博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
几种按键消抖方案的verilog描述
阅读量:5159 次
发布时间:2019-06-13

本文共 5284 字,大约阅读时间需要 17 分钟。

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

  • 假定按键的默认状态为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;     endendmodule

 

  • 方案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;     endendmodule

 

  • 方案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;    endendmodule

 

  • 测试代码
// 按键消抖测试电路// 时间单位`timescale 1ns/10ps// modulemodule  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;    endendmodule

 

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

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

转载于:https://www.cnblogs.com/qingkai/p/7596126.html

你可能感兴趣的文章
windows下的C++ socket服务器(4)
查看>>
css3 2d转换3d转换以及动画的知识点汇总
查看>>
【Java】使用Eclipse进行远程调试,Linux下开启远程调试
查看>>
对Vue为什么不支持IE8的解释之一
查看>>
计算机改名导致数据库链接的诡异问题
查看>>
Java8内存模型—永久代(PermGen)和元空间(Metaspace)(转)
查看>>
ObjectiveC基础教程(第2版)
查看>>
centos 引导盘
查看>>
Notes of Daily Scrum Meeting(12.8)
查看>>
Apriori算法
查看>>
onlevelwasloaded的调用时机
查看>>
求出斐波那契数组
查看>>
lr_start_transaction/lr_end_transaction事物组合
查看>>
CodeIgniter学习笔记(四)——CI超级对象中的load装载器
查看>>
.NET CLR基本术语
查看>>
ubuntu的home目录下,Desktop等目录消失不见
查看>>
建立,查询二叉树 hdu 5444
查看>>
[Spring框架]Spring 事务管理基础入门总结.
查看>>
2017.3.24上午
查看>>
Python-常用模块及简单的案列
查看>>