强化版按键消抖Verilog实现

介绍:按键的物理结构导致了会有抖动现象的出现,判断按键是否真正按下,需要把抖动的部分滤波。根据经验可知,抖动一般在20ms内,所以常规的消抖方法是从变化沿出现时刻开始,延时20ms后判断按键的状态。这种方法适用范围不广,因为精度不高(如下图,会判断出错)。

 

 

 本次设计通过状态机的设计提高了按键消抖的性能,具体思路如图:

学习:

  ①testbench文件不会综合成电路,所以可以适用较多的高级语句。

  ②学会看IEEE手册,里面有很完整的语法讲解。想查看某个语句的语法,可以直接 Ctrl+F 搜关键字 ,找的比较

新语法:

  ①random function:产生一个随机数

    rand = $random(seed) 则rand为一个随机数,seed一般为1,2等,不影响结果,可以直接省略为 rand = $random

    rand = $random % range 则rand为在 - range  ~  +range-1  内的随机数 。%是取余运算

    rand = {$random } % range 则rand为在  0  ~  +range-1  内的随机数 。{}是取绝对值运算。

  ② repeat 重复,循环

    repeat(n)重复n次,下面跟begin-end语句,重复n次begin-end 。

   

 

 

代码实现:

复制代码
module buttopn_debounde(
    clk,
    tx,
    reset,
    bd_tx
    );
    input tx ;
    input clk ;
    input reset ;
    output reg bd_tx ;
    
    reg [1:0]edge_detect_regist;
    always@(posedge clk or negedge reset)//输入信号的移位寄存器
    begin
        if (!reset)
            edge_detect_regist <= 2'd0 ;
        else 
            begin
            edge_detect_regist[0] <= tx ;
            edge_detect_regist[1] <= edge_detect_regist[0] ;
            //等效于 edge_detect_regist <={ edge_detect_regist[0] , tx }
            end            
    end
    
    wire neg_edge , pos_edge ;
    assign neg_edge = ( edge_detect_regist == 2'b10 ) ? 1 : 0 ;//下降沿
    assign pos_edge = ( edge_detect_regist == 2'b01 ) ? 1 : 0 ;//上升沿
    
    parameter delay = 20000000 / 20 ;//抖动20ms
    
    reg [3:0]state ;   
    reg [19:0]counter1 ;
    always@(posedge clk or negedge reset)
    begin
        if (!reset)
            state <= 4'd0 ;//空闲态
        else if ( ( neg_edge ) && ( state == 4'd0 ) )
            state <= 4'd1 ;//按下消抖态
        else if ( ( state == 4'd1 ) && (( delay - 1) > counter1 ) && ( pos_edge ) )   
             state <= 4'd0 ;//空闲态
        else if ( ( state == 4'd1 ) && (( delay - 1) <= counter1 ) )
            state <= 4'd2 ;//按下态
        else if ( ( pos_edge ) && ( state == 4'd2 ) )
            state <= 4'd3 ;//释放消抖态   
        else if ( ( state == 4'd3 ) && (( delay - 1) > counter1 ) && ( neg_edge ) ) 
            state <= 4'd2 ;//按下态
        else if ( ( state == 4'd3 ) && (( delay - 1) <= counter1 ) )
            state <= 4'd0 ;//空闲态                          
    end
    

    always@(posedge clk or negedge reset)
    begin
        if (!reset)
            counter1 <= 5'd0 ;
        else if ( ( neg_edge ) || ( pos_edge ) ) 
            counter1 <= 5'd0 ;
        else if ( ( state == 4'd1 ) && (! neg_edge ) && (! pos_edge ) )
            counter1 <= counter1 + 1'd1 ;
        else if ( ( state == 4'd3 ) && (! neg_edge ) && (! pos_edge ) )
            counter1 <= counter1 + 1'd1 ;              
    end
    
    always@(posedge clk or negedge reset)
    begin
        if (!reset)
            bd_tx <= 1'd1 ;//空闲态
        else 
            case(state)
            0:bd_tx <= 1'd1 ;
            1:bd_tx <= 1'd1 ;
            2:bd_tx <= 1'd0 ;
            3:bd_tx <= 1'd0 ;
           endcase           
    end    
    
    reg pre_sign ;
    always@(posedge clk or negedge reset)
    begin
        if (!reset)
            pre_sign <= 1'd1 ;//空闲态
        else if( ( state == 4'd1 ) && (( delay - 1) <= counter1 ) )
            pre_sign <= 1'd0 ;
        else if ( state == 4'd2 )      
            pre_sign <= 1'd1 ;
    end
    
    reg release_sign ;
    always@(posedge clk or negedge reset)
    begin
        if (!reset)
            release_sign <= 1'd0 ;//空闲态
        else if( ( state == 4'd3 ) && (( delay - 1) <= counter1 ) )
            release_sign <= 1'd1 ;
        else if ( state == 4'd0 )      
            release_sign <= 1'd0 ;
    end       
            
endmodule
复制代码
复制代码
`timescale 1ns / 1ns
module button_debounce_tb(
    );
    
    reg clk ;
    reg tx ;
    reg reset ;
    wire bd_tx ;
    
    buttopn_debounde 
    #(
        .delay(100)
      )
    buttopn_debounde_sim(
    clk,
    tx,
    reset,
    bd_tx
    );
    
    initial clk = 1 ;
    always #10 clk = ! clk ;
    initial 
        begin
        reset = 1'd0 ;
        tx = 1'd1 ;
        #201 ;
        reset = 1'd1 ;
        #200 ;
        tx = 1'd0 ;#500 ;
        tx = 1'd1 ;#400 ;
        tx = 1'd0 ;#200 ;
        tx = 1'd1 ;#100 ;
        tx = 1'd0 ;#2100;
        #2000 ;
        tx = 1'd1 ;#100 ;
        tx = 1'd0 ;#200 ;
        tx = 1'd1 ;#1900;
        tx = 1'd0 ;#200 ;
        tx = 1'd1 ;#2000;
        #2000;
        $stop;
        end
endmodule
复制代码
复制代码
`timescale 1ns / 1ns
module button_debounce_tb_optimization(
    );
    
    reg clk ;
    reg tx ;
    reg reset ;
    wire bd_tx ;
    
    buttopn_debounde 
    #(
        .delay(100)
      )
    buttopn_debounde_sim1(
    clk,
    tx,
    reset,
    bd_tx
    );
    
    initial clk = 1 ;
    always #10 clk = ! clk ;
    initial 
        begin
        reset = 1'd0 ;
        tx = 1'd1 ;
        #200 ;
        reset = 1'd1 ;
        #2000 ;
        press_generator(1) ;
        #1000;
        press_generator(1) ;
        #10000;
        press_generator(1) ;
        #10000;
        $stop;
        end
        
    reg [31:0]rand ;
    task press_generator;
    input reg seeds;
        begin
            tx = 1 ;
            # 200 ;
            tx = ! tx ; //0    
            
            repeat(6) 
            begin
                rand = {$random(seeds)} % ( 2000 );
                # rand ; 
                tx = ! tx ;             
            end
            
            #10000;
            
            repeat(5) 
            begin
                tx = ! tx ;
                rand = {$random(seeds)} % ( 2000 );
                # rand ;
            end
            #10000;            
        end
    endtask
endmodule
复制代码

 

posted @   little_breeze  阅读(564)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示