简介:
可以在任意时刻启动,可以重复启动,延时时长可调,单位可切换(ms/us),在50MHz时钟下的延时范围是1ms-85899ms/1us-85899us。
源代码和modelsim仿真代码:
module delay
//#(parameter N ) //可以延时N*1ms/us
(input clk,rst_n,
input start, //start上升沿有效
input delay_unit, //延时单位,high:ms/low:us
output finish,finish_pose); //finish上升沿有效
reg start_reg0,start_reg1; //start两级缓存,用于边沿检测
reg finish_reg0,finish_reg1; //finish两级缓存
reg [31:0]cnt; //固定32位宽计数
reg [31:0]cnt_full;
reg restart; //重新开始
wire start_pose,full;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt <= 32'd0;
cnt_full <= 32'd10; //避免一开始finish置位
restart <= 1'b0;
start_reg0 <= 1'b0; start_reg1 <= 1'b0;
finish_reg0 <= 1'b0; finish_reg1 <= 1'b0;
end
else
begin
start_reg0 <= start; start_reg1 <= start_reg0;
finish_reg1 <= finish_reg0;
/**检测计时单位**/
if(delay_unit)
cnt_full <= 32'd50_000*2-32'd2; //计时2ms 实际例化时用N代替: 32'd50_000*N-32'd2
else
cnt_full <= 32'd50*2-32'd2; //计时2us
/***************/
/**是否重新开始**/
if(start_pose) //检测到起始时刻
restart <= 1'b1;
/****计时完成****/
else if(full) //延时结束
begin
cnt <= 32'd0; //cnt归零
finish_reg0 <= 1'b1; //finish响应
restart <= 1'b0;
end
/***************/
/****计时开始****/
else if(restart)
begin
finish_reg0 <= 1'b0; //新一轮延时finish复位
cnt <= cnt+1'b1;
end
/***************/
/**等待新一轮计时**/
else
begin
cnt <= cnt;
finish_reg0 <= finish_reg0;
restart <= restart;
end
end
end
assign start_pose = (~start_reg1&start_reg0)?1'b1:1'b0; //start上升沿检测
assign finish_pose = (~finish_reg1&finish_reg0)?1'b1:1'b0; //finish上升沿检测
assign full = (cnt_full-cnt==0)?1'b1:1'b0; //检测是否计满
assign finish = finish_reg0;
endmodule
/**************************************************************************************************/ /***************************************modelsim********************************************/
`timescale 1ns/1ps
module delay_tb();
reg clk,rst_n;
reg start;
wire finish,finish_pose;
delay delay_u0
(.clk(clk),
.rst_n(rst_n),
.start(start),
.delay_unit(1'b1),
.finish(finish),
.finish_pose(finish_pose));
//defparam delay_u0.N = 2; //延时2ms
initial
begin
clk = 1'b0;
rst_n = 1'b0;
start = 1'b0;
#1000 rst_n = 1'b1;
#4010 start = 1'b1; #50 start = 1'b0; end
always #10 clk = ~clk;
endmodule
思路:
start端口给上升沿启动延时,延时结束端口finish置位(重新启动延时后复位)、finish的上升沿检测在模块内部已做好(端口finish_pose),直接调用即可,端口delay_unit置高选择ms,置低选择us,#(parameter N )”是计时时长,例如计时8ms: "N = 8, .delay_unit(1'b1)",实际例化时只需“defparam 例化名.N = 数值”。因为modelsim无法识别这种调用,所以直接用数值代替N进行测试。边沿检测会消耗两个时钟周期,所以cnt_full需要减2,并且将finish_reg0直接连到finish输出端口而不是用finish_reg1连接finish。
延时2ms测试的起始时刻(5010ns)和结束时刻(2005010ns):