介绍:按键的物理结构导致了会有抖动现象的出现,判断按键是否真正按下,需要把抖动的部分滤波。根据经验可知,抖动一般在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
手机扫一扫
移动阅读更方便
你可能感兴趣的文章