文章目录

  • 一、按键消抖的原理
  • 二、按键消抖的设计思路
  • 三、代码部分
  • 四、仿真验证
  • 五、总结

一、按键消抖的原理

一般开发板上的按键都是机械按键,所以在按下的时候,会产生回弹的时刻,称为机械的弹性开关,这导致你按键按下但不一定真的按下了,按键弹起来了但不一定真的弹起来了,所以我们常常能看到这样的两幅图片
1.第一幅图是实际波形图,产生这样的毛刺

2.第二幅图是理想中的毛刺图

当然专业的术语还是的得看专业的,我这里只是笼统地讲一讲。

二、按键消抖的设计思路

按键消抖,顾名思义,就是当按键不再抖动的时候,整体的设计思路就是下降沿出现开始计数20ms,如果在计数20ms中又出现了一个上升沿,则计数清零,等待下一个下降沿,然后接着计数,反复如此,直到在20ms内未出现上升沿,算是真正的稳定了,也就是所谓的按键消抖了。

所以我们需要下降沿或者上升沿的检测,就拿下降沿来说,下降沿前一个周期的信号为低电平,后一个周期的信号为高电平,所以我们需要一些逻辑去判断这个是否为下降沿。

//下降沿
assign  n_edge = key_r0 & ~key_r1;
//上升沿
assign  p_edge = ~key_r0 & key_r1;

这里的key_r1与key_r0是一个信号,但是相差了一个周期,你想想,边沿就是信号在一个周期后的变化。

所以这个时候要借助打拍器了

何为打拍器,我也不能很好的告诉你,以我现在的水平只能告诉你打拍器是为了信号的稳定性,因为信号从0到1其实是有一个小斜坡的,如下图

在小斜坡上的值叫压摆率,中间的状态叫亚稳态,如果只取按下去的key的当前信号和key前一个周期信号,作为你检测边沿的条件,万一正好取在亚稳态上就不对了,所以需要借助打拍器,确保信号的稳定性,让数据更可靠。
然后第一个打拍是为了同步时钟信号,因为按键是异步信号,所以需要一个第一个打拍,当时钟周期为上升沿的时候,进行同步
具体参考:为什么需要打拍器

我们这里打三拍,也可以打两拍
这里按下复位键取-1,其实就是相当于2’b11,简单写法

// 对输入按键进行打拍,异步信号同步并检测边沿
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginkey_r0 <= -1;//负数以补码的方式存放,对原码取反加1key_r1 <= -1;key_r2 <= -1;end else begin key_r0 <= key_in;key_r1 <= key_r0;key_r2 <= key_r1;end
end

这里定义一个filter_flag,来判断下降沿的,如果是下降沿为1,不是则为0

//当检测到下降沿,filter_flag为1
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginfilter_flag <= 1'b0;end //检测到下降沿else if(n_edge)begin filter_flag <= 1'b1;end else if(end_cnt)beginfilter_flag <= 1'b0;endelse begin filter_flag <= filter_flag;end
end

对上一个模块的filter_flag标志来判断是否开始计数,如果出现下降沿的filter_flag标志开始计数,如果在计数中出现上升沿,则立马清零,计数的时间为20ms

//当检测到filter_flga为1的时候开始计数
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt <= 0;end else if(add_cnt)begin if(end_cnt || p_edge)begin cnt <= 0;endelse begin cnt <= cnt + 1;end endelse  begincnt <= cnt;end
end assign add_cnt = filter_flag;
assign end_cnt = add_cnt && cnt == DELAY_TIME-1;

最后一个模块是key_down的值,用来取最后抖动消除后并且计数达到20ms后稳定的key值,取的是最后一个周期的key_r2的值
(我也不知道为啥取key_r2的值,反正取最后一个就对了)
往后你就可以用这个稳定的key_down的值来使用

//key_down取的值是最后当前周期的key_r2值,是个稳定的值
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginkey_down <= 0;end else if(end_cnt)begin key_down <= ~key_r2;end else begin key_down <= 0;end
end

三、代码部分

这里定义一个常量KEY_W是按键个数,以后直接改变这个KEY_W的值来改变按键个数即可

module key_filter #(parameter KEY_W = 2,DELAY_TIME = 1_000_000)( input                             clk     ,input                              rst_n   ,input              [KEY_W-1:0]     key_in  ,output     reg     [KEY_W-1:0]     key_down
);  //计数器
reg     [19:0]      cnt;
wire                add_cnt;
wire                end_cnt;// 标志信号
reg                 filter_flag; reg      [KEY_W-1:0]  key_r0;
reg      [KEY_W-1:0]  key_r1;
reg      [KEY_W-1:0]  key_r2;    wire                  n_edge;
wire                  p_edge;// 对输入按键进行打拍,异步信号同步并检测边沿
// 打几拍就是延时几个周期
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginkey_r0 <= -1;//负数以补码的方式存放,对原码取反加1key_r1 <= -1;key_r2 <= -1;end else begin key_r0 <= key_in;key_r1 <= key_r0;key_r2 <= key_r1;end
end// assign  n_edge = {!key_r1[1] && key_r2[1],!key_r1[0] && key_r2[0]};//第一种检测边沿
//三目运算符
assign  n_edge = ~key_r1 & key_r2?1'b1:1'b0;//第二种检测边沿
// assign  p_edge = {key_r1[1] && !key_r2[1],key_r1[0] && !key_r2[1]};
assign  p_edge = key_r1 & ~key_r2?1'b1:1'b0;//当检测到下降沿,filter_flag为1
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginfilter_flag <= 1'b0;end //检测到下降沿else if(n_edge)begin filter_flag <= 1'b1;end else if(end_cnt)beginfilter_flag <= 1'b0;endelse begin filter_flag <= filter_flag;end
end//当检测到filter_flga为1的时候开始计数
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt <= 0;end else if(add_cnt)begin if(end_cnt || p_edge)begin cnt <= 0;endelse begin cnt <= cnt + 1;end endelse  begincnt <= cnt;end
end assign add_cnt = filter_flag;
assign end_cnt = add_cnt && cnt == DELAY_TIME-1;//key_down取的值是最后当前周期的key_r2值,是个稳定的值
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginkey_down <= 0;end else if(end_cnt)begin key_down <= ~key_r2;end else begin key_down <= 0;end
end
endmodule

四、仿真验证

1.成功消抖的波形图

2.未成功消抖的波形图(中间出现上升沿)

五、总结

这些就是我对按键消抖的理解,可能有很多不对的,但是思路应该是这样的一步一步地设计的,接下来我会用按键去实现别的功能。

【FPGA】实战之按键消抖相关推荐

  1. 【 FPGA 】按键消抖与LED灯流动小实验

    记录一个小实验吧,实验的目的是仅仅是塞塞牙缝而已,没其他意思,很简单. 功能:拨码开关控制led灯工作与否,拨码开关为on,led灯工作,否则不工作:导航按键up和down,也就是独立按键而已,控制l ...

  2. FPGA学习笔记---利用连续赋值语句延时功能实现按键消抖

    最近一直在学习FPGA,今天在学习延时语句时,发现了连续赋值的一个特点.在连续赋值语句中添加延时时,任何小于延迟值的输入变化都会被滤除而不会体现在输出上.比如  #10 B = A; 当A的变化小于1 ...

  3. stm32 工业按键检测_STM32单片机按键消抖和FPGA按键消抖大全

    写在前面: 物联网STM32入门 - 直播课程 - 创客学院​www.makeru.com.cn 按键去抖:由上图可以看出理想波形与实际波形之间是有区别的,实际波形在按下和释放的瞬间都有抖动的现象,抖 ...

  4. [FPGA入门笔记](十):按键消抖实验

    简介 今天购买了AXLINX AX7020的开发板,从今天开始每一个例程都要做文档记录,为自己加油. 本实验,基于ALINX AX7020开发板,芯片为xc7z020clg400-2.开发板输入时钟为 ...

  5. FPGA VerilogHDL语言 数字钟 按键消抖

    1.描述 一个简单的基于FPGA的数字钟,语言用的是VerilogHDL,可以实现以下功能: 1. 数码管显示0-59(秒表) 2. 数码管显示:时-分-秒 3. 数码管显示时分秒并且可以设置时间(小 ...

  6. FPGA学习-Verilog实现独立按键消抖

    文章目录 前言 一.独立按键消抖原理 二.按键消抖程序实现(Verilog) 1.按键触发判断 2.计数器模块实现 3.按键状态更新 4.按键控制led亮灭 三.仿真测试文件编写 四.编译结果 前言 ...

  7. stm32硬件消抖_STM32单片机按键消抖和FPGA按键消抖大全

    原标题:STM32单片机按键消抖和FPGA按键消抖大全 写在前面: 按键去抖:由上图可以看出理想波形与实际波形之间是有区别的,实际波形在按下和释放的瞬间都有抖动的现象,抖动时间的长短和按键的机械特性有 ...

  8. FPGA编程按键消抖

    FPGA按键消抖 编写思路 1.按键消抖的基本原理 2.代码原理 3.代码部分 4.仿真代码编写 5.仿真 6.总结 一.按键消抖的基本原理 按键消抖,按下,松开存在毛刺,主要为了消除毛刺.通过稳定后 ...

  9. FPGA按键消抖(高级篇)

    一. 硬件介绍 FPGA开发板 一个按键 一个led灯 二. 功能介绍 可以满足三种不同要求的消抖方式 通过led灯测试三种消抖方式 三. 消抖方式介绍 mode 0 : 按键按下消抖后,算一次. m ...

最新文章

  1. 在Linux(Ubuntu)下搭建ASP.NET Core环境并运行 继续跨平台
  2. SAP Spartacus npm install 里包含的 postinstall
  3. Incompatible JavaHL library loaded. Subversion 1.8.x required.
  4. html5 --- 利用localStorage进行本地存储
  5. C++ 学习之旅(2)——链接器Linker
  6. 光模块常见故障与使用注意事项详解
  7. SpringBoot集成MyBatis-Plus框架详细方法
  8. Android之Adobe AIR本地扩展
  9. Mongo散记--聚合(aggregation)amp; 查询(Query)
  10. Go_认识golang
  11. YOLOv4中的数据增强
  12. uniapp —— 实现左右联动商品分类页面
  13. mysql限制数据类型的长度_MySQL数据类型的长度
  14. iOS: 常用的宏
  15. Linux电源管理--PM QoS
  16. FastStone Capture 下载
  17. 服务器运维KPI指标,IT运维包括哪些内容,考核标准是什么
  18. 医疗APP有哪些功能
  19. 破解flowplayer
  20. Python界面设计之Button

热门文章

  1. python期末大作业之实现多线程爬虫系统
  2. ARM9嵌入式Linux开发-LCD
  3. Web全栈开发学习(1)
  4. [内核安全4]内核态Rootkit之IDT Hook
  5. 计算机网络前三章笔记
  6. Mysql登录报错:Can‘t connect to MySQL server on ‘localhost:3306‘ (10061)
  7. 【Java】抽象类继承的综合案例
  8. rstudio中logit模型代码
  9. [HR规划]什么是人力资源规划?(zt)
  10. MiCO系统开发MiCoder-IDE安装遇到的坑