Слияние кода завершено, страница обновится автоматически
from machine import Pin, ADC, Timer
from micropython import schedule
class KeyPadException(Exception):
pass
class KeyPad(object):
"""
10 按键键盘 ADC 驱动
使用相同阻值电阻串联方案,只有一个按键的优先级最高,因此不支持多键检测
作为 HID 输入设备需要实现:
1. 按键按下:触发 key_down
2. 按键按下并保持:多次触发 key_down
3. 按键松开:触发 key_up
"""
class Const(object):
ADC_BIT_WIDTH = 11
KEY_MAX_VALUE = 2 ** ADC_BIT_WIDTH - 1 # 按键最大值
KEY_NO_KEY = 55 # 未按键键值范围 0~55
# KEY_TABLE = [954, KEY_MAX_VALUE] # 所有按键键值
KEY_INDEX_NONE = 0xff # 无按键索引值
"""
key_down_cb 触发后 1000 毫秒,每隔 200 毫秒再触发 1 次 key_down_cb
"""
ADC_SCAN_PERIOD = 50 # ADC 扫描间隔
KEY_HOLD_MS = 1000 # 按键长按触发时间
KEY_HOLD_TRIGGER_MS = 200 # 按键长按触发后连续触发时间间隔
KEY_HOLD_COUNT = int((KEY_HOLD_MS + ADC_SCAN_PERIOD - 1) / ADC_SCAN_PERIOD) # 根据 ADC 扫描间隔计算次数
KEY_HOLD_TRIGGER_COUNT = int((KEY_HOLD_TRIGGER_MS + ADC_SCAN_PERIOD -1) / ADC_SCAN_PERIOD) # 根据 ADC 扫描间隔计算次数
PERECISION = 0.05 # 电阻精度:1%
PERECISION_MAX = 1.00 + PERECISION # 电阻精度上限值
PERECISION_MIN = 1.00 - PERECISION # 电阻精度下限值
def __init__(self, pin=None, key_table=None, key_down_cb=None, key_hold_cb=None, key_up_cb=None):
assert pin is not None and pin in range(32, 39), KeyPadException("pin must be in range 32~39")
assert key_table is not None, KeyPadException("key_table must be specified")
self.__adc = ADC(Pin(pin, Pin.IN))
self.__key_table = key_table
self.__key_count = len(self.__key_table)
self.__timer = Timer(10)
self.__key_down_cb = key_down_cb
self.__key_hold_cb = key_hold_cb
self.__key_up_cb = key_up_cb
self.__current_key_index = KeyPad.Const.KEY_INDEX_NONE
self.__key_hold_counter = 0
self.__key_hold_trigger_counter = 0
self.__adc.atten(ADC.ATTN_11DB)
self.__adc.width(ADC.WIDTH_11BIT)
def get_key_count(self):
"""
获取按键数量
"""
return self.__key_count
def get_adc_width(self):
"""
获取 ADC 位宽
"""
return KeyPad.Const.ADC_BIT_WIDTH
def capture(self, for_test=False):
"""
开启按键捕捉扫描
for_test=True 则只打印 ADC 读取的数值
"""
try:
self.__timer.init(
mode=Timer.PERIODIC,
period=KeyPad.Const.ADC_SCAN_PERIOD,
callback=lambda timer: schedule(self.__key_scan, for_test)
)
except RuntimeError as re:
if str(re) in ("schedule queue full"): pass
def __get_key_index(self, value):
"""
根据 ADC 数值获取当前按键索引值
"""
key_index = KeyPad.Const.KEY_INDEX_NONE
if self.__key_count == 1:
key_index = 0
elif value == KeyPad.Const.KEY_MAX_VALUE:
key_index = self.__key_count - 1
else:
for index in range(self.__key_count):
if value > self.__key_table[index] * KeyPad.Const.PERECISION_MIN and value < self.__key_table[index] * KeyPad.Const.PERECISION_MAX:
key_index = index
break
return key_index
def __key_scan(self, for_test):
value = self.__adc.read()
if value <= KeyPad.Const.KEY_NO_KEY:
if self.__current_key_index != KeyPad.Const.KEY_INDEX_NONE:
if self.__key_up_cb is not None:
self.__key_up_cb(self.__current_key_index)
self.__current_key_index = KeyPad.Const.KEY_INDEX_NONE
self.__key_hold_counter = 0
self.__key_hold_trigger_counter = 0
return
if for_test:
print("value:", value)
return
key_index = self.__get_key_index(value)
if key_index == KeyPad.Const.KEY_INDEX_NONE: return
if key_index == self.__current_key_index:
self.__key_hold_counter += 1
if self.__key_hold_counter == KeyPad.Const.KEY_HOLD_COUNT:
self.__key_hold_counter -= 1
self.__key_hold_trigger_counter += 1
if self.__key_hold_trigger_counter == KeyPad.Const.KEY_HOLD_TRIGGER_COUNT:
self.__key_hold_trigger_counter = 0
if self.__key_hold_cb is not None:
self.__key_hold_cb(self.__current_key_index)
else:
self.__current_key_index = key_index
if self.__key_down_cb is not None:
self.__key_down_cb(self.__current_key_index)
def main():
def key_hold_cb(index):
print("key {} holding".format(index))
def key_down_cb(index):
print("key {} down".format(index))
def key_up_cb(index):
print("key {} up".format(index))
KEY_TABLE = [1280, KeyPad.Const.KEY_MAX_VALUE] # 所有按键键值
keypad = KeyPad(34, key_table=KEY_TABLE, key_down_cb=key_down_cb, key_hold_cb=key_hold_cb, key_up_cb=key_up_cb)
keypad.capture()
print("Keypad key count:", keypad.get_key_count())
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nPRESS CTRL+D TO RESET DEVICE")
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )