刚参加工作的时候,看了一些同事采用的按键扫描和消抖方法,对比学校里和网上查到的按键处理,发现觉得不尽善尽美,有以下几点:
1. 消抖复杂,效率低。有人直接在电平判断后使用delay()函数,进行消抖,耽误时间;有人在按键电平中断中进行消抖和处理,导致其他的服务反应慢,不适合做实时系统;
2. 许多功能在不同界面下是不同的,把按键处理在中断进行,导致分支很多,业务流不清晰。
3. 特殊功能按键的处理麻烦。在需要长按作为特殊按键、复合按键响应、复合按键长按响应的时候,需要增加很多的标志位,反复使用if..else判断,流程看起来很乱。
4. 跟硬件设计或业务关联很深,不便于移植和修改,导致每个项目都要更改一次。
想了很久之后,我结合PC的键盘处理方法,编写了自己的按键函数,经过几次修改,定了下来。这十多年来,无论更换单片机,还是采用端口/扫描方式,还是采用前后台或操作系统,都一直在用,方便移植,也比较清晰。
/****/
它主要有几个特点:
按键扫描和取值分开。
在中断中,每隔10ms调用keyScan()进行按键扫描,多次扫描进行消抖,获得的按键值不返回,作为消息放到全局变量中;
在业务层需要判断的地方使用getKeyValue()获取当前的键值,进行处理。
每一个按键,都有单独的标志位和计时变量。
消抖计时:
每调用一次10ms中断,如果按键按下,gucKeyOkTimer(以OK按键为例)增加;
gucKeyOkTimer超过消抖的阀值(我一般10次,即100ms),则确认有按键了。
任何一次扫描到按键没有按下,gucKeyOkTimer清零,重新开始;
标志位:
如果按下的电平时间超过阈值,一直按着,会有gfOkPressing的标志,表明按键一直有效中;
如果按下过一次,需要响应,会有gfOkNeedAck,这个标志只置位一次;
复合按键的响应:
因为每个按键,都有自己的标志位和计时变量。复合按键的判断,使用多