题目:用Verilog实现按键抖动消除电路,抖动小于20ms,输入时钟10MHz。
按键在按下的时候会有抖动特点,如果不加以处理,可能会被识别为多次按下,所以要设计去抖动电路。
去抖动电路的核心思想就是通过计数器去计时,在按键按下的时候开始计数,当达到计数阈值时,再次判断当前的按键输入,如果开始和结束时一样,则判断为按键已按下,所以中间的时间段(本题为20ms)内不论按键发生了什么变化都无所谓
本次程序是我第二次使用状态机实现,当然也可以不用状态机(上一次使用状态机是序列检测)
电路共四个状态:
state1:清零状态 ;state2:计数状态 ; state3:计数完成检测输入是否变化 ;state4 :成功状态
状态转移图:
verilog代码:
`define DELAY_TIME 20 //ms
`define CLK_FREQUENCY 10 // Mhz
module debounce(
input clk,rst_n,din,
output pdge,ndge,
output reg dout,
output reg [1:0]current_state,
output reg [1:0]next_state,
reg [17:0] cnt//用来计数
);
parameter n_cnt = 1000*`CLK_FREQUENCY *`DELAY_TIME;//需要查的时钟个数,本题中为200,000个
parameter STATE1 = 2'b00;//状态1
parameter STATE2 = 2'b01;//状态2
parameter STATE3 = 2'b10;//状态3
parameter STATE4 = 2'b11;//状态4
reg din0, din1;//输入同步缓冲
assign pdge = (~din1) & din0;
assign ndge = (~din0) & din1;
always@(posedge clk,negedge rst_n)//输入同步缓冲
begin
if(!rst_n)
begin
din0 <= 0;
din1 <= 0;
end
else
begin
din0 <= din;
din1 <= din0;
end
end
always@(posedge clk,negedge rst_n)//状态机第一段
begin
if(!rst_n)
begin
current_state <= 0;
next_state <= 0;
end
else
begin
current_state <= next_state;
end
end
always@(posedge clk,negedge rst_n)//状态机第二段
begin
if(!rst_n)
begin
cnt <= 0;
next_state <= STATE1;
end
else
begin
case(next_state)
STATE1:
if(pdge == 1)next_state <= STATE2;
else next_state <= next_state;
STATE2:
if(cnt == n_cnt)next_state <= STATE3;
else cnt <= cnt + 1;
STATE3:
if(din1 == 1)next_state <= STATE4;
else
begin
next_state <= STATE1;
cnt <= 0;
end
STATE4:
if(din1 == 0)
begin
next_state <= STATE1;
cnt <= 0;
end
else next_state <= next_state;
default: next_state <= next_state;
endcase
end
end
always@(posedge clk,negedge rst_n)//状态机第三段
begin
if(!rst_n)
begin
dout <= 0;
end
else
begin
if(current_state == STATE4)dout <= 1;
else dout <= 0;
end
end
endmodule
testbench:
`timescale 10ns/10ns
module debounce_tb;
reg DIN, CLK, RST_N;
wire PDGE,NDGE,DOUT;
wire [1:0] CURRENT_STATE;
wire [1:0] NEXT_STATE;
wire [17:0] CNT;//用来计数
integer i,j;
debounce U_debounce(
.clk(CLK),
.rst_n(RST_N),
.din(DIN),
.dout(DOUT),
.pdge(PDGE),
.ndge(NDGE),
.current_state(CURRENT_STATE),
.next_state(NEXT_STATE),
.cnt(CNT)
);
initial
begin
CLK = 0;
RST_N = 1;
#6 RST_N = 0;
#6 RST_N = 1;
for(j = 0; j<10000000; j = j+1)
begin
#5 CLK = ~CLK;
end
end
initial
begin
DIN = 0;
for(i = 0; i<4; i = i+1)
begin
DIN = 1;
#4000000 DIN = 0;
#800000 DIN = 1;
#800000 DIN = 0;
#8000000;
end
end
endmodule
仿真结果: