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)仿真波形分析:

相关推荐
珞光电子USRP SDR软件无线电平台16 小时前
打破通用瓶颈:珞光电子发布 Luowave Driver V2 定制化驱动方案
fpga开发
9527华安16 小时前
FPGA实现PCIe数据通信培训课程,提供工程源码+视频教程+FPGA开发板
fpga开发·pcie·视频教程·培训
my_daling16 小时前
FPGA实现IIC主机读写,以及部分IIC传感器控制流程
fpga开发
乌恩大侠17 小时前
【AI-RAN】在空ubuntu服务器安装环境和生成TV,高达430G文件
服务器·人工智能·ubuntu·fpga开发·o-ru
qq_1508419918 小时前
高云FPGA固件下载速成
fpga开发
一个平凡而乐于分享的小比特19 小时前
一文读懂MCU与FPGA:核心区别、协同之道与双修秘籍
单片机·fpga开发·职场发展·mcu开发
LCMICRO-133108477461 天前
长芯微LD1871完全P2P替代AD1871,是一款立体声音频ADC
单片机·嵌入式硬件·fpga开发·音视频·硬件工程·dsp开发·音频adc
木心术11 天前
AI在FPGA中实现多平台射频信号时隙调整参考及案例
人工智能·fpga开发·信息与通信
LCMICRO-133108477461 天前
长芯微LD73360完全P2P替代AD73360,是一款工业电能计量6通道模拟输入前端(AFE) 处理器
stm32·单片机·嵌入式硬件·fpga开发·硬件工程·模拟前端afe
zjxtxdy2 天前
STM32开发
stm32·单片机·fpga开发