概述
“众所周知”,FPGA中的操作,很多都是依靠参考时钟来进行的,最简单的
always@(posedge clk or negedge rst)
这条语句在always的敏感信号中,是基于clk的上升沿进行判断,然后再进行接下来的处理的。而实际上你的程序中会出现很多这样的always。
很经典的一个问题就是边沿检测!
按键的信号输入是在任意时刻都有可能发生的,这样的一个随机发生的信号,和系统时钟clk是没有可对照性的,因此会觉得很难处理这玩意儿。
下面来分析一下常用的处理方式
1.一级寄存
下面是主程序的代码,对一个输入信号in_signal进行判断,如果输入出现一个上升沿,则产生一个out_signal的输出高脉冲信号。
1.1主程序代码
module posedge_detect(
clk,
rst,
in_signal,
out_signal
);
input clk;
input rst;
input in_signal;
output out_signal;
reg in_signal_buf1;
/*****************寄存一次******************/
always@(posedge clk or negedge rst)
if(!rst)
in_signal_buf1<=1'b0;
else
in_signal_buf1<=in_signal;
assign out_signal = (!in_signal_buf1)&in_signal;
endmodule
1.2RTL视图
上面的RTL是在对主程序进行分析综合后得到的,可以看出,in_signal信号输入进D触发器进行了一次寄存,然后将D触发器的输出再和in_signal信号进行比较判断。以此来判断两次的输入信号值,通过与门判断是否出现了上升沿。
这里需要注意D触发器,在CLK的上升沿采样D端口的数据,然后输出到Q。通常我们看到的是,如果在CLK的上升沿,D上有个高电平信号,那么会立刻出现在Q端。但是实际情况不是这么理想的,D端数据需要提前保持稳定,然后CLK的上升沿才能采到数据(这个叫建立时间);同时,D的数据还要在CLK上升沿后一段时间继续保持稳定(这个叫保持时间);同时,Q端的数据是延迟D端数据一个时间Tco,这个就是输出延迟。这里写这些只是帮助自己记忆理解,不做分析了。
1.3TestBench
`timescale 1ns/1ns
`define clock_period 20
module posedge_detect_tb;
reg clk;
reg rst;
reg in_signal;
wire out_signal;
posedge_detect posedge_detect1(
.clk(clk),
.rst(rst),
.in_signal(in_signal),
.out_signal(out_signal)
);
initial clk = 1;
always #(`clock_period/2) clk = ~clk;
initial begin
rst = 1'b0;
in_signal = 1'b0;
#(`clock_period*200)
rst = 1'b1;
#(`clock_period*200)//在clk的上升沿处产生输入信号上升沿 #1
in_signal = 1'b1;
#(`clock_period*200)//在clk的上升沿处把输入信号拉低,这个输入的高脉冲信号时间足够长,大于一个clk时钟周期
in_signal = 1'b0;
#(`clock_period*200)//clk的上升沿拉高信号 #2
in_signal = 1'b1;
#5 //高电平持续5ns,注意这里是小于一个clk时钟周期了
in_signal = 1'b0;
#(`clock_period*200-10)//拉高输入信号,此时出现在clk的低电平处,不是边沿喽 #3
in_signal = 1'b1;
#5 //同样持续5ns,小于一个时钟周期
in_signal = 1'b0;
#(`clock_period*200+10)//拉高输入信号,此时出现在clk的高电平处 #4
in_signal = 1'b1;
#2000000000;
$stop;
end
endmodule
注意testbench中的4个输入模拟信号 分别标注了#1、#2、#3、#4;代码中给了明确注释
1.4仿真波形
根据上面的4幅图,可以看出,指示上升沿的脉冲信号out_signal,它的脉冲宽度是很难确定的。这个脉冲信号的下降沿是和后面的clk的上升沿对齐的;脉冲信号的上升沿是和输入信号in_signal的上升沿对齐的;这个out_signal的脉冲宽度很难被clk采样到,正常来说,要能被clk采样到,那么它的脉宽起码是一个clk的时钟周期。
2.二级寄存
接来下对信号进行二级寄存
2.1主程序代码
module posedge_detect(
clk,
rst,
in_signal,
out_signal
);
input clk;
input rst;
input in_signal;
output out_signal;
reg in_signal_buf1;
reg in_signal_buf2;
/*****************寄存两次******************/
always@(posedge clk or negedge rst)
if(!rst) begin
in_signal_buf1 <=1'b0;
in_signal_buf2 <=1'b0;
end
else begin
in_signal_buf1 <=in_signal;
in_signal_buf2 <=in_signal_buf1;
end
assign out_signal = (!in_signal_buf2)&in_signal_buf1;
endmodule
2.2RTL视图
2.3TestBench
仿真文件同上
2.4仿真波形
具体的分析都备注在图片中了。可见,当将异步输入信号进行两级寄存后,只要这个输入信号的脉宽足够,那么无论如何都能采到这个异步信号。
最后
以上就是狂野大神为你收集整理的FPGA学习专题-对异步信号的处理(边沿检测)1.一级寄存2.二级寄存的全部内容,希望文章能够帮你解决FPGA学习专题-对异步信号的处理(边沿检测)1.一级寄存2.二级寄存所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复