FPGA的按键消抖之初学状态机

按键的结构图如图所示

 理想状态下,按键的波形图如图所示,按下即变为低电平,释放即变为高电平

 然而实际中,由于弹簧的存在,再按下按键和释放按键时会有一个抖动状态,如图所示:

 如果直接判断下降沿的产生就为按下,那么系统就会判定为按下了多次,这样就会出大问题!例如一个计数器,当按键按下一次就计数加1,如果下降沿判断,系统就会判定为按下了多次,从而计数器多次加1!但是明明操作者只按下了一次按键!

那么如何解决这个问题呢?经过研究发现,按键的抖动时间不会超过20ms!那么我们就对低电平/高电平检测持续时间,当持续时间大于20ms时,则判定经过了抖动状态,已经稳定了!

引入状态机:

按键一共存在四种状态:

状态1:空闲状态:此时等待按下操作的来临,当按下操做的来临,当按下操作来临后,检测到下降沿即即开始计时,转移到状态2,否则保持状态1不变。

状态2:按下抖动状态:20ms的计时状态,当计数小于20ms时检测到了上升沿,则返回状态1,当20ms内没有检测到上升沿时,则转到状态3。

状态3:等待释放状态:等待释放操作来临,当释放操作来临后,检测到上升沿即开始计数,转移到状态4,否则保持状态3不变。

状态4:释放抖动状态:20ms的计时状态,当计数小于20ms时检测到了下降沿,则返回状态3,当20ms内没有检测到下降沿时,则转到状态1。

 状态转移图如图所示:

程序要求:需要一个按下完成标志(Key_P_flag)和释放完成标志(Key_R_flag)

module key(
    input clk,
    input key,
    input rst,
    output reg key_p_flag,  //按下标志
    output reg key_r_flag //释放标志
    );
     
     reg [1:0] state;
     //定义状态机
     parameter state_1 = 2'd0; 
     parameter state_2 = 2'd1; 
     parameter state_3 = 2'd2; 
     parameter state_4 = 2'd3; 
     //定义20ms计数器
     parameter MCNT_20ms = 20'hF4240;
     reg [19:0] counter_20ms;   

     //检测按键下降沿以及上升沿
     reg [1:0] Detect;
     always@(posedge clk)
        begin
            Detect[0] <=key;
            Detect[1] <= Detect[0];
        end 
     wire posedge_detect;  //上升沿
     wire negedge_detect;  //下降沿
     assign posedge_detect = Detect == 2'b01;
     assign negedge_detect = Detect == 2'b10;
     //状态机循环
     always@(posedge clk or negedge rst)
        if(!rst)
            begin
                state <= state_1;
                counter_20ms <= 0;
                key_p_flag<=0;
                key_r_flag<=0;
            end
        else if (state == state_1)
            begin   
                    key_r_flag <=0;
                    if(negedge_detect)
                        begin
                            state<=state_2;
                            counter_20ms<=counter_20ms+1;
                        end
                    else state <= state;
            end
        else if(state == state_2)
            begin
                if(posedge_detect==1 && counter_20ms < (MCNT_20ms-1))
                    begin
                        state<=state_1;
                        counter_20ms <= 0;
                    end 
                else if(counter_20ms >=  (MCNT_20ms-1))
                    begin
                        state<=state_3;
                        counter_20ms <= 0;
                        key_p_flag <=1;
                    end
                else 
                    begin
                        state <= state;
                        counter_20ms<=counter_20ms+1;
                    end
            end
        else if ( state == state_3 )
            begin
                key_p_flag <=0;
                if(posedge_detect)
                    begin
                        state<=state_4;
                        counter_20ms<=counter_20ms+1;
                    end
                else state<=state;
            end
        else if(state == state_4) 
            begin
                if(negedge_detect && counter_20ms < (MCNT_20ms-1))
                    begin
                        state<=state_3;
                        counter_20ms <= 0;
                    end
                else if(counter_20ms > (MCNT_20ms-1))
                    begin
                        state<=state_1;
                        counter_20ms <= 0;
                        key_r_flag <=1;
                    end
                else
                    begin
                        state <= state;
                        counter_20ms<=counter_20ms+1;
                    end
            end

endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值