代码改变世界

verilog 按键消抖的设计思路

2014-08-30 22:56  雷韦雷  阅读(2335)  评论(0编辑  收藏  举报

本文是对特权同学的按键消抖实验的作的一个随笔,主要是从自己的角度来理解按键消抖。

消抖,顾名思义就是对抖动的情况进行消去,这种抖动的情况包括外界非人为而
产生的抖动,比如所在平面的震动、周边的按键对其造成的影响等。那么这些情
况就必须视为按键没有按下,应该予以排除。排除的方法就是作延迟处理,让机
器“沉默”一段时间,一般就是正常按键抖动所需要的时间,大约为20ms。
下面的一行代码在按键消抖中功能强大,它有两个巧妙之处:
(1)reg[2:0] key_rst;

always @(posedge clk or negedge rst_n)
if (!rst_n) key_rst <= 3'b111;
else key_rst <= {sw3_n,sw2_n,sw1_n};

reg[2:0] key_rst_r; //每个时钟周期的上升沿将low_sw信号锁存到
low_sw_r中

always @ ( posedge clk or negedge rst_n )
if (!rst_n) key_rst_r <= 3'b111;
else key_rst_r <= key_rst;

//当寄存器key_rst由1变为0时,led_an的值变为高,维持一个时钟周期
wire[2:0] key_an = key_rst_r & ( ~key_rst);

key_an是为了检测任何一个从1到0的按键值变化过程,而产生抖动的情况下,这
个过程会有很多,key_an也会一一地检测出来,真正的延迟是在密集的抖动中最
后一次按键值跳变之后开始的,我们将其叫做按键计数清零键,它的巧妙之处就
是能滤波。

(2)reg[19:0] cnt; //计数寄存器

always @ (posedge clk or negedge rst_n)
if (!rst_n) cnt <= 20'd0; //异步复位
else if(key_an) cnt <=20'd0;
else cnt <= cnt + 1'b1;

reg[2:0] low_sw;

always @(posedge clk or negedge rst_n)
if (!rst_n) low_sw <= 3'b111;
else if (cnt == 20'hfffff) //满20ms,将按键值锁存到寄存器low_sw中
cnt == 20'hfffff
low_sw <= {sw3_n,sw2_n,sw1_n};

//2^10~=10^6,当满足cnt == 20'hfffff时,也就相当于是过了20ms。

reg [2:0] low_sw_r; //每个时钟周期的上升沿将low_sw信号锁存到
low_sw_r中

always @ ( posedge clk or negedge rst_n )
if (!rst_n) low_sw_r <= 3'b111;
else low_sw_r <= low_sw;

//当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期
wire[2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);

第二次对sw_r的上升到下降沿的记录保证了一次按键按下只产生一次的led灯亮
灭的跳变,这就是第二个“取反相与”操作的巧妙之处。