想说的话...

本次实现的是一个24秒倒计时器,功能顾名思义,进行一个24秒的倒计时操作,本文先给出一个简单样例,并结合仿真验证功能,再对样例进行拓展,成为一个可以被调用的模块.

本文未涉及显示模块.

样例_边沿检测计数器

代码讲解

首先给出样例代码.

module CntDwn
(input CK//Clock
,output[4:0]CD//CountDown
);
parameter[4:0]cd=5'd24;//Define a parameter which can be modified when called
reg[4:0]dif=0;//Difference
always@(posedge CK)
if(dif==cd)
dif<=0;
else
dif<=dif+1;
assign CD=cd-dif;
endmodule

这段代码非常简单,原理即利用了一个边沿检测计数器直接实现计时功能,逻辑为每检测到一个升沿,差(dif)自增1,若差满,即和倒计时数相等,则差清零.

在这段代码里将倒计时数初始化为24,这个倒计时数在被其他模块调用的时候可以被修改,可移植性好.

仿真演示

`timescale 1 ns/ 1 ns
module CntDwn_vlg_tst();
reg CK;
wire[4:0]CD;
CntDwn i1 (.CD(CD),.CK(CK));
initial begin
CK=0;
end
always begin
#1 CK<=~CK;
end
endmodule

以上是样例代码的一个仿真文件(.vt),通过ModelSim仿真后波形如下图

[FPGA]Verilog实现可自定义的倒计时器(24秒为例)-LMLPHP

如果在仿真文件调用时修改传递参数,将Line 5改为

CntDwn #(.cd(10)) i1 (.CD(CD),.CK(CK));

则波形如下图

[FPGA]Verilog实现可自定义的倒计时器(24秒为例)-LMLPHP

可见,本样例代码成功实现了倒计时功能,接下来进行样例代码的拓展.

拓展_自定义倒计时数和倒计时间隔

代码讲解

module CntDwn
(input CK//Clock
,output[4:0]CD//CountDown
);
parameter[4:0]cd=5'd24;//Define a parameter which can be modified when called
parameter[25:0]div=26'd50;//Frequency Division
reg[25:0]cnt=0;//Timer.Control the period
reg[4:0]dif=0;//Difference
always@(posedge CK)
if(cnt==div)begin
cnt<=0;
dif<=dif+1;
end
else if(dif==cd)
dif<=0;
else
cnt<=cnt+1;
assign CD=cd-dif;
endmodule

这是拓展后的代码,加入了分频,可以自定义倒计时的间隔,在调用时修改传递参数来达到自定义间隔和倒计时数的功能.

代码中已经为分频参数初始化为50,方便下面仿真调试.

仿真演示

仿真文件如下

`timescale 1 ns/ 1 ns
module CntDwn_vlg_tst();
reg CK;
wire[4:0]CD;
CntDwn i1 (.CD(CD),.CK(CK));
initial begin
CK=0;
end
always begin
#1 CK<=~CK;
end
endmodule

波形如下

[FPGA]Verilog实现可自定义的倒计时器(24秒为例)-LMLPHP

由于分频参数为50,相当于比样例满了50倍,所以等尺寸缩放后时钟信号已经密密麻麻的(甚至密集到只能显示为一条粗粗的线),倒计时仍然功能正常,说明间隔功能无误.

总结

本文概述了如何通过Verilog实现倒计时器,并且加入了波形仿真的知识,方便验证和调试,还考虑到了参数调用的思想,增强代码的可读性,可维护性和可移植性.

值得说明的是,本文代码仍有缺漏,例如在调用时如果需要倒计时数大于32(5位宽),顶层代码中的参数位宽就要手动修改,不是很方便,一个解决方案就是将倒计时数的位宽也定义为一个WIDTH参数,使之也能够被传递不同的参数.分频参数已经定义为26位宽,基本能满足大多数情况的需求,一般不需要进行修改位宽的操作.

如果要实现秒倒计时器,在仿真层面可以将分频参数和自己的激励时钟信号周期相匹配,达到间隔为1秒的效果;如果要在开发板上实现,则需要考虑板载晶振的参数,计算分频参数,在调用时传递参数或直接修改参数来达到1秒间隔.

实例_24秒倒计时器

module CntDwn_24s
(input CK//Clock
,output[4:0]CD//CountDown
);
parameter[4:0]cd=5'd24;//Define a parameter which can be modified when called
parameter[25:0]div=26'd12000000;//Frequency Division,12M
reg[25:0]cnt=0;//Timer.Control the period
reg[4:0]dif=0;//Difference
always@(posedge CK)
if(cnt==div)begin
cnt<=0;
dif<=dif+1;
end
else if(dif==cd)
dif<=0;
else
cnt<=cnt+1;
assign CD=cd-dif;
endmodule

此段代码在板载晶振为12M的情况下正常运行.

05-19 01:45