设计规划
开发板上使用的机械按键在闭合及断开的瞬间均伴随有一连串的抖动,按键抖动会引起一次按键被误读多次,需要进行消抖处理:在按键闭合稳定时读取按键的状态,并且必须判别到按键释放稳定后再作处理 。
如果按键个数少,可以用硬件消抖,按键多时需要用软件消抖:检测出按键闭合后执行一个 20ms的延时程序 (抖动的时间为5ms~10ms)再一次检测键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。硬件消抖需要有额外的电路,软件消抖没有这种顾虑。
先用波形图模拟出按键被按下和释放时抖动的毛刺状态:
计数器一节中已经介绍过计数的实现方法,这里20ms的延迟需要一个20ms的计数器cnt_20ms。系统检测到按键输入为低电平就开始计数,如果20ms(50mhz的晶振需要计数个数为999_999)内检测出高电平说明是一个抖动,计数器清零。计数器计满999_999之后,key_flag拉高,一个时钟周期后变低,因此key_flag是脉冲信号。计数器计满后的状态至关重要,如果清零,当输入是低电平的时间过长就会造成一次按键却有多个key_flag脉冲的情况。
如果计满后不清零,到kin_in为高电平时再清零也会有新的问题,就是key_flag维持高电平时间太长,不再是一个脉冲信号。
此时如果令计数器记到999_998,就可以达到预期的效果。
编写代码
module key_filter#(parameter cnt_max = 20'd999_999 )(input wire sys_clk ,input wire sys_rst_n , input wire key_in , output reg key_flag //key_flag为1时表示消抖后检测到按键被按下//key_flag为0时表示没有检测到按键被按下);//reg definereg [19:0] cnt_20ms ; //计数器//cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_20ms <= 20'b0;else if(key_in == 1'b1)cnt_20ms <= 20'b0;else if(cnt_20ms == cnt_max && key_in == 1'b0)cnt_20ms <= cnt_20ms;elsecnt_20ms <= cnt_20ms + 1'b1;always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)key_flag <= 1'b0;else if(cnt_20ms == cnt_max - 1'b1)key_flag <= 1'b1;elsekey_flag <= 1'b0;endmodule首先定义了参数cnt_max是计数器的最大值,然后定义了输入输出和计数器。2^19<999999<2^20,因此需要20位的计数器。然后,还是要分析两个信号的变化,一个是计数器的状态,一个是标志位的状态。他们变化的条件都是时钟上升沿和复位有效(下降沿)。
cnt_20ms的变化是,如果复位有效就清零;如果检测到输入为高电平就清零;如果计满且输入为低电平就保持;如果没计满就+1。
key_flag的变化是,复位有效就清零,计数到999999-1就拉高,其他时候都为0。
编写testbench
`timescale 1ns/1nsmodule tb_key_filter(); parameter cnt_1ms = 20'd19 , cnt_11ms = 21'd69 , cnt_41ms = 22'd149 , cnt_51ms = 22'd199 , cnt_60ms = 22'd249 ; wire key_flag ; reg sys_clk ; reg sys_rst_n ; reg key_in ; reg [21:0] tb_cnt ; initial begin sys_clk = 1'b1; sys_rst_n <= 1'b0; key_in <= 1'b0; #20 sys_rst_n <= 1'b1; end //sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50mhz always #10 sys_clk = ~sys_clk; //tb_cnt:按键过程计数器,通过该计数器的计数时间来模拟按键的抖动过程 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) tb_cnt <= 22'b0; else if(tb_cnt == cnt_60ms) tb_cnt <= 22'b0; else tb_cnt <= tb_cnt + 1'b1; //key_in:产生输入随机数,模拟按键的输入情况 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) key_in = cnt_1ms && tb_cnt = cnt_41ms && tb_cnt <= cnt_51ms)) key_in = cnt_11ms && tb_cnt <= cnt_41ms) key_in <= 1'b0; else key_in 24)。0ms-1ms和41ms以上都为高电平。
7、实例化:这里定义了cnt_max,要小于11ms-41ms,否则会一直抖动。
对比波形
整体波形图,达到了预期效果:key_in低电平开始计数到cnt_max-1时一旦检测到输入高电平就清零,但是没有检测到输入信号为高电平,那么key_flag拉高成为一个脉冲信号。
空气污染可能会引发的疾病有哪些,你需要知道
2019年第三季度可穿戴设备出货量8450万台,同比增长94.6%
照明电路常见故障_照明电路故障排除方法
链改以后将会是区块链广泛的认知吗
如何快速实现具有专用高音单元和低音单元的高质量 TWS 耳塞设计
基于fpga的图像处理
威迈斯:已向Stellantis集团量产销售车载电源集成产品
放大器的输出电压/电流和1dB压缩点
图像查看器IrfanView 4 50已退出
如何推动电动汽车更加安全、高效的发展
5G时代即将来临,PCB产业商机巨大!
北斗导航系统应用在即:明年进入手机领域?
Tango系统
基于单片机的温湿度采集系统的硬件结构设计[图]
盘点中国、美国、俄罗斯和欧洲的月球基地计划
数控加工和传统机加工的区别
SHARK KSR-A0黑鲨新机已入网,搭载骁龙888处理器
基于数字信号处理器DSP芯片实现图像采集处理系统的设计
Murata BAC3S隔离式3W稳压单输出交流/直流转换器
首款针对物联网应用的CMOS图像传感器产品 — SC210IoT