在按键信号的首尾加上计数器,以达到去抖的效果。
module key (in,clk,rst_n,outkey,outflag);
input in; //按键输入(物理)
input clk;
input rst_n;
output reg outkey; //按键输出(同步)
output reg outflag;//按下/松开标志
//--------------------------------------------------------------------
wire down;//检测到下降沿
wire up; //检测到上升沿
reg temp1,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;
//-------------------------------------------------------------------
reg en_cnt;//去抖模块送进来的
reg cnt_full;
reg [19:0]cnt;
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;
//---------------------------------------------------------------------
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
testbench
模拟按键抖动
`timescale 1ns/1ns
`define shizhong 20
module key_tb;
reg clk2;
reg rst_n2;
reg in2;
wire outflag2;
wire outkey2;
key f1(
.clk(clk2),
.rst_n(rst_n2),
.in(in2),
.outflag(outflag2),
.outkey(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_00; //按键稳定
//释放时抖动
in2 = 1 ;
#2000;
in2 = 0 ;
#1000;
in2 = 1 ;
#2000;
in2 = 0 ;
#1000;
in2 = 1 ;
#2600;
in2 = 0 ;
#1300;
in2 = 1 ;
#2_000_000_00; //按键稳定松开
$stop;
end
endmodule
功能仿真

生成了同步于当前时钟域的信号以供其他模块使用
测试
用按键改变数码管的显示内容,查看是否有抖动!

module top(
input clk,
input rst_n,
input key1,
output [5:0] dig,
output [7:0] dict
);
dig8_6 f0(
.clk(clk),
.rst(rst_n),
.set_data(data),
.dig(dig), //六位独热码表示六个数码管
.dict(dict) //位选数码管
);
key f1(
.in(key1),
.clk(clk),
.rst_n(rst_n),
.outkey(outkey1),
.outflag1()
);
//对outkey1进行上升沿检测,检测成功说明一次有效按键。——___——
wire outkey1;
reg dout;
wire out2dig;
always@(posedge clk or negedge rst_n)
if(!rst_n)
dout <= 1'b0;
else
dout <= outkey1;
assign out2dig = outkey1 & (!dout);
//将只能维持一个时钟周期的out2dig,转化为一个开关量。
reg switch;
always@(posedge clk or negedge rst_n)
if(!rst_n)
switch <= 1'b0;
else
begin
if(out2dig == 1'b1)
switch <= ~switch;
else
switch <= switch;
end
//数码管指示
reg [23:0]data;
always@(posedge clk or negedge rst_n)
if(!rst_n)
data <= 1'b0;
else
begin
if(switch == 1'b1)
data <= 24'hffffff;
else
data <= 24'h000000;
end
endmodule
测试平台(正点原子开拓者开发板)
clk Input PIN_E1
key1 Input PIN_E16
rst_n Input PIN_M1
dict[7] Output PIN_D9
dict[6] Output PIN_P11
dict[5] Output PIN_N11
dict[4] Output PIN_M10
dict[3] Output PIN_N13
dict[2] Output PIN_C9
dict[1] Output PIN_N12
dict[0] Output PIN_M11
dig[5] Output PIN_T15
dig[4] Output PIN_R16
dig[3] Output PIN_P15
dig[2] Output PIN_P16
dig[1] Output PIN_N15
dig[0] Output PIN_N16

博客介绍了使用Verilog在按键信号首尾加计数器实现去抖的方法。包含testbench模拟按键抖动,进行功能仿真生成同步信号,还在正点原子开拓者开发板上测试,通过按键改变数码管显示内容查看是否有抖动。
9522

被折叠的 条评论
为什么被折叠?



