数字IC设计学习笔记
按键消抖模块2
1 原理图
2 Verilog 代码
3 Modelsim仿真
1. 原理图
实验现象:
每次按下按键0,4个led显示状态以二进制加法格式加1;每次按下按键1,4个led显示状态以二进制加法格式减1.
2 Verilog 代码
//----top module---------------------------------
module fsm_key_filter_top(
input clk,
input rst_n,
input key0,
input key1,
output [3:0] led
);
wire key_flag0;
wire key_flag1;
wire key_state0;
wire key_state1;
led_ctrl uut_ctrl(
.clk(clk),
.rst_n(rst_n),
.key_flag0(key_flag0),
.key_state0(key_state0),
.key_flag1(key_flag1),
.key_state1(key_state1),
.led(led)
);
fsm_key_filter uut_filter0(
.clk(clk),
.rst_n(rst_n),
.key(key0),
.key_state(key_state0),
.key_flag(key_flag0)
);
fsm_key_filter uut_filter1(
.clk(clk),
.rst_n(rst_n),
.key(key1),
.key_state(key_state1),
.key_flag(key_flag1)
);
endmodule
//---------------------------------
//----抖动滤除模块------------------
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
//----异步信号key同步处理---------------------------------
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---------------------------------------
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
//-------------------------------------------------
//----LED灯控制模块--------------------------------
`timescale 1ns/1ns
module fsm_filter_model(
input press,
output reg key
);
reg [15:0] myrand;
initial begin
key = 1;//before press
end
always@(posedge press)
press_key;
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;
#25_000_000;
end
endtask
endmodule
//----------------------------------------------------
//----按键信号发生模型--------------------------------
`timescale 1ns/1ns
module fsm_filter_model(
input press,
output reg key
);
reg [15:0] myrand;
initial begin
key = 1;//before press
end
always@(posedge press)
press_key;
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;
#25_000_000;
end
endtask
endmodule
//----testbench-------------------------------
`timescale 1ns/1ns
`define clock_period 20
module tb_fsm_key_filter_top;
reg clk;
reg rst_n;
reg press0;
reg press1;
wire [3:0] led;
wire key0;
wire key1;
fsm_filter_model uut_model0(
.press(press0),
.key(key0)
);
fsm_filter_model uut_model1(
.press(press1),
.key(key1)
);
fsm_key_filter_top uut_top(
.clk(clk),
.rst_n(rst_n),
.key0(key0),
.key1(key1),
.led(led)
);
initial clk = 1;
always #(`clock_period/2) clk = ~clk;
initial begin
rst_n = 0;
press0 = 0;
press1 = 0;
#(`clock_period*10);
rst_n = 1;
#(`clock_period*10+1);
//----press0------------------------------
#80_000_000;
press0 = 1;//press
#(`clock_period*3);
press0 = 0;//release
#80_000_000;
press0 = 1;//press
#(`clock_period*3);
press0 = 0;//release
#80_000_000;
press0 = 1;//press
#(`clock_period*3);
press0 = 0;//release
#80_000_000;
press0 = 1;//press
#(`clock_period*3);
press0 = 0;//release
//----press1-------------------------------
#120_000_000;
press1 = 1;//press
#(`clock_period*3);
press1 = 0;//release
#80_000_000;
press1 = 1;//press
#(`clock_period*3);
press1 = 0; //release
#80000100;
$stop;
end
endmodule
endmodule
如何将仿真模型加载到testbench?
(Quartus)由于仿真模型内部是不可综合逻辑语句,所以在仿真前,需要将仿真模型加到testbench,按一下操作执行:
Assignment–> setting–>simulation–>1–>2–>3–>4,
再进行RTL simulation.
3. Modelsim仿真
按键模型
led的阳极端通过一个上拉电阻接到电源,若阴极端接低电平(LED[3:0]为低电平),led灯亮;若阴极端接高电平LED[3:0]为高电平),led灯灭;
学习原内容来自小梅哥FPGA自学笔记
【注】:个人学习笔记,如有错误,望不吝赐教,这厢有礼了~~~