按键消抖电路设计

  • 1. 什么是按键抖动
  • 2. 消抖电路设计思路
  • 3. 代码实现
  • 4. 仿真测试
    • 4.1. initial语句块赋值
    • 4.2. 调用task任务封装赋值并调用$random函数

重新补充一下,
这里的消抖,可以看作开关的消抖,开关闭合和释放都要进行消抖处理,并且中间会保持一段时间。
而按键的消抖,按下释放是连着的,这一个过程会发出一个脉冲信号,证明按键按下过


1. 什么是按键抖动

实际的拨动开关和按键都是机械式的设备,在状态改变时可能会出现来回抖动多次导致状态不稳定的情况,通常抖动的持续时间不超过20ms。消抖电路的目的就是滤去这段时间内的抖动信号。

2. 消抖电路设计思路

  1. 使用有限状态机的思想,当输入信号稳定20ms后才改变抖动以后的输出值。假定使用的系统时钟频率为50HMz,要等待20ms的时间,那么就使用计数器数1_000_000个clk,解决延时问题。

  2. 按照等待延时的思路,可以这样设计:检测到按键key_in按下,启动计数器,等到20ms后检测key_in是否为0,若为0,表明按键按下状态稳定,关闭计数器,然后等待按键key_in释放;当检测到key_in释放出现上升沿,再次启动计数器,20ms后检测key_in是否为1,若为1,表明按键已释放,一次完整的按键过程结束。 每20ms检测完毕后,输出一个flag脉冲。

  3. 为了实现按键消抖,考虑到两种情况,按下需要消抖,释放需要消抖。状态机分为4个状态,两个稳定状态和两个消抖状态

    IDLE:空闲状态,默认按键不按下为稳定高电平
    FILTER_DOWN:按键按下消抖状态
    DOWN:按键按下稳定状态
    FILTER_UP:按键释放消抖状态

  4. 消抖模块端口设计

3. 代码实现

module key_filter(output  reg     key_flag,   // 消抖完毕输出脉冲output  reg     key_state,  // 按键状态输出input   wire    clk,       // 50MHz时钟input   wire    rst,input   wire    key_in);// 状态声明parameter   IDLE        =   4'b0001;parameter   FILTER_DOWN =   4'b0010; parameter   DOWN        =   4'b0100;parameter   FILTER_UP   =   4'b1000;reg     [3:0]   next_state;reg             key_temp;   // wire            key_nedge;  //wire            key_pedge;  //reg             en_counter; // 计数器使能信号reg     [19:0]  counter;    // 计数1_000_000次// 边沿检测电路// 按键信号属于异步信号,在状态转移中需要对按键边沿敏感,所以先采用一级D触发器将key_in与clk同步,产生pedge和nedge信号always @ (posedge clk)key_temp    <=  key_in;                         // 暂存上一个按键状态assign key_nedge   =   (key_temp) && (!key_in);    // 下降沿检测assign key_pedge   =   (!key_temp) && (key_in);    // 上升沿检测// 带使能的计数器,实现20ms延时always @ (posedge clk)      beginif (rst == 1'b0)    begincounter <=  0;end else if (en_counter == 1'b1)    begincounter <=  counter + 1;end else    begincounter <=  0;endend// 状态机模块always @ (posedge clk or negedge rst)   beginif (rst == 1'b0)    beginnext_state  <=  IDLE;en_counter  <=  1'b0;key_flag    <=  1'b0;key_state   <=  1'b1;end else    begincase (next_state)IDLE:           beginkey_flag    <=  1'b0;key_state   <=  1'b1;if (key_nedge)  beginnext_state  <=  FILTER_DOWN;en_counter  <=  1'b1;end else    beginnext_state  <=  IDLE;end  endFILTER_DOWN:    beginif (counter >= 20'd999_999) begin   // 20ms时间到key_flag    <=  1'b1;       // flag输出一个高脉冲,进入稳定状态en_counter  <=  1'b0;       // 计数器不使能next_state  <=  DOWN;end else if (key_pedge)     begin   // 20ms内检测到有上升沿en_counter  <=  1'b0;       //计数器不使能,保持空闲状态next_state  <=  IDLE;endendDOWN:           beginkey_flag    <=  1'b0;key_state    <=  1'b0;if (key_pedge)  beginnext_state  <=  FILTER_UP;en_counter  <=  1'b1;end else    beginnext_state  <=  DOWN;end                endFILTER_UP:      beginif (counter >= 20'd999_999) begin   // 20ms时间到key_flag    <=  1'b1;       // flag输出一个高脉冲,进入稳定状态en_counter  <=  1'b0;       // 计数器不使能next_state  <=  IDLE;end else if (key_nedge) begin       // 20ms内检测到有下降沿en_counter  <=  1'b0;       // 计数器不使能,保持按下稳定状态next_state  <=  DOWN;endenddefault:        beginnext_state  <=  IDLE;endendcaseendendendmodule

4. 仿真测试

4.1. initial语句块赋值

`define clk_period 20        //100M系统时钟module key_filter_tb();reg clk;                   //50M时钟信号reg rst;                   //低电平复位reg key_in;                //按键输入wire key_flag;             //消抖完毕输出脉冲wire key_state;            //按键状态输出//例化测试模块key_filter key_filter_test(.clk(clk),             //50M时钟信号.rst(rst),             //低电平复位.key_in(key_in),       //按键输入.key_flag(key_flag),   //消抖完毕输出脉冲.key_state(key_state)  //按键状态输出
);//产生100M时钟信号initial clk = 1;always #(`clk_period / 2) clk <= ~clk;//开始测试initial beginrst <= 0;        //系统复位key_in <= 1;     //按键处于空闲状态#(`clk_period * 2);rst <= 1;#10_000_000;        //延时10ms,方便观察按键按下现象//开始模拟按键按下抖动key_in <= 0;    #1000;key_in <= 1;    #2000;key_in <= 0;    #1400;key_in <= 1;    #2600;key_in <= 0;    #1300;key_in <= 1;    #200;//产生一个稳定的低电平大于20ms,代表按键稳定key_in <= 0;   #30_000_000;//模拟释放抖动key_in <= 1;    #2000;key_in <= 0;    #1000;key_in <= 1;    #2600;key_in <= 0;    #1400;key_in <= 1;    #200;key_in <= 0;    #1300;//产生一个稳定的高电平大于20ms,代表释放稳定key_in <= 1;   #30_000_000;$stop;endendmodule


局部抖动

4.2. 调用task任务封装赋值并调用$random函数

  1. 利用$randon函数产生随机延时置模拟抖动
reg [15:0]randnum;
randnum = $random % 50;        //产生一个-49~49内的随机数
randnum = {$random} %  50;     //产生一个0 ~ 50内的随机数
  1. 利用 task / endtask 将重复代码进行封装
task <任务名>;<语句1><语句2><语句3>....
endtask
`define clk_period 20        //100M系统时钟module key_filter_2_tb();reg clk;                   //50M时钟信号reg rst;                   //低电平复位reg key_in;                //按键输入wire key_flag;             //消抖完毕输出脉冲wire key_state;            //按键状态输出reg [15:0]rand_time;       //按键抖动时随机时长//例化测试模块key_filter key_filter_test(.clk(clk),                    //50M时钟信号.rst(rst),                    //低电平复位.key_in(key_in),              //按键输入.key_flag(key_flag),          //消抖完毕输出脉冲.key_state(key_state)         //按键状态输出
);//产生100M时钟信号initial clk = 1;always #(`clk_period / 2) clk <= ~clk;//开始测试initial beginrst <= 0;        //系统复位key_in <= 1;     //按键处于空闲状态#(`clk_period * 2);rst <= 1;#10_000_000;          //延时10ms,方便观察按键按下现象press_key; #10000;    //第一次按下按键press_key; #10000;    //第二次按下按键press_key; #10000;    //第三次按下按键$stop;endtask press_key;begin//开始模拟按键按下抖动repeat(50)beginrand_time = {$random} % 65536;#rand_time key_in = ~key_in; end //产生一个稳定的低电平大于20ms,代表按键稳定key_in = 0;     #30_000_000;//模拟释放抖动repeat(50)beginrand_time = {$random} % 65536;#rand_time key_in = ~key_in;  end//产生一个稳定的高电平大于20ms,代表释放稳定key_in = 1;#30_000_000;endendtaskendmodule

状态机按键消抖电路设计相关推荐

  1. 小梅哥三段式状态机按键消抖改写

    小梅哥三段式状态机按键消抖改写 小梅哥资料中按键消抖部分是用一段式.二段式状态机写的.我用三段式状态机改写了一下,仿真和板载测试通过. 代码记录如下: module key_filter1(input ...

  2. (三) 按键消抖电路设计

    由于普通物理按键存在反作用弹簧,因此当按下或者松开时均会产生额外的物理抖动,物理抖动便会产生电平的抖动.在按键从按下再到松开的过程中,其电平变化如图2.2.1所示,上为理想波形输出,下为实际波形输出. ...

  3. verilog基础-状态机之FPGA独立按键消抖设计与验证(熟练testbench的写法)

    独立按键消抖设计与验证 本实验主要是为了锻炼状态机的思维模式以及熟练掌握TB的写法 本节主要收获了:define的用法,另外就是,顶层的input在TB中是reg的真正含义,其实就是把激励当做寄存器来 ...

  4. Verilog实现独立按键消抖(状态机)

    本文参考小梅哥的独立按键消抖视频 1,实验原理: 这里是黑金开发板教程中的图,可以看出,按键未按下时的状态是高电平,按下为低电平.下边是小梅哥画的图解. 因为是机械按键,按下时候有一个不稳定的抖动期, ...

  5. 使用状态机消进行按键消抖

    在机械按键内部都会有弹簧,当我们按下时会发生抖动,这可能导致我们系统对电信号的判断有误.所以可以用状态机进行消抖,我的理解就是在只要按键保持的时间没有达到一定的数值,在这个中间的抖动对归为一种状态.设 ...

  6. STM32按键消抖——入门状态机思维

    在嵌入式软件开发中,状态机编程是一个十分重要的编程思想,它也是嵌入式开发中一个常用的编程框架.掌握了状态机编程思想,可以更加逻辑清晰的实现复杂的业务逻辑功能. 1 状态机思想 状态机,或称有限状态机F ...

  7. 【FPGA】状态机实现按键消抖

    1.状态机简介 状态机,FSM(Finite State Machine),也称为同步有限状态机从.指的是在同步电路系统中使用的,跟随同步时钟变化的,状态数量有限的状态机,简称状态机. 状态机分类 根 ...

  8. STM32按键消抖的几种实现方式-STM32 Button Debouncing

    一.按键抖动的现象 按键按下和松开的时候,按键金属片之间的贴合.分离有一个过程.给STM32输入的信号并不是理想的0和1切换的过程.而是如下图所示的,按下和松开的一小段时间内按键信号出现抖动(jitt ...

  9. 单片机按键“消抖”的思考

    初学单片机时,讲到了一个按键"消抖"概念,视屏教程中只是说到要确定按键是不是真正按下,所以需要加一个延时来判断. 附上延时消抖程序代码: 代码1 void keypros() {i ...

最新文章

  1. Turing渲染着色器网格技术分析
  2. 基于深度学习的步态识别算法的MATLAB仿真
  3. 关于list.extend(iterable)
  4. 实用计算机相关日语词汇,计算机相关日语词汇整理2
  5. POJ - 3020 Antenna Placement(最小路径覆盖-二分图最大匹配)
  6. 2.9 logistic 回归中的梯度下降法
  7. ubuntu-18.04 设置开机启动脚本-亲测有效
  8. CF #439 E The Untended Antiquity
  9. ARM学习笔记--day10
  10. 单词首字母大写,将每个单词的首字母改为大写后输出
  11. Python字串(string)基础与20种常见操作
  12. CSDN博客炫丽图标调整字体大小和颜色
  13. SONM挖矿收益计算器
  14. 欧洲对撞机实现最高能级对撞 启动宇宙大爆炸实验
  15. PDF文件打开密码的消除办法
  16. 关于广州小狐科技有限公司
  17. IDEA连接数据库踩过的坑之无法连接到数据表
  18. 【笔记】白岩松:如何去看待青年人看抖音。
  19. python图像灰度化_python实现图片二值化及灰度处理方式
  20. 7-2 正负数统计 (100 分)

热门文章

  1. python爬去智联招聘网_Python爬虫爬取智联招聘(进阶版)
  2. Python Elasticsearch 报错 elasticsearch.UnsupportedProductError
  3. Python垃圾回收和GC模块
  4. 基于VUE+Echarts大屏数据展示150套 (集合)
  5. 新手必看的DIY装机教程(图解)
  6. Web端点餐系统(HTML5 + CSS3 + JS(jQuery))
  7. 【计算机毕业设计】家校通微信小程序的设计与实现
  8. 全景视频拼接(二)--OpenCV源码解析
  9. [转帖]ARM 相关内容
  10. Java、SQL Serve ----简单的增删查改