【FPGA】按键消抖
目录
- 一丶按键原理
- 二丶按键消抖
- 三丶消抖方式
- 1.延迟采样
- ①任务描述
- ②编写代码
- ③时序图分析
- ④仿真
- 2.抖动稳定后采样
- ①任务描述
- ②编写代码
- ③代码分析
- ④仿真
- 四丶消抖场景
- 五丶消抖应用
一丶按键原理
我们首先来看原理图
可以看到有4条输入线接到FPGA的IO口(最左边四个KEY)上,分两种情况:
1.当按键KEY1
按下时,D3V3
(也就是电源)通过电阻R(原理图上折线的那一段)然后再通过按键KEY1
最终进入GND
形成一条通路,那么这条线路的全部电压都加到了R这个电阻上,KEY1
(最左边四个IO口)这个引脚就是个低电平。
2.当松开按键后,线路断开,就不会有电流通过,那么KEY1
和D3V3
就应该是等电位,是一个高电平。我们就可以通过KEY1
这个IO口的高低电平来判断是否有按键按下。
二丶按键消抖
由于机械按键的物理特性,按键被按下的过程中,存在一段时间的抖动,同
时在释放按键的过程中也存在抖动,这就导致在识别的时候可能检测为多次的按键按下,而通常检测到一次按键输入信号的状态为低电平,就可以确认按键被按下了,所以我们在使用按键时往往需要消抖,以确保按键被按下一次只检测到一次低电平
按键消抖解决方案1:延迟采样。(图片采用作者stark-lin)
按键消抖解决方案2:信号变化频率平稳后并且持续20ms则采样。
三丶消抖方式
1.延迟采样
①任务描述
任务:
我们需要在检测到按键抖动的时刻延时20ms再采样
思路:我们首先需要一个模块来检测按键是否抖动,如果抖动,→
给计时模块一个标志位开始计时,记满20ms,→
再给输出消抖后按键信号模块一个标志位进行采样。
理清思路,整个程序分为三个模块,模块之间相互关联,关联之处需要一个起到连接作用的器件,也就是标志位。比如将flag作为标志位,检测到按键抖动之后,将flag作为计时开始的条件。下面开始编写代码,之后进行时序以及代码分析。
②编写代码
key_debounce.v
module key_debounce ( input wire clk, //系统时钟 50MHzinput wire rst_n, //复位信号input wire key, //按键输入信号output reg key_done //消抖之后的按键信号
);reg key_r0; //同步信号(滤波作用,滤除小于一个周期的抖动)
reg key_r1; //打拍
reg flag; //标志位
wire nedge; //下降沿检测(检测到下降沿代表开始抖动)//计时器定义
reg [19:0] cnt;
wire add_cnt; //计时器开启
wire end_cnt; //计时记满parameter MAX_CNT=20'd1_000_000; //20ms延时//同步
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginkey_r0<=1'b1;endelsekey_r0<=key;
end//打拍
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginkey_r1<=1'b1; endelsekey_r1<=key_r0;
endassign nedge = ~key_r0 & key_r1; //检测到下降沿拉高//标志位
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginflag<=1'b0; endelse if (nedge) beginflag<=1'b1; endelse if (end_cnt) beginflag<=1'b0;end
end//延时模块
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt<=20'b0;endelse if (add_cnt) beginif (end_cnt) begincnt<=20'b0;endelsecnt<=cnt+1;end
endassign add_cnt=flag; //计时器开启
assign end_cnt=add_cnt&&cnt==MAX_CNT-1; //计时器关闭//key_done输出
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginkey_done<=1'b0; endelse if (end_cnt) begin //延时满20ms采样key_done<=~key_r0;endelsekey_done<=1'b0;
endendmodule
③时序图分析
clock:我们的整个程序都是在时钟的控制下运行的,所有的always模块都对时钟的上升沿敏感,本人使用的开发板时钟频率是50MHz,也就是一秒震动50_000_000次,一个周期就是20ns
always @(posedge clk or negedge rst_n)
key_in:这是按键输入信号,低电平有效
key_r0:为了滤除掉小于一个周期的抖动,对key_in推迟一个周期进行同步。看图
方框位置key_in输入的按键信号抖动为低电平,小于一个周期,在时钟上升沿(posedge 代表上升沿敏感)到来的时候信号已经恢复高电平,key_r0还是保持高电平,这样就达到了滤波的效果
key_r1:这个信号是把同步信号再延时一个周期,主要是为了保存key_r0上一个周期的值,来判断是否出现下降沿
nedge:检测key_r0是否出现下降沿,若出现,则将标志位flag设为1,也是计时器开启的条件
cnt:20ms计时器
add_cnt:计时器开启条件,用flag表示
end_cnt:计时器结束条件,记满20ms,也是采样模块的开启条件
key_done:计时器记满,则开始采样,key_done拉高一个周期,代表按键按下
④仿真
代码:
`timescale 1ns/1psmodule tb_key_debounce ();
reg tb_clk;
reg tb_rst_n;
reg tb_key;
wire tb_key_done;integer i,j;
defparam u_key_debounce.MAX_CNT=5; //将延时的时间修改为5个周期,也就是100nskey_debounce u_key_debounce( .clk (tb_clk) , //系统时钟 50MHz.rst_n (tb_rst_n) , //复位信号.key (tb_key) , //按键输入信号.key_done (tb_key_done) //消抖之后的按键信号
);always #10 tb_clk=~tb_clk;
initial begintb_clk=1'b1;tb_rst_n=1'b1;tb_key=1'b1;#100;//复位tb_rst_n=1'b0;#100;//恢复tb_rst_n=1'b1;//模拟按键抖动for (i = 0; i<=15; i=i+1) beginj=({$random}%15);#(j);tb_key={$random};end//按键按下tb_key=1'b0;#150;tb_key=1'b1;#2000;$stop;
endendmodule
方框标红处延时20ms开始采样,拉高一个周期
2.抖动稳定后采样
①任务描述
任务:
我们需要不停的检测到按键抖动,直到信号稳定之后再延时20ms,之后采样
思路:我们首先需要一个模块来检测按键是否抖动,如果抖动,→
给计时模块一个标志位开始计时,记满20ms,→
再给输出消抖后按键信号模块一个标志位进行采样。
计时模块与方式1不同,只要还在抖动就把计数器清零,重新计数20ms,直到抖动稳定
②编写代码
key_debounce.v
module key_debounce(input wire clk,input wire rst_n,input wire key_in,output reg key_flag, //判断抖动是否消除的标志信号,0为抖动,1为抖动结束output reg key_value //消抖后稳定的按键值给到蜂鸣器模块
);//定义20ms延迟计数器,0.2s,1_000_000次
reg [19:0] delay_cnt;//寄存依次key的值用来判断按键是否消抖成功
reg key_reg;parameter MAX_CNT=20'd1_000_000; //20ms//20ms延时计数器
always@(posedge clk or negedge rst_n)beginif(!rst_n)beginkey_reg <= 1'b1; //复位信号,设置按键无效delay_cnt <= 1'b0; //计数器设置为0endelsebeginkey_reg <= key_in; if(key_reg == 1 && key_in == 0) //当这一次key值和上一次key值不一样,证明正在抖动delay_cnt <= MAX_CNT; //延迟时间20mselse if(delay_cnt > 0)delay_cnt <= delay_cnt - 1; //没有抖动,开始20ms倒计时elsedelay_cnt <= 1'b0; end
end//根据延时计数器获取按键状态以及按键值
always@(posedge clk or negedge rst_n)beginif(!rst_n)beginkey_flag <= 1'b0; //复位信号,设置信号标志为抖动key_value <= 1'b1; //设置抽样值为1endelsebeginif(delay_cnt == 20'd1) //倒计时1_000_000到1beginkey_flag <= 1'b1;key_value <= key_in; //稳定20ms后将key值给到key_valueendelse beginkey_flag <= 1'b0;key_value <= key_value; //20ms内先不取样endend
end
endmodule
③代码分析
这里因为没有同步信号,和打拍信号,比较容易理解,就不画时序图做分析,可以对照仿真进行理解
计时模块中此处
key_reg
相当于消抖方式1的同步信号,同样检测到下降沿开始计时(即计时器清零,我们这里使用倒计时,效果一样)
红框中的条件也可以换成key_reg != key_in
,但是意义就不一样了,更改了之后就是只要前一个周期跟现在的信号有差异就计数,也就是出现下降沿和上升沿都计数,实际上差别不大,因为抖动时间在5-10ms内,有抖动一定会出现上升沿和下降沿
④仿真
代码:
`timescale 1ns/1psmodule tb_key_debounce ();
reg tb_clk;
reg tb_rst_n;
reg tb_key_in;
wire tb_key_flag;
wire tb_key_value;integer i,j;
defparam u_key_debounce.MAX_CNT=5; //将延时的时间修改为5个周期,也就是100nskey_debounce u_key_debounce( .clk (tb_clk) , //系统时钟 50MHz.rst_n (tb_rst_n) , //复位信号.key_in (tb_key_in) , //按键输入信号.key_flag (tb_key_flag) , //标志位.key_value (tb_key_value) //消抖之后的按键信号
);always #10 tb_clk=~tb_clk;
initial begintb_clk=1'b1;tb_rst_n=1'b1;tb_key_in=1'b1;#100;//复位tb_rst_n=1'b0;#100;//恢复tb_rst_n=1'b1;//模拟按键抖动for (i = 0; i<=15; i=i+1) beginj=({$random}%15);#(j);tb_key_in={$random};end//按键按下tb_key_in=1'b0;#150;tb_key_in=1'b1;#2000;$stop;
endendmodule
红框处,计时器从我修改的值延时5个周期(100ns),倒计时到0,key_value采样,电平拉低一个周期,代表按键低有效
四丶消抖场景
上面所提到的按键消抖方式我们可以想象:
①验证密码:
假设我们的密码是10101,设置key[1]代表密码1,key[0]代表密码0
我们第一次按下key[1],经过消抖之后,系统只会检测到一个按键低电平,代表只按了一次key[1],否则,不消抖的话,按一次,系统能检测到多次低电平,输入的密码就会出现错误
②按键控制LED灯状态切换
按下一个按键并松开,LED保持对应状态,切换按键,LED切换状态
如果跟①一样,那么按键必须按住不放LED才会显示对应的状态,因为按照我们的按键消抖,按一下只会输出一个周期的低电平,所以需要一直按下按键,才能保持低电平,在不改变按键消抖的前提下,我们可以设置一个标志位,在按键消抖模块输出一个周期低电平的时候给标志位flag赋值为1,让flag作为LED状态的条件
五丶消抖应用
1.按键消抖+识别字符串(类似于验证密码)
2.按键消抖+led灯状态切换(切换LED灯和呼吸灯)
【FPGA】按键消抖相关推荐
- stm32 工业按键检测_STM32单片机按键消抖和FPGA按键消抖大全
写在前面: 物联网STM32入门 - 直播课程 - 创客学院www.makeru.com.cn 按键去抖:由上图可以看出理想波形与实际波形之间是有区别的,实际波形在按下和释放的瞬间都有抖动的现象,抖 ...
- stm32硬件消抖_STM32单片机按键消抖和FPGA按键消抖大全
原标题:STM32单片机按键消抖和FPGA按键消抖大全 写在前面: 按键去抖:由上图可以看出理想波形与实际波形之间是有区别的,实际波形在按下和释放的瞬间都有抖动的现象,抖动时间的长短和按键的机械特性有 ...
- FPGA按键消抖(高级篇)
一. 硬件介绍 FPGA开发板 一个按键 一个led灯 二. 功能介绍 可以满足三种不同要求的消抖方式 通过led灯测试三种消抖方式 三. 消抖方式介绍 mode 0 : 按键按下消抖后,算一次. m ...
- FPGA编程按键消抖
FPGA按键消抖 编写思路 1.按键消抖的基本原理 2.代码原理 3.代码部分 4.仿真代码编写 5.仿真 6.总结 一.按键消抖的基本原理 按键消抖,按下,松开存在毛刺,主要为了消除毛刺.通过稳定后 ...
- 【 FPGA 】按键消抖与LED灯流动小实验
记录一个小实验吧,实验的目的是仅仅是塞塞牙缝而已,没其他意思,很简单. 功能:拨码开关控制led灯工作与否,拨码开关为on,led灯工作,否则不工作:导航按键up和down,也就是独立按键而已,控制l ...
- FPGA学习笔记---利用连续赋值语句延时功能实现按键消抖
最近一直在学习FPGA,今天在学习延时语句时,发现了连续赋值的一个特点.在连续赋值语句中添加延时时,任何小于延迟值的输入变化都会被滤除而不会体现在输出上.比如 #10 B = A; 当A的变化小于1 ...
- [FPGA入门笔记](十):按键消抖实验
简介 今天购买了AXLINX AX7020的开发板,从今天开始每一个例程都要做文档记录,为自己加油. 本实验,基于ALINX AX7020开发板,芯片为xc7z020clg400-2.开发板输入时钟为 ...
- FPGA VerilogHDL语言 数字钟 按键消抖
1.描述 一个简单的基于FPGA的数字钟,语言用的是VerilogHDL,可以实现以下功能: 1. 数码管显示0-59(秒表) 2. 数码管显示:时-分-秒 3. 数码管显示时分秒并且可以设置时间(小 ...
- FPGA学习-Verilog实现独立按键消抖
文章目录 前言 一.独立按键消抖原理 二.按键消抖程序实现(Verilog) 1.按键触发判断 2.计数器模块实现 3.按键状态更新 4.按键控制led亮灭 三.仿真测试文件编写 四.编译结果 前言 ...
- verilog基础-状态机之FPGA独立按键消抖设计与验证(熟练testbench的写法)
独立按键消抖设计与验证 本实验主要是为了锻炼状态机的思维模式以及熟练掌握TB的写法 本节主要收获了:define的用法,另外就是,顶层的input在TB中是reg的真正含义,其实就是把激励当做寄存器来 ...
最新文章
- linux手动注入网络数据_记一次手动SQL注入
- python turtle库画图案-Python基础图形绘制库——turtle
- 使用CocoaPods出现 The `master` repo requires CocoaPods 0.32.1 - 问题解决
- 走进移动支付:开启物联网时代的商务之门
- 收藏 | 一文读懂深度学习中的各种卷积
- php表示昨天_php输出各种时间代码表示
- getconnection java_在MyEclipse用java写的一个GetConnection1.java,用于连接MySQL,却总是出错。(没有财富值了,见谅!)...
- python 包含汉字的文件读写之每行末尾加上特定字符
- 《java入门第一季》之面向对象(成员方法)
- C语言程序设计(第五版)-谭浩强著-课后习题
- oop思想php,避免OOP的形式,POP的思想
- 塑胶模具设计之冷却系统
- EXCEL中发现不可读的内容。是否恢复此工作薄的内容?如果信任此工作薄的来源,请单击”是“
- html 用户列表,用户列表.html
- Ubuntu 16.04 系统 gflags glog 安装
- 在外企当程序员是怎样的体验?
- 网络命令一览表(绝对实用)
- 【分享】成功将Thinkpad E40 0578M59更换无线网卡AR9280
- 2017CVPR NID-SLAM:基于归一化信息距离的鲁棒单目SLAM系统
- SEO和反向链接对ASO的影响