zoukankan      html  css  js  c++  java
  • 几种按键消抖方案的verilog描述

    首先,做两个假定,以方便后面的描述

    • 假定按键的默认状态为0,被按下后为1
    • 假定按键抖动时长小于20ms,也即使用20ms的消抖时间

    核心:方案

    • 最容易想到的方案

        在按键电平稳定的情况下,当第一次检测到键位电平变化,开始20ms计时,计时时间到后将按键电平更新为当前电平

    • 或许这才是最容易想的方案

        在20ms计时的过程中,有任何的电平变化都立即复位计时

    • 消除按键反应延时抖方案

        在有电平变化时立即改变按键输出电平,并开始20ms计时,忽略这其中抖动

    测试平台设计(修改代码以仿真的1us代替实际1ms)

    • 无抖动 上升沿抖动5毫秒
    • 下降沿抖动15毫秒
    • 上升和下降沿均抖动19毫秒

      附加测试(可以不通过)

    • 抖动25毫秒

    代码

    • 方案1
    module debounce(
        input wire clk, nrst,
        input wire key_in,
        output reg key_out
        );
    
        // 20ms parameter
    //    localparam TIME_20MS = 1_000_000;
        localparam TIME_20MS = 1_000;       // just for test
    
        // variable
        reg [20:0] cnt;
        reg key_cnt;
        
        // debounce time passed, refresh key state
        always @(posedge clk or negedge nrst) begin
            if(nrst == 0)
                key_out <= 0;
            else if(cnt == TIME_20MS - 1)
                key_out <= key_in;
        end
    
        // while in debounce state, count, otherwise 0
        always @(posedge clk or negedge nrst) begin
            if(nrst == 0)
                cnt <= 0;
            else if(key_cnt)
                cnt <= cnt + 1'b1;
            else
                cnt <= 0; 
        end
         
         // 
         always @(posedge clk or negedge nrst) begin
                if(nrst == 0)
                    key_cnt <= 0;
                else if(key_cnt == 0 && key_in != key_out)
                    key_cnt <= 1;
                else if(cnt == TIME_20MS - 1)
                    key_cnt <= 0;
         end
    endmodule
    • 方案2
    module debounce(
        input wire clk, nrst,
        input wire key_in,
        output reg key_out
        );
    
    //    localparam TIME_20MS = 1_000_000;
        localparam TIME_20MS = 1_000;
    
        reg key_cnt;
        reg [20:0] cnt;
    
        always @(posedge clk or negedge nrst) begin
            if(nrst == 0)
                key_cnt <= 0;
            else if(cnt == TIME_20MS - 1)
                key_cnt <= 0;
            else if(key_cnt == 0 && key_out != key_in)
                key_cnt <= 1;
        end
    
        always @(posedge clk or negedge nrst) begin
            if(nrst == 0)
                cnt <= 0;
            else if(key_cnt) begin
                if(key_out == key_in)
                    cnt <= 0;
                else
                    cnt <= cnt + 1'b1;
            end
            else
                cnt <= 0;
        end
         
         always @(posedge clk or negedge nrst) begin
                if(nrst == 0)
                    key_out <= 0;
                else if(cnt == TIME_20MS - 1)
                    key_out <= key_in;
         end
    endmodule
    • 方案3
    module debounce(
        input wire clk, nrst,
        input wire key_in,
        output reg key_out
        );
    
    //    localparam TIME_20MS = 1_000_000;
        localparam TIME_20MS = 1_000;       // just for test
    
        reg key_cnt;
        reg [20:0] cnt;
    
        always @(posedge clk or negedge nrst) begin
            if(nrst == 0)
                key_cnt <= 0;
            else if(key_cnt == 0 && key_out != key_in)
                key_cnt <= 1;
            else if(cnt == TIME_20MS - 1)
                key_cnt <= 0;
        end
    
        always @(posedge clk or negedge nrst) begin
            if(nrst == 0)
                cnt <= 0;
            else if(key_cnt)
                cnt <= cnt + 1'b1;
            else
                cnt <= 0;
        end
    
        always @(posedge clk or negedge nrst) begin
            if(nrst == 0)
                key_out <= 0;
            else if(key_cnt == 0 && key_out != key_in)
                key_out <= key_in;
        end
    endmodule
    • 测试代码
    // 按键消抖测试电路
    
    // 时间单位
    `timescale 1ns/10ps
    
    // module
    module  debounce_tb;
    
        // time period parameter
        localparam T = 20;
    
        // variable
        reg clk, nrst;
        reg key_in;
        wire key_out;
    
        // instantiate
        debounce uut(
            .clk    (clk    ),
            .nrst   (nrst   ),
            .key_in (key_in ),
            .key_out(key_out)
        );
    
        // clock
        initial begin
            clk = 1;
            forever #(T/2) clk = ~clk;
        end
    
        // reset
        initial begin
            nrst = 1;
            @(negedge clk) nrst = 0;
            @(negedge clk) nrst = 1;
        end
    
        // key_in
        initial begin
            // initial value
            key_in = 0;
            
            // wait reset
            repeat(3) @(negedge clk);
            
            // no bounce
            // key down
            key_in = 1;
    
            // last 60ms
            repeat(3000) @(negedge clk);
    
            // key up
            key_in = 0;
    
            // wait 50ms
            repeat(2500) @(negedge clk);
    
            // down 5ms, up 15ms
            // key down, bounce 5ms
            repeat(251) @(negedge clk) key_in = ~key_in;
    
            // last 60ms
            repeat(3000) @(negedge clk);
    
            // key up, bounce 15ms
            repeat(751) @(negedge clk) key_in = ~key_in;
    
            // wait 50ms
            repeat(2500) @(negedge clk);
    
            // down 19ms, up 19ms
            // key down, bounce 19ms
            repeat(951) @(negedge clk) key_in = ~key_in;
    
            // last 60ms
            repeat(3000) @(negedge clk);
    
            // key up, bounce 19ms
            repeat(951) @(negedge clk) key_in = ~key_in;
    
            // wait 50ms
            repeat(2500) @(negedge clk);
            
            // additional, this situation shoud not ever happen
            // down 25ms, up 25ms
            // key down, bounce 25ms
            repeat(1251) @(negedge clk) key_in = ~key_in;
    
            // last 60ms
            repeat(3000) @(negedge clk);
    
            // key up, bounce 25ms
            repeat(1251) @(negedge clk) key_in = ~key_in;
    
            // wait 50ms
            repeat(2500) @(negedge clk);
    
            // stop
            $stop;
        end
    endmodule

    放在最后的,并不一定是最不重要的

      对于上面的三种方案,我比较喜欢第三种方案,它更贴合实际的按键状态,以上的代码我都做过modelsim仿真,但还没有在实际的项目中验证。在整理准备这个博客的时候,我又想到了一个感觉是更巧妙的方案,具体是这样的:在第三个方案的基础上,因为按键输入有变化的第一时刻,输出就已经改变了,在这种情况下,我可以把计时的时长改为一个很小的值,该值只要比抖动中的最长高低电平变化时间长即可。但想想也没这个必要,且这个抖动的高低电平变化时长我也很难去给它界定一个值。

  • 相关阅读:
    [课程设计]任务进度条&开发日志目录
    《软件工程》课程设计-团队成立
    软件工程学期总结
    第三次冲刺及课程设计 617
    学术诚信与职业道德
    第二个冲刺
    操作系统 实验四主存空间的分配和回收
    0526 《构建之法》第8-10章读后感
    SCRUM项目 6.0
    SCRUM项目 5.0
  • 原文地址:https://www.cnblogs.com/qingkai/p/7596126.html
Copyright © 2011-2022 走看看