强化版按键消抖Verilog实现
阅读原文时间:2023年07月11日阅读:1

介绍:按键的物理结构导致了会有抖动现象的出现,判断按键是否真正按下,需要把抖动的部分滤波。根据经验可知,抖动一般在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

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章