查看: 158|回复: 1

[原创] 锆石A4学习笔记之按键消抖

[复制链接]

9

主题

0

好友

138

积分

童生

Rank: 2

  • TA的每日心情
    开心
    2016-8-26 16:22
  • 签到天数: 1 天

    [LV.1]初来乍到

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

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

    QQ图片20160827230033.jpg


    贴代码进行讲解:
    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的值

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


    回复

    使用道具 举报

    4

    主题

    0

    好友

    106

    积分

    童生

    Rank: 2

    该用户从未签到

    发表于 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
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    关闭

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


    手机版|爱板网 |网站地图  

    GMT+8, 2016-12-11 12:08 , Processed in 0.090663 second(s), 11 queries , Memcache On.

    苏公网安备 32059002001056号

    Powered by Discuz!

    回顶部