1回答

0收藏

锆石A4学习笔记之按键消抖

其他 其他 4527 人阅读 | 1 人回复 | 2016-08-27

做按键功能时,无论是什么按键,一般都需要做一下消抖工作,不论是从硬件或者软件上都是有一定必要的,确保按键正常反映按下与否情况。以前是玩单片机的,没有从单片机的思维转到FPGA的思维来,总想着用一个延时函数什么的进行处理,所以耗费了一点时间去理解这个FPGA用Verilog去做软件的按键消抖。

总的检测方法就是基于脉冲的边沿检测法。第一次检测到下降沿的时候,启动20ms计数器进行计数,计数时间到以后再做检测,这里的检测和脉冲边沿检测有着异曲同工之处,方法几乎是一样的,FPGA经过20ms以后检测按键是否按下,存储检测到的值,并且按位取反与前一个20ms的值相与,得到一个值,如果为1,则表示按键按下,否则没有按下。



贴代码进行讲解:
module sw_debounce(
                            clk,rst_n,
                        sw1_n
                           led_d1
                    );

input   clk;        //主时钟信号,50MHz
input   rst_n;        //复位信号,低有效
input   sw1_n;         //独立按键,低表示按下
output  led_d1;        //发光二极管,分别由按键控制

//---------------------------------------------------------------------------
reg key_rst;  

always @(posedge clk  or negedge rst_n)
    if (!rst_n) key_rst <= 1'b1;
    else key_rst <= sw1_n;

reg key_rst_r;       //由于非阻塞赋值,key_rst_r比key_rst的值滞后一个时钟周期

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 key_an = key_rst_r & ( ~key_rst);

例如:key_rst  1 1 1 1 1 0 0 0 0
        ~key_rst  0 0 0 0 0 1 1 1 1
        key_rst_r    1 1 1 1 1 0 0 0
          key_an      0 0 0 0 1 0 0 0  
key_rst 出现下降沿就可以检测到了
//---------------------------------------------------------------------------
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 low_sw;

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

//---------------------------------------------------------------------------
reg  low_sw_r;      

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

//当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期
wire led_ctrl = low_sw_r & ( ~low_sw);
此处同理于上面两个always语句,不同的是,这个检测周期是20ms的值

按键消抖最主要的精髓就是这个了。


分享到:
回复

使用道具 举报

回答|共 1 个

倒序浏览

沙发

砂锅骆驼

发表于 2016-8-30 11:39:58 | 只看该作者

感觉你的代码是特权的视频教程里面的。
其他书上看到的,如下:
assign key_done = (dout1|dout2|dout3);
always @(posedge clk)  //clk不是系统时钟,分频之后的,可以弄个3-5ms时间,然后下面的非阻塞赋值是并行运行的,最后得到按键的结果大概在9ms-15ms。这种写法比你的那种简单一些吧。
begin
    dout1 <= key_in;
    dout2 <= dout1;
    dout3 <= dout2;
end
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条