边沿检测:其实就是检测输入信号的跳变,即上升沿和下降沿的检测。
module edge_detect(
input clk, rst_n, data, //输入端口
output posedge0,negedge0 //输出端口
);
//one regester
reg data_1;
always@(posedge clk or negedge rst_n)
begin
if (! rst_n) //置位
begin
data_1 <= 1'b0;
end
else
begin
data_1 <= data; //触发器
end
end
assign negedge0 = data_1 & (~data); //下降沿检测
assign posedge0 = (~data_1) & data; //上升沿检测
endmodule
`timescale 1ns / 1ps
module tb_test(
);
reg clk,rst_n,data;
wire posedge0, negedge0;
//模块调用
edge_detect u1(
.clk(clk),
.rst_n(rst_n),
.data(data),
.posedge0(posedge0),
.negedge0(negedge0)
);
//initial
initial begin
clk = 0;
rst_n = 0;
#10
rst_n = 1;
data = 0;
#13
data = 1; //上升沿
#20
data = 0; //下降沿
#15
data = 1; //上升沿
#10
data = 0; //下降沿
end
//clk 信号
always #5 clk = ~clk;
endmodule
可以看到 检测到信号的边沿时,例如第一个data上升沿时,距离下一个的时钟沿的到来时间太短,可能会导致建立时间不够,从而导致毛刺的长生。
为此,我们采用两个触发器来检测
1.主程序
module edge_detect(
input clk, rst_n, data, //输入端口
output posedge0,negedge0 //输出端口
);
//one regester
reg data_1,data_2;
always@(posedge clk or negedge rst_n)
begin
if (! rst_n) //置位
begin
data_1 <= 1'b0;
data_2 <= 1'b0;
end
else
begin
data_1 <= data; //触发器
data_2 <= data_1; //触发器
end
end
assign negedge0 = data_2 & (~data_1); //下降沿检测
assign posedge0 = (~data_2) & data_1; //上升沿检测
endmodule
2.仿真
`timescale 1ns / 1ps
module tb_test(
);
reg clk,rst_n,data;
wire posedge0, negedge0;
//模块调用
edge_detect u1(
.clk(clk),
.rst_n(rst_n),
.data(data),
.posedge0(posedge0),
.negedge0(negedge0)
);
//initial
initial begin
clk = 0;
rst_n = 0;
#10
rst_n = 1;
data = 0;
#13
data = 1; //上升沿
#20
data = 0; //下降沿
#15
data = 1; //上升沿
#10
data = 0; //下降沿
end
//clk 信号
always #5 clk = ~clk;
endmodule
3.时序图
可以看到时钟沿信号产生了一个周期,消除了毛刺的产生,但同时检测信号的延迟增大。
三、总结
没有十全十美的东西,也没有十全十美的电路、代码;边沿检测技术亦如此。有如下缺陷:
(1)增大CLK信号可以增强边沿检测的效率,但不能滤去跳变的杂波。
(2)减少CLK可以有效滤去跳变的杂波,但不能及时检测到边沿跳变。
(3)增加DFF能更好的滤除杂波,寄存信号,但同时检测延时大。