按键防抖,一直以来都是个非常重要的优化,除却硬件上并联电容的防抖。更加常见的则是软件上的防抖。 通常来说,软件防抖一般使用一个延时函数来实现,但是如果使用简单暴力的计算堵塞延时。就会导致系统的实时响应性不好,甚至会因为按键的延时意外中断一些高实时性的数据交互操作,例如串口数据的响应、传感器数据的读取。严重时,甚至会因为干扰了其他通讯时序,从而读出错误的数据,进而导致系统出现致命性的异常。 所以,在进行按键延时防抖的时候,一般会采用定时器的非堵塞式防抖。从而达到不影响系统的高实时性。 通过对常见的微动开关进行示波器波形测试,可以看到,电平的变化并非常简单的高低电平变化,而是出现了连续的震荡才逐渐变得稳定(这通常是因为导线和单片机内的电容形成了一个小的RC震荡),因为现在的单片机运行速度普遍较高,这些震荡的信号就很有可能被单片机读取到,进而产生误动作。
关于矩阵键盘识别,这里我提供两个思路,一个是使用行列式扫描,即先将行IO拉到低电平,此时如果没有按下按键,读列IO应该全是高电平,如果出现了低电平,就证明按键是被按下了。此时需要设定一个延时(5~10ms,推荐5ms,根据开关类型试一下,按键大,震动毛刺多的就延时长一点。按键小,响声清脆的就延时小一点),然后再次判断是否有按下动作,如果仍然存在。就证明这是一次真实有效的按下动作,此时就可以先存下列IO的电平状态,然后将列IO拉到低电平,读行IO,并且同样存下电平状态,将两个电平状态拼接起来,就获得了一个按键的唯一状态编码。此时,通过查询编码就可以知道当前按下的按键。如果没有查到,就说明是一次多按键触发,可以不予处理。这个方法好处是便于理解,但是没法处理多按键按下的情况,或者说处理多按键按下所需要的编码表数量过多。 而第二种方法则是一种优化过的单按键扫描方式,不仅可以处理多个按键同时按下的情况,还可以通过新的架构识别出来单击、双击、长按三种状态,从而实现各种新的组合。
但是,由于矩阵键盘的结构问题,如果出现一个按键周围三个连续按键的按下就会导致错误的识别到这个按键的按下,如下图所示 在这个图中, S7按键会因为S11、S10、S6的按下而造成误识别。所以,这种单按键扫描方式我设定仅允许识别至多两个和部分三个按键的情况,如果识别到有四个及以上的按键(如果识别到四个实际可能是三个,主要是为了避免这个问题),就直接放弃本次识别。 而这种单按键扫描方法,运用的其实就是单点扫描点阵屏的一种方法,既然程序可以对点阵屏幕进行单个灯的扫描,用以减少功耗和控制灵活度,算是一种将显示颗粒度细化的方案。而我的这种单按键扫描方式同样是对于单个按键使用逐个判断的方式,先将第一行的IO拉低,判断是否有其他拉低引脚(按下),然后再将第一列的IO拉低,判断是否有其他拉低引脚。以此类推,如果两次都检测到了拉低,说明当前行列对应的这个按键就被按下了,然后就可以对当前这个按键进行按下计时,超过20ms就算做一次按下稳定,此时如果抬起了,就设定为单击,如果等待200ms之内没有再次按下,则设定为空状态。如果按下了,并且又持续了20ms,则算作一次双击状态,如果第一次按下没有松开,一直持续了700ms,则算作一次长按。所有的状态在逻辑线程里面使用过后都会回到空状态,如果没有回到空状态。则认为需要保留当前状态到逻辑线程内,就暂时不进行这个按键的状态检测了。等待逻辑线程使用过后再进行识别操作。 当然,如果比赛的时候一般来说是不会要求这种多按键重叠状态检测的。此时如果需要追求速度,可以使用第一种思路 如果需要识别重叠按键,可以使用第二种思路的前半部分,作为第一种思路的变体。不过需要注意的是,如果检测到了四个按键的情况(如上图状况的就是按下三个蓝色电路的按键就能检测到四个按键按下),那么就有可能是硬件的“鬼影”,需要在程序中剔除掉。
如果需要独立按键识别状态,可以参考第二种思路的后半部分。
|