基于状态机实现的按键处理算法
这篇文章写了很久了,一直没发,现在发出来吧。
关于按键的基础知识,这里就不多写了,可以参考程序匠人的《按键漫谈》
一次完整的击键过程包括:等待阶段,闭合抖动阶段,有效闭合阶段,释放抖动阶段,有效释放阶段。释放抖动阶段对于按键处理用处不大,所以这个阶段被忽略了,即按键击键包括四个状态:等待阶段,闭合抖动阶段,有效闭合阶段,释放抖动阶段。
设等待阶段为A状态,闭合抖动阶段为B状态,有效闭合阶段为C状态,释放抖动阶段为D状态。各状态之间的转换关系如图:
A:等待阶段。此阶段若碰到有按键,立即转向B阶段。此阶段处理无击。
B:闭合抖动阶段。此阶段若本次键值=备份键值,则转向C阶段。否则,备份键值=本次键值,继续下一次判断。
C:有效闭合阶段。此阶段若检测到无效按键,则转向D阶段。此阶段处理长击和连击。
D:按键释放阶段。此阶段执行完按键散转程序后,可直接跳到A阶段。此阶段处理单击。
检测到按键后,10ms扫描一次按键,获取键值。当然也可以不管有没有按键,都10ms扫描一次。
按键处理程序需要变量
变量名 |
作用 |
key_state |
按键当前状态 0-等待阶段;1-闭合抖动阶段;2-有效闭合阶段 3-释放阶段 |
key_type |
击键类型 0-无按键或按键已响应;1-单击;2-连击;3-长击;4-无击 |
key_detect |
按键检测标志 0-无按键;1-检测到按键按下 |
key_disbale |
按键是否已经响应 1表示已经响应。用于长击。 |
key_scan_en |
按键允许扫描标志 0-不允许扫描;1-允许扫描(一般10ms允许一次扫描) |
key_value |
当前键值 |
key_backvalue |
备份键值 |
key_tmr_no |
无键计数器,用于无击 |
key_cnt_press |
按键闭合计数器,用于长击 |
key_delay_con |
连击响应延时时间,即多长时间响应一次连击 |
按键处理程序需要常量:
常量 |
作用 |
AN_XD_DL |
连击 初键延时时间(AN_XD_DL*定时扫描时间) |
AN_LA_DL |
连击响应时间(AN_LA_DL*定时扫描时间) |
AN_CJ_DL |
长击所需时间(AN_CJ_DL* AN_LA_DL*定时扫描时间) |
NoKeyTMR |
无键响应时间 |
各阶段程序流程图:
A:等待阶段
B:按键抖动阶段
此阶段较为简单。在按键允许扫描标志置1后,开始扫描,获取键值。若当前键值key_value=备份键值key_backvalue,转向闭合阶段,否则 备份键值=当前键值。另外此阶段要对无键计数器清零。
C:按键有效闭合阶段
需要注意的是,在按键散转后,需要对某些变量清零。
流程图如下:
D:释放阶段
本阶段处理的是单击程序。此处需要避免长击和单击冲突。执行完后,立即转向等待阶段。
根据键值散转处理时,请注意:一个按键可以:只支持单击,只支持长击,只支持连击,支持单击和长击。连击实际上包含了单击(根据初键延时时间AN_XD_DL来确定按键的灵敏度)。散转时不要对同一个按键执行冲突的操作(比如连击和长击)。