按键信号的输入(in1) 是有抖动的,经过消抖处理,以得到标准的按键信号(l___l)。
边沿检测器来用来检测按键按下时的下降沿,和松开时的上升沿
计数器提供延时去抖
协助状态机进行去抖操作
module top(in1,clk1,rst_n1,outkey1,outflag1);
input in1;
input clk1;
input rst_n1;
wire down1;
wire up1;
wire cnt_full1;
wire en_cnt1;
output outkey1;
output outflag1;
abstract u1(
.in(in1),
.clk(clk1),
.rst_n(rst_n1),
.down(down1),
.up(up1)
);
counter u2(
.clk(clk1),
.rst_n(rst_n1),
.cnt_full(cnt_full1),
.en_cnt(en_cnt1)
);
key u3(
.down(down1),
.up(up1),
.cnt_full(cnt_full1),
.clk(clk1),
.rst_n(rst_n1),
.en_cnt(en_cnt1),
.outkey(outkey1),
.outflag(outflag1)
);
endmodule
module counter (clk,rst_n,cnt_full,en_cnt);
input clk;
input rst_n;
input en_cnt;
reg [19:0] cnt;
output reg cnt_full;
//系统时钟50M = 20ns 20ms = 20_000_000ns 0.2ms = 2000_000ns /20 = 1_000_000
//1 000 000 换算成二进制 得到 20个二进制位
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt <= 20'd0;
else if (en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 20'd0;
//计数器计满标志位
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_full <= 1'b0;
else if (cnt == 999_999)
cnt_full <= 1 ;
else
cnt_full <= 1'b0;
endmodule
module abstract(in, clk,rst_n,down,up);
//in 是输入信号,down为下降沿输出端,up为上升沿输出端
input in;
input clk;
input rst_n;
output down;
output up;
reg temp1;
reg temp2;
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
temp1 <= 1'b0;
temp2 <= 1'b0;
end
else
begin
temp1 <= in ;
temp2 <= temp1;
end
assign up = temp1 & (!temp2);
assign down = (!temp1) & temp2;
endmodule
module key (down,up,cnt_full,clk,rst_n,en_cnt,outkey,outflag);
input rst_n;
input clk;
input down;
input up;
input cnt_full;
output reg outflag;
output reg en_cnt;
output reg outkey;
localparam
DENGXIA = 4'b0001,
YANSHI = 4'b0010,
WENDING = 4'b0100,
YANSHI2 = 4'b1000;
reg [3:0]state; //状态寄存器
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
state <= DENGXIA;
en_cnt <= 1'b0;
outkey <= 1'b1;
outflag <=1'b0;
end
else begin
case(state)
DENGXIA :
begin
outflag <= 1'b0; //flag
if(down) begin
state <= YANSHI;
en_cnt <= 1'b1;
end
else
state <= DENGXIA;
end
YANSHI :
if(cnt_full)begin
outflag <=1'b1; //flag
outkey <= 1'b0; //out
state <= WENDING;
en_cnt <= 1'b0;
end
else if (up) begin
state <= DENGXIA;
en_cnt <= 1'b0;
end
else
state <= YANSHI;
WENDING :
begin
outflag <=1'b0; //flag
if(up) begin
state <= YANSHI2;
en_cnt <= 1'b1;
end
else
state <= WENDING;
end
YANSHI2 :
if(cnt_full)begin
outflag <=1'b1; //flag
outkey <= 1'b1; //out
state <= DENGXIA;
en_cnt <= 1'b0;
end
else if (down) begin
state <= WENDING;
en_cnt <= 1'b0;
end
else
state <= YANSHI2;
default :
begin
state <= DENGXIA;
en_cnt <= 1'b0;
outkey <=1'b1; //out
outflag <=1'b0;//flag
end
endcase
end
endmodule
`timescale 1ns/1ns
`define shizhong 20
module top_tb;
reg clk2;
reg rst_n2;
reg in2;
wire outflag2;
wire outkey2;
top u5(
.clk1(clk2),
.rst_n1(rst_n2),
.in1(in2),
.outflag1(outflag2),
.outkey1(outkey2)
);
initial clk2 = 1;
always#(`shizhong/2) clk2 = ~clk2;
initial begin
rst_n2 = 1'b0;
in2 = 1'b1;
#(`shizhong*10);
rst_n2 = 1'b1;
//模拟出按键的抖动过程 按下抖动
#(`shizhong*10 + 1);
in2 = 0 ;
#1000;
in2 = 1 ;
#2000;
in2 = 0 ;
#1400;
in2 = 1 ;
#2600;
in2 = 0 ;
#1300;
in2 = 1 ;
#200;
in2 = 0 ;
#2_000_000_000; //按键稳定
//释放时抖动
in2 = 1 ;
#2000;
in2 = 0 ;
#1000;
in2 = 1 ;
#2000;
in2 = 0 ;
#1000;
in2 = 1 ;
#2600;
in2 = 0 ;
#1300;
in2 = 1 ;
#2_000_000_000; //按键稳定松开
$stop;
end
endmodule
出不来 拉倒了