一种基于定时器的按键检测方案

  对于按键检测,大家应该都不陌生。对于各种微控制器来说,按键检测都是最简单同时又最基础的东西。也许按键检测里面唯一比较需要花心思来考虑的地方就是去抖动而已。

  以往的按键检测无非是三种方式:基于CPU延时方式、基于外部中断方式、基于ADC转换器件方式。

  基于CPU延时的方式,就是通过CPU运行空指令的方式延时检测判断抖动。不管是上课也好,各种参考资料也好,都是介绍的这种方式,所以这应该是我们大家最早接触并且最常用的一种方式了。但是这种方式极大的降低了CPU的效率,实时性也非常差。特别是按键按着的时候CPU基本不能再做其他操作。

  基于外部中断的扫描方式,这种方法比起上一种,实时性很高。但是它需要占用外部中断资源,特别是常用的51单片机里面就只有2个外部中断,这显得相当浪费。

  第三种是使用ADC转换器件的方式,用这种方式进行按键扫描这种方法是非常有新意的,完全不同于之前两种。并且倒是很节省IO口,因为不管是单线并联多按键还是矩阵按键,最终只需要一根线接入ADC(当然IO口连ADC的数据线你们就另算吧,:-P ),而且可以很轻松的完成一些诸如“多按键检测”之类的高级功能。但是,对于要求不高的按键使用环境就用ADC就有点太大材小用了。

  这几天看书找到一种比较有新意的按键检测方案,就是使用定时器的资源,然后配合状态机的方式来进行按键检测。这样不仅可以轻松检测去抖和弹起,还可以做到既保证了CPU的效率,又在最大程度上释放了CPU。

  这种按键检测方式的流程大概是这样的,首先设定一个时间段的定时器中断(我用的是10ms),未到达定时器中断的时候CPU就执行程序其他操作。进入到定时器中断当中时,首先通过状态机判断状态(有3种状态,分别是状态0、状态1和状态2,未有按键按下时默认为状态0),进入状态0判断是否有按键按下,如若有按下则设置状态标志为状态1,如若没有则离开中断。当下一个10ms到来时再次进入中断,此时若之前有按键按下会进入到状态1,在状态1当中判断此时是否还是按下,若已经未按下说明刚才是按键抖动,不需要做动作,改变状态标志回状态0离开中断;如果此时继续按下说明是确实有按键按下,可以开始执行按键操作的程序,结束后设置状态标志为状态2,离开中断。当下一次进入状态机时,再进行判断是否是按下的状态,如果是则说明之前按下的没有抬起;如果此时没有按下了就说明已经抬起了,设置状态标志归零进行下一次按下的检测。

  整个方案的流程图如下:

  这种检测方式比起传统的那些有不少优势。它把一个完整的按键检测流程分割成不同的状态来分别呈现,这样的话就有效的节约了“延时”上面耗费的CPU效率,在延时的过程中CPU是回到主程序继续执行原来的流程的。这样的响应也很快,一旦检测到是非抖动的按键之后可以立即执行相应的操作(当然传统方式也可以通过编程实现一旦按下就执行相应操作,可是后面如果不检测弹起的话会变成按一下就动了好几次动作的状态,所以传统按键方式一般会采取松手后再执行动作)。而且它把松手的状态检测放在做相应动作之后,也可以很好的避免了按一下就动作好几次的情况。

  对了,刚想起来,如果用这种方式来进行状态判断的话,还可以通过增加状态来判断是否长按,对于按键不多但要实现功能多的系统来说,无疑有了更大的方便。

  当然这种检测方式也不是一点劣势也没有,毕竟它还是浪费了一个定时器中断的资源,如果是STM32之类的处理器当然是一丁点问题都没有的,但是如果是对于51之类本来资源就不多的处理器来说,可能还是会捉襟见肘。总之视情况使用呗,至少我觉得占用一个定时器比占用一个外部中断要来得实惠。

  最后晒一下我在我毕业设计里面分别用传统的延时方式检测按键和使用这种新型的方式检测按键的效果图对比一下~

(传统的按键检测方式)

(采用定时器中断按键检测方式)

  可能光看图还是看不出什么所以然来,我简单解说一下吧。上面采取传统按键检测方式的,当按键按下之后没弹起来之前,程序相当于停滞在按键检测的区域内,所以动态扫描七段数码管显示那里只能固定到按下之前的最后一个显示状态,ADC转换也是被暂停掉无法工作的。而下面采用定时器中断的按键检测方式,按下了立即在数码管上有所体现,没有多余的多按之类的误操作,并且ADC和数码管也是在持续工作中(锁定按下时,同时修改采集的电压,ADC能进行转换并把电压值显示在数码管上)。综上所述,还是能体现出这种方式的优势所在的。

  具体程序的源代码就不贴出来丢人现眼了,反正流程图都有在这里了,写出代码来还不是很简单的事情么?

文章目录
|