FPGA系统性学习笔记连载_Day17【状态机:实现按键消抖】 【verilog仿真】篇

2021-04-08 11:03:42 浏览数 (1)

FPGA系统性学习笔记连载_Day17【状态机:实现按键消抖】 【verilog仿真】篇

本系列为FPGA系统性学习学员学习笔记整理分享,如有学习或者购买开发板意向,可加交流群联系群主。

连载《叁芯智能fpga设计与研发-第17天》 【状态机:实现按键消抖】 【verilog仿真】

原创作者:紫枫术河 转载请联系群主授权,否则追究责任

本篇文章,采用状态机,来实现按键检测及消抖,本程序做成一个标准模块,模块输入clk,rst_n,key,flag_down,flag_up。

可以供工程使用,模块同时输出按键按下、抬起的标准信号,具体怎么用看工程需要。

一、代码实现

代码语言:javascript复制
module  FSM_key_fiter(
    input           clk,
    input               rst_n,
    input           key,
     
    output  reg     flag_up,
    output  reg     flag_down
);
 
    parameter   WAIT_DOWN   = 3'b000;
    parameter   DOWN            = 3'b001;
    parameter   DOWN_Fiter  = 3'b010;
    parameter   WAIT_UP     = 3'b011;  
    parameter   UP              = 3'b100;  
    parameter   UP_Fiter        = 3'b101;      
    parameter   OK              = 3'b110;
     
    parameter   T_10ms      = 500_000;
     
    reg [19:0]  cnt;
     
    reg [2:0] status;
 
     
    wire        flag_up_r;
    wire        flag_down_r;
 
     
    edge_check edge_check_inst(
        .signal     (key),
        .clk            (clk),
        .rst_n      (rst_n),
 
        .flag_up        (flag_up_r),
        .flag_down  (flag_down_r)
    );
 
     
    always@(posedge clk,negedge rst_n)begin
        if(!rst_n)
            begin
                status <= WAIT_DOWN;
                cnt <= 20'd0;
                flag_down <= 1'b0;
                flag_up <= 1'b0;            
            end
        else
            begin
                case(status)
                    WAIT_DOWN:
                                begin
                                    if(flag_down_r)
                                        status <= DOWN; 
                                    else
                                        status <= WAIT_DOWN;
                                end
                    DOWN:
                                begin
                                    cnt <= 20'd0;
                                    status <= DOWN_Fiter;   
                                end
                    DOWN_Fiter:
                                begin
                                    if(flag_down_r || flag_up_r)
                                        status <= DOWN;
                                    else
                                        begin
                                            if(cnt == T_10ms-1)
                                                begin
                                                    //flag拉高,产生脉冲
                                                    flag_down <= 1'b1;
                                                    cnt <= 20'd0;
                                                    status <= WAIT_UP;
                                                end
                                            else
                                                cnt <= cnt   1'b1;                                      
                                        end
                                end
                    WAIT_UP:
                                begin
                                    //flag拉低,只产生一个clk的脉冲
                                    flag_down <= 1'b0;                              
                                    if(flag_up_r)
                                        status <= UP;   
                                    else
                                        status <= WAIT_UP;  
                                end                                                                
                    UP:
                                begin
                                    cnt <= 20'd0;
                                    status <= UP_Fiter; 
                                end
                    UP_Fiter:
                                begin
                                    if(flag_down_r || flag_up_r)
                                        status <= UP;
                                    else
                                        begin
                                            if(cnt == T_10ms-1)
                                                begin
                                                    //flag拉高,产生脉冲
                                                    flag_up <= 1'b1;
                                                    cnt <= 20'd0;
                                                    status <= OK;
                                                end
                                            else
                                                cnt <= cnt   1'b1;                                      
                                        end
                                end
                    OK:
                                begin
                                    //flag拉低,产生脉冲
                                    flag_up <= 1'b0;                            
                                    status <= WAIT_DOWN;
                                end                                
                    default:
                                begin
                                    status <= WAIT_DOWN;
                                    flag_down <= 1'b0;
                                    flag_up <= 1'b0;                                
                                    cnt <= 20'd0;
                                end
                endcase
            end
    end
 
endmodule

二、仿真代码

代码语言:javascript复制
`timescale 1ns/1ps
 
 
module FSM_key_fiter_tb;
 
        reg         signal;
        reg     clk;
        reg     rst_n;
         
        wire        flag_down;
        wire        flag_up;
 
        FSM_key_fiter FSM_key_fiter_inst(
            .clk            (clk),
            .rst_n      (rst_n),
            .key            (signal),
            .flag_down  (flag_down),
            .flag_up        (flag_up)          
        );
 
        always #10 clk = ~clk;
         
        initial begin
            clk = 0;
            signal = 1;
            rst_n = 0;
            #20;
            rst_n = 1;
             
            //模拟按下
            signal = 1;
            //延时15ms
            #15000000; 
            repeat(50)
                begin
                    //抖动
                    signal = 0;
                    #10;
                    signal = 1;
                    #15;           
                    //抖动
                    signal = 0;
                    #17;
                    signal = 1;
                    #26;   
            end
            signal = 0;
             
            //延时15ms
            #15000000;
            //模拟抬起
            signal = 1;
            repeat(50)
                begin
                    //抖动
                    signal = 0;
                    #10;
                    signal = 1;
                    #15;           
                    //抖动
                    signal = 0;
                    #17;
                    signal = 1;
                    #26;   
            end
            signal = 1;
            #500;  
     
            //延时15ms
            #15000000;     
            $stop;
        end
     
 
endmodule

三、仿真波形

从图中看,我们检测按键有效,且产生的脉冲的判断条件是完整的按下和抬起全过程。

0 人点赞