18.按键消抖模块设计(使用状态机,独热码编码)

(1)设计意义:按键消抖主要针对的时机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子就断开。因而在闭合以及断开的瞬间会伴随有一连串的抖动,为了保证系统正确的识别到按键的开关,就必须对按键的抖动进行处理,这就是按键消抖。

(2)Verilog实现代码:

复制代码
module key_filter(clk,reset_n,key_in,key_p_flag,key_r_flag,key_state);

    input clk;
    input reset_n;
    input key_in;
    
    output reg key_p_flag;
    output reg key_r_flag;
    output reg key_state;
    
    reg key_in1;
    reg key_in2;
    reg key_in3;
    reg [3:0]STATE;
//抖动时间往往小于20ms,20ms = 20_000_000ns = 20ns * 1_000_000;   需要一个20位的寄存器
    reg [19:0]cnt;
    reg en_cnt;

    wire podge;
    wire nedge;
    wire arrive_time_20ms;
    
//状态设计
    parameter IDLE      = 4'b0001;
    parameter P_SHAKE   = 4'b0010;
    parameter DOWN      = 4'b0100;
    parameter R_SHAKE   = 4'b1000;
    
    
//异步输入key_in信号的同步化------------"打两拍"
    always@(posedge clk)begin
        key_in1 <= key_in;
        key_in2 <= key_in1;
    end

//上升沿、下降沿设计
    always@(posedge clk)
        key_in3 <= key_in2;
        
    assign podge = key_in2  &&  (!key_in3);
    assign nedge = (!key_in2)  &&  key_in3;
    
//20ms计数器模块设计    
    always@(posedge clk or negedge reset_n)
        if(!reset_n)
            cnt <= 20'd0;
        else if(en_cnt &&(cnt == 20'd999_999))
            cnt <= 20'd0;
        else if(en_cnt)
            cnt <= cnt + 20'd1;
        else 
            cnt <= 20'd0;
            
//计满20ms信号设计           
    assign arrive_time_20ms = (cnt == 20'd999_999);
    
//状态机主程序设计
    always@(posedge clk or negedge reset_n)
        if(!reset_n)begin
            key_r_flag <= 1'd0;
            key_p_flag <= 1'd0;
            key_state  <= 1'd1;
            STATE      <= IDLE;
        end
        else begin
            case(STATE)
                IDLE:begin
                    key_r_flag <= 1'd0;
                    key_state  <= 1'd1;
                    if(nedge)begin
                        STATE <= P_SHAKE;
                        en_cnt <= 1'd1;
                    end
                    else 
                        STATE <= STATE;
                end
                
                P_SHAKE:begin
                    if(arrive_time_20ms)begin
                        STATE <= DOWN;
                        en_cnt <= 1'd0;
                        key_p_flag <= 1'd1;
                        key_state <= 1'd0;
                    end
                    else if(podge)begin
                        STATE <= IDLE;
                        en_cnt <= 1'd0;
                    end
                    else 
                        STATE <= STATE;  
                end
                
                DOWN:begin
                    key_p_flag <= 1'd0;
                    key_state <= 1'd0;
                    if(podge)begin
                        STATE <= R_SHAKE;
                        en_cnt <= 1'd1;
                    end
                    else 
                        STATE <= STATE;          
                end
                
                R_SHAKE:begin
                    if(arrive_time_20ms)begin
                        STATE <= IDLE;
                        en_cnt <= 1'd0;
                        key_r_flag <= 1'd1;
                        key_state  <= 1'd1;
                    end
                    else if(nedge)begin
                        STATE <= DOWN;
                        en_cnt <= 1'd0;
                    end
                    else 
                        STATE <= STATE; 
                end
                
                default:begin
                    key_r_flag <= 1'd0;
                    key_p_flag <= 1'd0;
                    key_state  <= 1'd1;
                    STATE      <= IDLE;
                end
            endcase
        end

endmodule

(3)仿真文件代码:

复制代码
`timescale 1ns / 1ps

module key_filter_tb;

    reg clk;
    reg reset_n;
    reg key_in;
    
    wire key_p_flag;
    wire key_r_flag;
    wire key_state;

    key_filter key_filter_inst(
        .clk(clk),
        .reset_n(reset_n),
        .key_in(key_in),
        .key_p_flag(key_p_flag),
        .key_r_flag(key_r_flag),
        .key_state(key_state)
    );

    initial clk = 1'd1;
    always #10 clk = ~clk;
    
    initial begin
        reset_n <= 1'd0;
        key_in  <= 1'd1;
        #15;
        reset_n <= 1'd1;
        #2000;
        key_in <= 1'd0;
        #1500;
        key_in <= 1'd1;
        #20000;
        key_in <= 1'd0;
        
        #40_000_000;
        
        key_in <= 1'd1;
        #1000;
        key_in <= 1'd0;
        #200;
        key_in <= 1'd1;
        #1800;
        key_in <= 1'd0;
        #25000;
        key_in <= 1'd1;
        #30_000_000;
        $stop;
    end
    

endmodule

(4)仿真波形分析:

相关推荐
嵌入式软硬件攻城狮12 小时前
9.读写DDR测试
fpga开发
幻智星科技16 小时前
多通道数据采集DMA设计详解
fpga开发·udp·硬件架构
泡泡糖的中文规格书21 小时前
HDLbits 1.4 学习笔记
fpga开发
智感子2 天前
FPGA触发采集:预触发、多通道同步与软硬件分工怎么落地
fpga开发
156082072193 天前
关于AGC性能测试
fpga开发
威嵌神州3 天前
国产化加固计算机项目选型笔记|板卡、整机、平板与定制模块评估要点
笔记·fpga开发·电脑
泡泡糖的中文规格书3 天前
HDLbits 1.2 学习笔记
fpga开发·学习笔记·verilog
樱木花道長3 天前
AMD Ross 深度系列 5:实战演示 —— MATLAB 到 FPGA,edge-detection 边缘检测全流程
fpga开发
吉他英雄一里4 天前
FPGA--RAM
fpga开发
szxinmai主板定制专家4 天前
储能 EMS、微网控制器选型:RK3588、RK3576、RK3568+FPGA 怎么选?多网、多 CAN、EMC 设计权衡
人工智能·深度学习·机器学习·fpga开发·工业网关·rk3576·电力网关