一、按键抖动
按键在按下时,活动触点击打固定触点会有机械振动,因而造成输出波形抖动,因按键形态和触点材料的不同,抖动的过程一般会持续数毫秒,金属触点的按键可能达到10ms,而软性触点(如导电橡胶或薄膜)则可能在1ms以内甚至没有抖动。
按键去抖动的实用做法是定时查询,定时器资源往往是极易复用的,一般10ms左右的查询间隔对于用户按键也是足够的,用户操作按键不可能达到50次每秒,按下的持续时间也不可能短于10ms。
二、解决思路
学过数字电路基础的同学应该都熟悉D触发器的特性,其输入端D和输出端Q的值相隔一个时钟周期,那么将两个信号取出来做如图所示的运算,就可以检测到按键输入端电平变化为上升还是下降:
检测到上升沿或下降沿时,我们可以开始计时,当电平变化保持时间超过按键抖动的理论最长时间时,我们可以认为抖动结束,进入稳定的按下状态。同理,松开按键时,当电平变化保持时间超过按键抖动的理论最长时间时,可以认为进入稳定的弹开状态。由于要对抖动时间进行计时,所以代码中必定包含一个计数器。
三、状态转换图
按键未检测到电平变化时为第一个状态S0,我们命名为IDLE(空闲)。当检测到第一个下降沿到来时,开始计时并进入第二个状态S1,我们命名为FILTER0。
进入第二个状态后,我们检查计数器的值——如果计数器计满了10ms,则说明此时抖动已经结束,进入稳定的闭合状态S2,我们将其命名为DOWN;如果计数器没有计满,而是迎来了上升沿变化,则说明遇到了抖动,经历的低脉冲无效,那么状态就返回到最初的IDLE状态,重新等待下降沿的到来。
进入第三个状态 DOWN后,我们可以设置各个管脚在按键按下时应有的变化,例如点亮LED,或者发送一帧数据。同时我们等待上升沿的到来,当上升沿到来时,开始计数并进入第四个状态S3,我们将其命名为FILTER1。
进入第四个状态后,我们检查计数器的值,如果计满了10ms,则说明抖动已经结束,回到最初的IDLE状态,如果计数器没有计满,反而是迎来了下降沿,则说明发生了抖动,重新回到DOWN的按下状态,等待上升沿的到来。
状态图如下:
四、按键消抖完整代码
module key_filter(
clk, //50M时钟输入
rst_n, //模块复位
key_in, //按键输入
key_flag, //按键标志信号
key_state, //按键状态信号
led //led调试端口
);
input clk;
input rst_n;
input key_in;
output reg key_flag;
output reg key_state;
output wire [3:0] led;
localparam
IDEL =