[FPGA]Verilog实现可自定义的倒计时器(24秒为例)
想说的话...
本次实现的是一个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仿真后波形如下图
如果在仿真文件调用时修改传递参数,将Line 5改为
CntDwn #(.cd(10)) i1 (.CD(CD),.CK(CK));
则波形如下图
可见,本样例代码成功实现了倒计时功能,接下来进行样例代码的拓展.
拓展_自定义倒计时数和倒计时间隔
代码讲解
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
波形如下
由于分频参数为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的情况下正常运行.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现