按键消抖

Posted ajiaoa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了按键消抖相关的知识,希望对你有一定的参考价值。

摘要:

本节将单 Bit 数据的异步信号同以及边沿检测方法引入到 FPG A中常用 的按键消抖设计,并在仿真测试吉利文件中引入随机数发生函数

消抖的实现分为硬件实现和软件实现,

技术图片

 

 

 

产生的抖动次数以及间隔时间均是不可预期的,这就需要通过
滤波来消除抖动可能对外部其他设备造成的影响。一般情况下抖动的总时间会持
续20ms 以内。这种抖动,可以通过硬件电路或者逻辑设计的方式来消除,也可
以通过软件的方式完成。其中硬件电路消除抖动适用于按键数目较少的场合。

下面先来讲硬件实现:

使用基于与非门的RS 触发器来消除抖动的电路图,如图 3.7-4 所示。假设
初始状态开关与B 接通,此时S=1,R=0,触发器置0 即Q=0;当B 切换到A 的
过程中,存在开关既没有与A 也没有与B 接触,此时S=1,R=1,触发器保持即
Q=0;当切换到A 瞬间时有R=1,S=0,触发器置1 即Q=1。此时即使当A 出现抖
动即S=1,触发器的状态仍能保持当前状态即Q=1 不变。整个过程波形图如图所
示Q。同理,可以分析出开关由A 切换到B 时触发器的状态变化。

技术图片

 

 请注意:这只适合于单刀双掷开关。

而对于两脚和四脚的按键目前常用的是RC电路和555定时器组成的单稳态触发器。

 

接下来是软件实现:

技术图片

 

 

 在按键没有按下时,处于高电平状态。

代码实现:

技术图片
module key_filter(
                clk,
                rst_n,
                key_in,
                key_flag,
                key_state
                );
    input clk;
    input rst_n;
    input key_in;
    output reg key_flag;//按键状态切换标志
    output reg key_state;//按键状态
    //因为按键是异步信号,先同步到系统时钟域
    reg key_in_r,key_in_rr;
    always@(posedge clk or negedge rst_n)
        if(!rst_n)begin    
            key_in_r<=0;
            key_in_rr<=0;
        end
        else begin
            key_in_r<=key_in;
            key_in_rr<=key_in_r;
        end
    //按键检测用到上升沿和下降沿检测
    reg key_in_rr_1,key_in_rr_11;
    wire pedge,nedge;
    always@(posedge clk or negedge rst_n)
        if(!rst_n)begin
            key_in_rr_1<=0;
            key_in_rr_11<=0;
        end
        else begin
            key_in_rr_1<=key_in_rr;
            key_in_rr_11<=key_in_rr_1;
        end
    assign pedge=(!key_in_rr_11) && key_in_rr_1;
    assign nedge=key_in_rr_11 && (!key_in_rr_1);
    //抖动计数包含使能模块和计数模块(按20ms来滤除,需要计数到1000000-1)
    reg [19:0]cnt;
    reg cnt_full;
    reg en_cnt;
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            cnt<=20d0;
        else if(en_cnt)
            cnt<=cnt+1b1;
        else
            cnt<=20d0;
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            cnt_full<=1b0;
        else if(cnt==20d999_999)
            cnt_full<=1b1;
        else
            cnt_full<=1b0;
    //状态机
    localparam IDLE=4b0001,FILTER0=4b0010,DOWN=4b0100,FILTER1=4b1000;
    reg [3:0]state;
    always@(posedge clk or negedge rst_n)
        if(!rst_n)begin
            en_cnt<=1b0;
            state<=IDLE;
            key_flag<=1b0;
            key_state<=1b1;
        end
        else begin
            case(state)
                IDLE:begin
                    key_flag=1b0;
                    if(nedge)begin
                        en_cnt<=1b1;
                        state<=FILTER0;
                    end
                    else
                        state<=IDLE;
                end
                FILTER0:begin
                    if(cnt_full)begin
                        en_cnt<=1b0;
                        state<=DOWN;
                        key_flag<=1b1;
                        key_state<=1b0;
                    end
                    else if(pedge)begin
                        state<=IDLE;
                        en_cnt<=1b0;
                    end
                    else
                        state<=FILTER0;
                end
                DOWN:begin
                    key_flag<=1b0;
                    if(pedge)begin
                        en_cnt<=1b1;
                        state<=FILTER1;
                    end
                    else
                        state<=DOWN;
                end
                FILTER1:begin
                    if(cnt_full)begin
                        en_cnt<=1b0;
                        state<=IDLE;
                        key_flag<=1b1;
                        key_state<=1b1;
                    end
                    else if(nedge)
                        state<=DOWN;
                    else
                        state<=FILTER1;
                end
                default:state<=IDLE;
            endcase
        end
        
    
endmodule 
View Code

tb:

技术图片
`timescale 1ns/1ns
module key_filter_tb;
    reg clk;
    reg rst_n;
    reg key_in;
    wire key_flag;//按键状态切换标志
    wire key_state;//按键状态
    key_filter key_filter(
                .clk(clk),
                .rst_n(rst_n),
                .key_in(key_in),
                .key_flag(key_flag),
                .key_state(key_state)
                );
    initial clk=0;
    always #10 clk=~clk;
    
    initial begin
        rst_n=0;
        #21;
        rst_n=1;
        //模拟抖动在20ms以内
        key_in=0;#1000;
        key_in=1;#2000;
        key_in=0;#1400;
        key_in=1;#2600;
        key_in=0;#1300;
        key_in=1;#200;
        //产生一个低电平大于20ms,代表稳定按下
        key_in=0;#20_000_100;
        #30_000_000;
        //模拟释放抖动20ms以内
        key_in=1;#1000;
        key_in=0;#2000;
        key_in=1;#1400;
        key_in=0;#2600;
        key_in=1;#1300;
        key_in=0;#200;
        //产生一个高电平大于20ms,代表稳定释放
        key_in=1;#20_000_100;
        #30_000_000;
        $stop;
    end
endmodule
View Code

tb_task:

技术图片
`timescale 1ns/1ns
module key_filter_tb_task;
    reg clk;
    reg rst_n;
    reg key_in;
    wire key_flag;//按键状态切换标志
    wire key_state;//按键状态
    key_filter key_filter(
                .clk(clk),
                .rst_n(rst_n),
                .key_in(key_in),
                .key_flag(key_flag),
                .key_state(key_state)
                );
    integer myrand;
    initial clk=0;
    always #10 clk=~clk;
    task press_key;
        begin
            repeat(50)begin
                myrand={$random}%65536;
                #myrand key_in=~key_in;
            end
            key_in=0;
            #50_000_000;
            repeat(50)begin
                myrand={$random}%65536;
                #myrand key_in=~key_in;
            end
            key_in=1;
            #50_000_000;
        end
    endtask
    initial begin
        rst_n=0;
        key_in=1;
        #21;
        rst_n=1;
        press_key;#10000;
        press_key;#10000;
        press_key;#10000;
        $stop;
    end
endmodule
View Code

波形图:

技术图片

 

 

 

 

 

 抖动放大:

技术图片

以上是关于按键消抖的主要内容,如果未能解决你的问题,请参考以下文章

FPGA按键防抖

FPGA按键防抖

FPGA按键防抖

经典按键扫描消抖算法实例仿真对比

用状态机写独立按键的消抖

按键消抖