FPGA学习日志——按键消抖key_filter

按键消抖key_filter

模块目的

通常按键开关往往为机械弹性开关,当机械触电断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。这样的抖动会对我们的按键操作产生一些干扰,比如:有时候按下了一次按键,但是会发生很多次的功能的变化,这就是因为抖动的存在。
在机械按键的触点闭合和断开时,都会产生抖动,为了保证系统能正确识别按键的开关,就必须对按键的抖动进行处理。单片机如果在触点抖动期间检测按键的通断状态,则可能导致判断出错,即按键一次按下或释放被错误地认为是多次操作,从而引起误处理。因此,为了确保单片机对一次按键动作只作—次响应,就必须考虑如何消除按键抖动的影响。

实验原理

按键稳定闭合时间长短是由操作人员决定的,通常都会在 100ms 以上,刻意快速按的话能达到 40-50ms 左右,很难再低了。抖动时间是由按键的机械特性决定的,一般都会在 10ms以内,为了确保程序对按键的一次闭合或者一次断开只响应一次,必须进行按键的消抖处理。当检测到按键状态变化时,不是立即去响应动作,而是先等待闭合或断开稳定后再进行处理。按键消抖可分为硬件消抖(通过硬件添加电容等元件来减少抖动)和软件消抖。

实验框图与波形图

在这里插入图片描述

在输入信号中,用上下抖动来模拟前后抖动大概在10ms以内,稳定状态随意设置。值得注意的是!其中计数器的设置:由于前后抖动加起来最大为20ms,所以只要按键时间大于20ms就可以判断为一定被按下,设置计数器为20ms,实验采用的时钟为50Mhz,一个时钟周期为20ns,1ms=1000000ns,所以计数器最大值M应设置为999_999.

其中cnt_20ms规则为:当key_in为高电平时归零,当key_in为低电平时,每一个时钟周期计数一次,当计数到最大值时一直保持CNT_MAX,直到key_in的高电平到来。

其中对于输出key_flag给出了两种方案

  1. 当cnt_20ms计数到最大值拉高电平,直到cnt_20ms为0拉低电平。
  2. 当cnt_20ms计数到最大值-1时拉高电平,不过只拉高一个时钟周期,此时key_flag信号将是一个脉冲信号,更适合后续模块利用。

实验代码

针对实验参数,应该单独给CNT_MAX用参数赋值,方便后续代码调用和仿真

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'b1)
        cnt_20ms<=20'd0;
            else    if(cnt_20ms==CNT_MAX)    
                    cnt_20ms<=cnt_20ms;
                    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'd0;
        else    if(cnt_20ms==CNT_MAX-20'd1)
                key_flag<=1'b1;
                else    key_flag<=1'b0;
endmodule

仿真代码

这里引入新的变量tb_cnt模拟按键,模拟按下开关后抖动的时间即5ms=250ns,即计数250次,8位宽
在这里插入图片描述

`timescale 1ns/1ns
module  tb_key_filter();
reg     sys_clk;
reg     sys_rst_n;
reg     key_in;

reg   [7:0]  tb_cnt;//模拟按下开关后抖动的时间即5ms=250ns,即计数250次,8位宽

wire    key_flag;
initial 
    begin
        sys_clk=1'b1;
        sys_rst_n<=1'b0;
        #20
        sys_rst_n<=1'b1;
    end
always #10 sys_clk=~sys_clk;//50Mhz 

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==1'b0)
        tb_cnt<=8'b0;
    else    if(tb_cnt==8'd249)
            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'b1;
    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<19)||(tb_cnt>199))
                    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
发出的红包

打赏作者

Chendy_00

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值