前言
一、边沿检测
1.1 使用背景
在我们设计电路时,经常会遇到需要继续检测上升沿和下降沿的电路,因此需要对边沿继续检测
1.2 方法:打拍法
1.2.1 背景
data数据信号不是时钟信号,不稳定,有许多毛刺,不能直接利用always语句中的posedge和nesedge来检测,因此需要通过其他办法来对边沿进行检测
有关毛刺,在数字电路的竞争与冒险中有讲解,是一个很重要的概念,希望读者先行掌握
1.2.2 原理
采用两个寄存器,对data数据信号进行打两拍处理,来消除数据不稳定产生的毛刺
1.2.3 上升沿
由上述波形图可知:上升沿脉冲即为data_0为0 ,data_1为1时所取的信号
代码
module pos_data(
input sys_clk,
input sys_rst_n,
input data,
output pos_data
);
reg data_0;
reg data_1;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
begin
data_0 <= 1'd0;
data_1 <= 1'd0;
end
else
begin
data_0 <= data;
data_1 <= data_0;
end
end
assign pos_data = data_0 && ~data_1; //若是下降沿,则改为~data_0 && data_1;若是边缘,则改为 data_0 ^ data_1
endmodule
tb代码
`timescale 1ns / 1ns
module tb_pos_data();
//parameter define
parameter CLK_PERIOD = 20;
//reg define
reg sys_clk;
reg sys_rst_n;
reg data;
//wire define
wire pos_data;
initial begin
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
data <= 1'b0;
#200
sys_rst_n <= 1'b1;
#200
data <= 1'b1;
#200
data <= 1'b0;
#200
data <= 1'b1;
end
always #(CLK_PERIOD/2) sys_clk = ~sys_clk;
pos_data u_pos_data(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.data (data),
.pos_data (pos_data)
);
endmodule
波形
需要注意的是,在编写Testbench时,要将data改变的时间间隔延长一些,否则结果不明显
二、计数器
2.1 原理
计时500ms用寄存器cnt_500;因为晶振为50MHZ,即20ns,所以需要cnt记到25000时清零,25000转化为二进制为0110 0001 1010 1000,有15位,所以cnt需要定义为15位
2.2 RTL代码
module cnt_500(
input sys_clk,
input sys_rst_n,
output reg [14:0] cnt
);
parameter CNT_MAX = 25000 ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 15'd0;
else if (cnt < (CNT_MAX - 1'd1))
cnt <= cnt + 1'd1;
else
cnt <= 1'd0;
end
endmodule
Testbench代码
`timescale 1ns / 1ns
module tb_cnt_500();
parameter CLK_PERIOD = 20;
reg sys_clk;
reg sys_rst_n;
wire [14:0] cnt ;
always #(CLK_PERIOD/2) sys_clk = ~sys_clk;
initial begin
sys_clk <= 1'd0;
sys_rst_n <= 1'd0;
#200
sys_rst_n <= 1'd1;
end
cnt_500 u_cnt_500(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.cnt (cnt)
);
endmodule
波形
符合预期
三、按键消抖
RTL代码
module key_debounce(
input sys_clk,
input sys_rst_n,
input key,
output reg key_filter
);
parameter CNT_MAX = 1000; //延时20ms
reg key_0;
reg key_1;
reg [9:0] cnt;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
key_0 <= 1'b0;
key_1 <= 1'b0;
end
else
begin
key_0 <= key;
key_1 <= key_0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 0;
else if ( key_0 != key_1 | cnt == (CNT_MAX - 1))
cnt <= 0;
else if (cnt < (CNT_MAX - 1) )
cnt <= cnt + 1;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
key_filter <= 1;
else if (cnt == (CNT_MAX-1))
key_filter <= key_1;
end
endmodule
Testbench代码
`timescale 1ns/1ns
module tb_key_debounce();
reg key;
reg sys_clk;
reg sys_rst_n;
wire key_filter;
parameter CLK_PERIOD = 20;
parameter CNT_MAX = 10;//延时200ns
initial begin
sys_clk <= 1'd0;
sys_rst_n <= 1'd0;
key <= 1'd1;
#10
sys_rst_n <= 1'd1;
key <= 1'd0;
#20
key <= 1'd1;
#30
key <= 1'd0;
#300
key <= 1'd1;
#20
key <= 1'd0;
#10
key <= 1'd1;
#30
key <= 1'd0;
end
always #(CLK_PERIOD/2) sys_clk = ~sys_clk;
key_debounce #(
.CNT_MAX (CNT_MAX)
)
u_key_debounce(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key (key),
.key_filter (key_filter)
);
endmodule
波形展示