FPGA-按键消抖(状态机实现)

1,按键物理结构以及电路设计

普通按键的硬件示意图如下图所示。

上图是两脚贴片按键,原理图如下图所示。由原理图可以看出,按键未按下时IO口为高电平,按键按下时则变为低电平, 因此系统即可通过检测IO的电平来判断按键的状态。

按键结构示意图中可以看到按键存在一个反作用弹簧,因此当按下或者松开时均会产生 额外的物理抖动,物理抖动便会产生电平的抖动。在按键从按下再到松开的过程中,其电平 变化如下图所示,上为理想波形输出,下为实际波形输出。

上图中,产生的抖动次数以及间隔时间均是不可预期的,这就需要通过滤波来消除抖动可能对外部其他设备造成的影响。一般情况下抖动的总时间会持续 20ms 以内。

下图是按键工作状态:

2,如何滤除按键抖动,正确判断按键按下还是释放?

思路一

这种方法只能适用于一般情况,在工作状态比较差的情况下结果就有可能不可靠。

思路2

对按键消抖状态分析:

3,绘制状态转移图

对以上分析绘制状态转移图:

IDIE : 空闲状态

P_FILTER :按键是否按下检测状态

WAIT_R : 按键按下等待释放状态

R_FILTER:按键是否释放检测状态

4,编写代码

系统框图如下:

输入 : Clk 时钟信号   Reset_n 复位信号  key 按键输入信号

输出 : Key_P_Flag 按键按下信号   Key_R_Flag 按键释放信号

注意:由于按键信号是由外部输入得到,属于异步信号,如果直接使用会引起亚稳态,所以需要将其转为同步信号。

代码如下:

module key_filter(
    Clk,
    Reset_n,
    Key,
    Key_P_Flag,
    Key_R_Flag
    );
    input Clk;
    input Reset_n;
    input Key;
    output reg Key_P_Flag;
    output reg Key_R_Flag;
    
    reg sync_temp0_key;
    reg sync_temp1_key;
    wire nedge_key;
    wire pedge_key;
    reg r_key;
    reg [1:0]state;
    reg [19:0]cnt;
    parameter IDLE = 0,P_FILTER = 1,WAIT_R = 2, R_FILTER = 3;
    parameter MCNT = 20000000/20-1;
    //异步信号转同步信号
    always@(posedge Clk)
        sync_temp0_key <= Key;
    always@(posedge Clk)
        sync_temp1_key <= sync_temp0_key;
    always@(posedge Clk)
        r_key <= sync_temp1_key;
       
    //上升沿 下降沿
    assign nedge_key = ((r_key == 1)&&(sync_temp1_key ==0));
    assign pedge_key = ((r_key == 0)&&(sync_temp1_key ==1));
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)begin
        state <= 0;
        Key_P_Flag <= 0;
        Key_R_Flag <= 0;
        cnt <= 0;
   end
   else begin
        case(state)
            IDLE :begin
                Key_R_Flag <= 0;
                if(nedge_key)
                    state <= P_FILTER;
                else
                    state <= IDLE;
            end
            P_FILTER : begin
                if((pedge_key)&&(cnt < MCNT))begin
                    state <= IDLE;
                    cnt <= 0;
                    end
                else if(cnt >= MCNT)begin
                    Key_P_Flag <= 1;
                    cnt <= 0;
                    state <= WAIT_R;
                end
                else begin
                    state <= P_FILTER;
                    cnt <= cnt + 1'b1;
                    
                end
            end
            WAIT_R : begin
                Key_P_Flag <= 0;
                if(pedge_key)
                    state <= R_FILTER;
                else
                    state <= WAIT_R;
            end
            R_FILTER : begin
                if((nedge_key)&&(cnt < MCNT)) begin
                    state <= WAIT_R;
                    cnt <= 0;
                    end
                else if(cnt >= MCNT) begin
                    Key_R_Flag <= 1;
                    cnt <= 0;
                    state <= IDLE;
                end
                else begin
                    cnt <= cnt + 1;
                    state <= R_FILTER; 
                end   
            end 
            
        endcase
   end 
endmodule

测试代码testbench如下:

`timescale 1ns / 1ps
module key_filter_tb();
    reg Clk;
    reg Reset_n;
    reg Key;
    wire Key_P_Flag;
    wire Key_R_Flag;

    key_filter key_filter0(
    .Clk(Clk),
    .Reset_n(Reset_n),
    .Key(Key),
    .Key_P_Flag(Key_P_Flag),
    .Key_R_Flag(Key_R_Flag)
    );
    
    initial Clk = 1;
    always #10 Clk = ~Clk;
    
    initial begin
        Reset_n = 0;
        Key = 1;
        #201
        Reset_n <= 1;
        #3000
        Key = 0;
        #20000;
        Key = 1;
        #30000;
        Key = 0;
        #20000;
        Key = 1;
        #30000;
        Key = 0;
        #30000000;
        
        Key = 1;
        #30000;
        Key = 0;
        #20000;
        Key = 1;
        #30000;
        Key = 0;
        #20000;
        Key = 1;
        #30000000;
        $stop;    
    end
endmodule

仿真波形:

至此,按键消抖学习到此结束,之后在使用按键中就可以将此代码嵌入!

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值