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

相关推荐
Terasic友晶科技26 分钟前
第13篇:Linux程序访问控制FPGA端Switch<二>
fpga开发·嵌入式系统·de1-soc开发板
cjie2216 小时前
FWFT_FIFO和Standard_FIFO对比仿真
fpga开发
9527华安7 小时前
国产紫光同创FPGA实现SDI视频编解码,基于HSSTHP高速接口,提供3套工程源码和技术支持
fpga开发·紫光同创·sdi·高速接口·hssthp
hahaha60168 小时前
ARINC818协议一些说明综述
fpga开发
_Hello_Panda_9 小时前
FX10(CYUSB4014)USB3.2(10Gbps)开发笔记分享(1):硬件设计与开发环境搭建
笔记·fpga开发·fx10·cyusb4014
FakeOccupational13 小时前
fpga系列 HDL:tips 初始化错误排查 & 仿真和实际不符的可能原因
fpga开发
FakeOccupational15 小时前
fpga系列 HDL:verilog latch在fpga中的作用 & 避免latch的常见做法
fpga开发
S&Z346316 小时前
[FPGA基础] RAM篇
fpga开发
绿算技术20 小时前
存储新势力:助力DeepSeek一体机
人工智能·科技·缓存·fpga开发
9527华安1 天前
国产紫光同创FPGA视频采集转SDI编码输出,基于HSSTHP高速接口,提供2套工程源码和技术支持
fpga开发·音视频·紫光同创·sdi·高速接口·hssthp