数字IC设计学习笔记
按键消抖模块1
1 原理图
2 Verilog 代码
3 Modelsim仿真
1. 原理图
(1). key波形图
理想的按键key信号在0,1转换之间,可以瞬时间完成;实际在按键时,会产生一定时间范围的抖动信号,这里抖动信号的持续时间定为20ms。
(2). key_flag, key_state 波形图
第一条波形为按键信号key;
第二条波形为key_flag信号,当滤除抖动波形完成后,产生单周期高脉冲;
第三条波形为key_state信号,当滤除抖动波形后,转变为与key信号一致的波形;
(3). 状态转移图
2 Verilog 代码
//----top module---------------------------------
module fsm_key_filter#(
parameter IDLE = 4'b0001,
parameter FILTER1 = 4'b0010,
parameter DOWN = 4'b0100,
parameter FILTER2 = 4'b1000
)
(
input clk, //50MHz 20us
input rst_n,
input key,
output key_flag,
output reg key_state
);
reg cnt_en;
reg cnt_full;
reg [19:0] cnt1;
//reg [19:0] cnt2;
reg [3:0] state;
reg key_syn1;
reg key_syn2;
reg key_reg1;
reg key_reg2;
wire pos_edge;
wire neg_edge;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
state <= IDLE;
cnt_en <= 1'b0;
end else
begin
case(state)
IDLE:
begin
if(neg_edge)begin
state <= FILTER1;
cnt_en <= 1'b1;
end else
begin
state <= IDLE;
cnt_en <= 1'b0;
end
end
FILTER1:
begin
if(cnt_full)//20ms
begin
state <= DOWN;
cnt_en <= 1'b0;
end
else if(pos_edge)
begin
state <= IDLE;
cnt_en <= 1'b0;
end else
begin
state <= FILTER1;
cnt_en <= cnt_en;
end
end
DOWN:
begin
if(pos_edge)begin
cnt_en <= 1'b1;
state <= FILTER2;
end else
begin
cnt_en <= 1'b0;
state <= DOWN;
end
end
FILTER2:
begin
if(cnt_full)
state <= IDLE;
else if(neg_edge)begin
cnt_en <= 1'b0;
state <= DOWN;
end
else
state <= FILTER2;
end
default: begin
state <= IDLE;
cnt_en <= 1'b0;
end
endcase
end
//----cnt--------------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt1 <= 20'd0;
else if(cnt_en)
cnt1 <= cnt1 + 20'd1;
else
cnt1 <= 20'd0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_full <= 1'b0;
else if(cnt1 == 20'd999_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
end
//----asyn_key-->syn---------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_syn1 <= 1'b0;
key_syn2 <= 1'b0;
end else
begin
key_syn1 <= key;
key_syn2 <= key_syn1;
end
end
//----key edge detect--------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_reg1 <= 1'b0;
key_reg2 <= 1'b0;
end else
begin
key_reg1 <= key_syn2;
key_reg2 <= key_reg1;
end
end
assign neg_edge = (!key_reg1) & key_reg2;
assign pos_edge = key_reg1 & (!key_reg2);
//----key_flag---------------------------------------
// always@(posedge clk or negedge rst_n)
// if(!rst_n)
// key_flag <= 0;
// else if(cnt_full)
// key_flag <= 1;
// else
// key_flag <= 0;
assign key_flag = (cnt1 == 20'd999_999)? 1'b1:1'b0;
//----key_state--------------------------------------
always@(posedge clk or negedge rst_n)
if(!rst_n)
key_state <= 1;
else if(cnt_full)
key_state <= ~key_state;
else
key_state <= key_state;
endmodule
//----------------------------------------------------
//----testbench--------------------------------------
`timescale 1ns/1ns
`define clock_period 20
module tb_fsm_key_filter;
reg clk;
reg rst_n;
reg key;
wire key_flag;
wire key_state;
fsm_key_filter uut(
.clk(clk),
.rst_n(rst_n),
.key(key),
.key_flag(key_flag),
.key_state(key_state)
);
initial clk = 1;
always #(`clock_period/2) clk = ~clk;
initial begin
rst_n = 0;
key = 1;//before press
#(`clock_period*10);
rst_n = 1;
#(`clock_period*1000000+1);
//-----------第一种testbench------------------
//-------------------------------------
//----first time-----------------------
//----press--------------------
// //---jitter------------
// key = 0;
// #1000;key = 1;
// #2000;key = 0;
// #1400;key = 1;
// #2600;key = 0;
// #1300;key = 1;
// #20; key = 0;
// //---non jitter--------
// #20000100;
// #50000100;
-----------------------------
//
----release------------------
// //---jitter------------
// #1000;key = 1;
// #2000;key = 0;
// #1400;key = 1;
// #2600;key = 0;
// #1300;key = 1;
// //---non jitter-------------
// #20000100;
-------------------------------------
----second time----------------------
----press--------------------
// //---jitter------------
// key = 0;
// #1000;key = 1;
// #2000;key = 0;
// #1400;key = 1;
// #2600;key = 0;
// #1300;key = 1;
// #20; key = 0;
// //---non jitter--------
// #20000100;
// #50000100;
-----------------------------
//
----release------------------
// //---jitter------------
// #1000;key = 1;
// #2000;key = 0;
// #1400;key = 1;
// #2600;key = 0;
// #1300;key = 1;
// //---non jitter-------------
// #20000100;
//
//-----------第二种testbench------------------
press_key;
#10000;
press_key;
#10000;
press_key;
#10000;
//#50000100;
$stop;
end
reg [15:0] myrand;
task press_key;
begin
repeat(50)begin
myrand = {
$random}%65536;//0~65535;
#myrand; key = ~key;
end
key = 0;
#50000000;
repeat(50)begin
myrand = {
$random}%65536;//0~65535;
#myrand; key = ~key;
end
key = 1;
#50000000;
end
endtask
endmodule
Testbench:
第一种详细列出激励信号,简单但代码冗长;
第二种采用task,随机发生函数$random,代码简单;
第三种采用仿真模型,单独一个module产生激励信号,多用于方真存储器模型等;(仿真模型一般由官方提供)
//----------------------------------------------------
//----第三种test bench--------------------------------------
`timescale 1ns/1ns
`define clock_period 20
module tb2_fsm_key_filter;
reg clk;
reg rst_n;
wire key;
wire key_flag;
wire key_state;
fsm_key_filter uut1(
.clk(clk),
.rst_n(rst_n),
.key(key),
.key_flag(key_flag),
.key_state(key_state)
);
fsm_filter_model uut2(
.key(key)
);
initial clk = 1;
always #(`clock_period/2) clk = ~clk;
initial begin
rst_n = 0;
#(`clock_period*10);
rst_n = 1;
#(`clock_period*1000000+1);
// #50000100;
// $stop;
end
//----仿真模型-------------------------------
`timescale 1ns/1ns
module fsm_filter_model(
output reg key
);
reg [15:0] myrand;
initial begin
key = 1;//before press
press_key;
#10000;
press_key;
#10000;
press_key;
#10000;
//#50000100;
$stop;
end
task press_key;
begin
repeat(50)begin
myrand = {
$random}%65536;//{$random}%6553(0~65535);{random}%65536:(-65535~65535)
#myrand; key = ~key;
end
key = 0;
#50000000;
repeat(50)begin
myrand = {
$random}%65536;//0~65535;
#myrand; key = ~key;
end
key = 1;
#50000000;
end
endtask
endmodule
endmodule
如何将仿真模型加载到testbench?
(Quartus)由于仿真模型内部是不可综合逻辑语句,所以在仿真前,需要将仿真模型加到testbench,按一下操作执行:
Assignment–> setting–>simulation–>1–>2–>3–>4,
再进行RTL simulation.
3 Modelsim仿真
学习原内容来自小梅哥FPGA自学笔记
【注】:个人学习笔记,如有错误,望不吝赐教,这厢有礼了~~~