9FPGA按键消抖

一、按键
按键消抖主要针对的是机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。
因而在闭合及断开的瞬间均伴随有一连串的抖动,为了保证系统能正确识别按键的开关,就必须对按键的抖动进行处理,这就是按键消抖。
消抖方式主要有两种
①硬件消抖:RS触发器(适用于按键个数比较少时)
②软件消抖:verilog语言编写(适用于按键个数比较多的时候)
在这里插入图片描述

在按键抖动时,可以分为前抖动和后抖动,其中前抖动和后抖动时间大概5ms—10ms左右,而中间稳定的时间大概在20ms左右,则需要计数M=999999 其计算方式如下
要实现20ms的计数,用50Mhz的晶振来实现,其计算过程如下所示
f=50Mhz=5 * 10四次方KHZ=50 * 10七次方HZ
即在单位时间内进行了50 * 10七次方的周期变化(单位时间为1s)
每次变化的时间T=1/f =1/(5 * 10七次方)s=2*10负八次方s=20ns
即每记一次数就计数20ns
20ms/20ns=1 * 10的六次方 所以计1 * 10六次方才能计20ms,但是计数是从0开始,所以计的个数为M=999999个

二、实现
1.波形图
方式一
在这里插入图片描述

cnt_20ms每当计满的时候清零并且key_flag就会产生一个高电平,但是会产生多个脉冲,并不能满足我们按键按下一次只有一次脉冲,因此不能满足我们的要求

方式二
在这里插入图片描述

这种方法是在前抖动时为高电平进行清零,为低电平时开始计数,当cnt_20ms计满的时候使其一直保持在999_999 且key_flag为高电平,直到检测到后抖动为高电平时cnt_20ms才清零,key_flag变为低电平,但是这样做的话会包含后抖动且key_flag持续周期太长,也不满足要求

方式三
在这里插入图片描述

这种方法是在前抖动时为高电平进行清零,为低电平时开始计数,当cnt_20ms计满的时候使其一直保持在999_999 且key_flag为高电平,直到检测到后抖动为高电平时cnt_20ms才清零,而key_flag是在M-1时产生一个高电平,虽然cnt_20ms有很多个999999 但是 M-1只有一个,满足要求

2.程序
代码程序
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

);

reg [19:0] cnt_20ms;

always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1’b0)
cnt_20ms <= 20’d0;
else if (key_in == 1’b0)
cnt_20ms <= 20’d0;
else if (cnt_20ms == CNT_MAX)
cnt_20ms <= CNT_MAX;
else
cnt_20ms <= cnt_20ms + 20’d1;

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-20’d1))
key_flag <= 1’b1;
else
key_flag <= 1’b0;

endmodule

仿真程序
在仿真程序中我们要模拟按键抖动,因此设置一个计数器,将其分段,在每个区间是高电平还是低电平或者是抖动,根据我们自己的要求进行编写
在这里插入图片描述

仿真代码如下
`timescale 1ns/1ns
module tb_key_filter();

reg sys_clk;
reg sys_rst_n;
reg key_in;
reg [7:0] tb_cnt;

wire key_flag;

always #10 sys_clk = ~sys_clk;

initial
begin
sys_clk = 1’b0;
sys_rst_n <= 1’b0;
#20
sys_rst_n <= 1’b1;
end

always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1’b0)
tb_cnt <= 8’d0;
else if (tb_cnt == 249)
tb_cnt <= 8’b0;
else
tb_cnt <= tb_cnt + 8’d1;

always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1’b0)
key_in <= 1’b0;
else if (((tb_cnt >= 8’d19) && (tb_cnt <= 8’d49))
|| ((tb_cnt >= 8’d149 ) && (tb_cnt <= 8’d199)))
key_in <= {$random} %2;
else if ((tb_cnt <= 8’d19) || (tb_cnt >= 8’d199))
key_in <= 1’b1;
else
key_in <= 1’b0;

key_filter
#(
.CNT_MAX (20’d24)
)
key_filter_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.key_in (key_in ),

.key_flag (key_flag)

);

endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值