当前位置: 首页 > news >正文

FPGA实战(08):Verilog 设计:带多级分频输出的 0~99 循环计数器(tops 模块)

前言

在数字系统中,计数器不仅是实现定时、状态机的基础,还经常兼任时钟分频器的角色。本文分享一个结构紧凑的 Verilog 模块——tops,它在0~99 循环计数的基础上,巧妙提取计数器的低 4 位,直接生成2/4/8/16 分频的同步输出。代码采用分区注释、异步复位、寄存器输出,适合 FPGA 初学者学习和工程复用。


1. 设计功能与创新点

功能点

  • 带符号的 0~99 循环计数器:每个时钟上升沿计数值 +1,计到 99 后自动归零,输出 10 位有符号数o_cout
  • 多级时钟分频输出:利用计数器低 4 位的周期性翻转,同步输出o_clk_2_div(2分频)、o_clk_4_div(4分频)、o_clk_8_div(8分频)、o_clk_16_div(16分频)。
  • 异步复位i_rst高电平有效,立即将所有寄存器清零。
  • 无毛刺寄存器输出:所有分频信号均经过寄存器打拍,输出稳定可靠。

创新点

  • “一计多用”的资源复用:不再单独例化分频器,而是直接抽取模 100 计数器的比特位,实现 2~16 分频。这种方法节省了寄存器和组合逻辑资源。
  • 符号位显式处理:在计数器自增时使用$signed将常量转为有符号数,消除混合符号类型的综合警告,提升代码可移植性(本版代码未使用$signed但保留了有符号声明,可根据需要添加)。
  • 预留式模块框架:顶层通过param / reg / wire / FSM / inst / combine_Logic / always等注释分区,为后续扩展状态机或子模块留下清晰接口,团队协作更高效。
  • 全覆盖条件写法always块用else if(1)保证条件树完整,综合工具会自动优化冗余逻辑,但代码阅读者可直观理解优先级。

2. 模块代码与详细解析

2.1 顶层模块tops

module tops( input i_clk , input i_rst , output signed [ 9: 0] o_cout , output o_clk_2_div , output o_clk_4_div , output o_clk_8_div , output o_clk_16_div ); //**************param*****************// //**************reg*******************// reg signed [ 9: 0] ro_cout ; reg ro_clk_2_div ; reg ro_clk_4_div ; reg ro_clk_8_div ; reg ro_clk_16_div ; //**************wire******************// //**************assign****************// assign o_cout = ro_cout ; assign o_clk_2_div = ro_clk_2_div ; assign o_clk_4_div = ro_clk_4_div ; assign o_clk_8_div = ro_clk_8_div ; assign o_clk_16_div = ro_clk_16_div ; //**************FSM*******************// //**************inst******************// //**************combine_Logic*********// //**************always****************// always @(posedge i_clk or posedge i_rst )begin if(i_rst) ro_cout <= ('d0) ; else if(ro_cout == 'd99) ro_cout <= ('d0) ; else if(1) ro_cout <= (ro_cout + 'd1) ; else ro_cout <= ro_cout ; end always @(posedge i_clk or posedge i_rst )begin if(i_rst) ro_clk_2_div <= ('d0) ; else ro_clk_2_div <= ro_cout[0] ; end always @(posedge i_clk or posedge i_rst )begin if(i_rst) ro_clk_4_div <= ('d0) ; else ro_clk_4_div <= ro_cout[1] ; end always @(posedge i_clk or posedge i_rst )begin if(i_rst) ro_clk_8_div <= ('d0) ; else ro_clk_8_div <= ro_cout[2] ; end always @(posedge i_clk or posedge i_rst )begin if(i_rst) ro_clk_16_div <= ('d0) ; else ro_clk_16_div <= ro_cout[3] ; end endmodule

2.2 代码解析

1. 端口与寄存器

  • o_cout:10 位有符号计数器值,直接由ro_cout驱动。
  • o_clk_2_div~o_clk_16_div:分频输出,由对应寄存器驱动,保证无组合逻辑毛刺。
  • 所有输出寄存器均支持异步复位(高电平有效)。

2. 计数器逻辑

  • 异步复位时ro_cout清零。
  • 达到上限 99 后下一周期归零,形成模 100 循环。
  • 其余情况每个时钟加 1,使用ro_cout + 'd1(若无符号乘除问题可省略$signed,但建议在混合类型时显式转换)。

3. 分频输出逻辑

  • ro_clk_2_div <= ro_cout[0]ro_cout[0]是计数器的最低位,在连续加 1 时每个时钟翻转一次,因此寄存器输出为时钟的2 分频信号(占空比 50%)。
  • ro_clk_4_div <= ro_cout[1]ro_cout[1]每 2 个时钟翻转一次,对应4 分频
  • ro_clk_8_div <= ro_cout[2]ro_cout[2]每 4 个时钟翻转一次,对应8 分频
  • ro_clk_16_div <= ro_cout[3]ro_cout[3]每 8 个时钟翻转一次,对应16 分频
  • 注意:由于计数器模 100 并非 2 的幂,高位的占空比可能不是严格的 50%,但频率关系依然正确。对于常规使能应用已足够,若需完美 50% 占空比,可改用模 2^N 的计数器。

4. 时序说明

  • 所有分频寄存器均在同一posedge i_clk采样ro_cout的比特位,因此输出相对于ro_cout有一级延迟,完全同步于系统时钟,可安全用于跨时钟域逻辑(经同步化后)。

3. 测试平台(Testbench)

为了验证计数器及分频功能,编写如下 testbench:

`timescale 1ns / 1ps module test_tops; reg i_clk; reg i_rst; wire signed[9:0] o_cout; wire o_clk2div; wire o_clk4div; wire o_clk8div; wire o_clk16div; tops tops_u( .i_clk (i_clk), .i_rst (i_rst), .o_cout (o_cout), .o_clk_2_div (o_clk2div), .o_clk_4_div (o_clk4div), .o_clk_8_div (o_clk8div), .o_clk_16_div (o_clk16div) ); initial begin i_clk = 1'b1; i_rst = 1'b1; #100 i_rst = 1'b0; end always #5 i_clk = ~i_clk; // 10ns 时钟周期 endmodule

激励说明

  • 时钟:周期 10 ns,占空比 50%。
  • 复位:初始高电平持续 100 ns,覆盖前 10 个时钟周期,确保可靠复位。
  • 观察信号:计数器值o_cout和四路分频信号。

4. 仿真结果与分析

在 ModelSim 或 Vivado 中运行仿真,可观察到以下波形(文字描述):

  • 0~100 ns(复位期)i_rst=1o_cout=0,所有分频输出均为 0。
  • 105 ns 起:复位释放后第一个时钟上升沿,计数器o_cout由 0 变为 1。
    • o_clk2div(对应ro_cout[0])在计数器 0→1 的下一周期变为高(即采集到ro_cout[0]的旧值 0,所以初始为低,然后翻转)。
    • 实际波形会显示o_clk2div每个时钟周期翻转一次,频率为 50 MHz(时钟 100 MHz 时)。
  • 计数循环o_cout从 0 递增到 99,然后归零,不断重复。
  • 分频验证
    • o_clk2div周期为 20 ns(2 倍时钟周期),上升/下降沿与计数器 LSB 同步。
    • o_clk4div周期为 40 ns,o_clk8div周期为 80 ns,o_clk16div周期为 160 ns。
    • 由于计数器的循环特性,即使经过 99→0 的突变,分频输出的连续性依然保持,无异常脉冲。

仿真截图建议(实际发布时可插入波形图片):

  • 展示复位释放瞬间的放大波形,查看分频与计数器的时序关系。
  • 展示计数值从 98→99→0 时,四个分频信号的电平变化。

5. 总结与扩展

总结

tops模块通过一个简洁的模 100 计数器,不仅输出带符号的计数值,还免费获得了 2/4/8/16 分频信号。这种“一计多用”的思路有效降低了逻辑资源消耗,同时寄存器输出消除了分频毛刺,在低速接口、LED 闪烁控制、简单时序产生等场景中非常实用。

扩展建议

  1. 参数化模值:引入parameter MAX = 99,并将判断条件改为ro_cout == MAX,便于修改计数上限。
  2. 分频级数可配置:通过参数控制抽取的比特位宽度,实现更多分频级数。
  3. 加入使能信号:添加计数使能端,在需要时才递增,实现可控分频。
  4. 消除非 2 次幂模值对分频占空比的影响:若要求严格 50% 占空比,可将计数器改为模 128 (2^7) 或直接使用独立的分频计数器。

希望这篇博客能帮助你快速理解 Verilog 中“计数器+分频”的复用设计。如果你有更巧妙的分频实现方式,欢迎在评论区留言交流!

http://www.jsqmd.com/news/1005201/

相关文章:

  • Codex 客户端对接 Agnes-2.0-Flash免费多模态大模型 AI 编程实现指南
  • buildroot Makefile include *.mk 的玄机.
  • 2026世界杯叒是“诸神的黄昏”懂球体育这一届梅西C罗真将成历史!
  • 【创新实训】五、事故复盘报告生成与知识库沉淀
  • BetterNCM Installer终极指南:解锁网易云音乐的无限可能
  • AI专著生成大揭秘:用AI工具,一键搞定20万字专著撰写难题!
  • MySQL的访问和数据流动
  • 嵌入式汇编开发环境变量配置:从ASMOPTIONS到项目级构建管理
  • 如何5分钟掌握网页媒体智能捕获:开源工具终极实战指南
  • 3步快速解决线缆依赖问题:NoCableLauncher的完整使用指南
  • 埃摩森猎头值得合作吗:从资质、能力到案例逐一拆解
  • 遇到一个ORA-01017错误,解决方法
  • 主流 MP3 音频转换工具大全,免费软件适配音频剪辑日常使用 - 软件工具教程方法
  • 魔兽争霸III终极优化指南:三分钟解决宽屏、卡顿、地图加载问题
  • 微信私域机器人开发:iPad协议API实战指南
  • 2026年济南跨专业中级经济师众智商学院人力资源工商管理报名费用怎么确认 - 众智商学院官方
  • Linux平台纯C++实现的HTTP长轮询聊天系统,含服务端与命令行客户端
  • 3分钟告别成就焦虑:Steam成就管理工具的实战指南
  • GanttProject终极指南:如何用免费开源工具高效规划项目?
  • 2026一览|武汉市8大叛逆男孩厌学心理辅导学校精选排名,正规靠谱不踩雷 - 辛云教育资讯
  • 考研数学积分题总丢分?掌握这3个对称区间和三角函数的‘秒杀’性质,计算速度翻倍
  • YaeAchievement:3分钟搞定原神成就数据导出,告别手动记录的烦恼
  • YimMenu:GTA5终极防护与增强菜单完全指南
  • Java 标准 JAXP(Java API for XML Processing),JDK 内置,无需额外引入第三方依赖
  • 嵌入式设备日志自动备份:用Dropbear+SCP免密传输,5分钟搞定脚本配置
  • 3大核心技术革新:MAA明日方舟助手如何实现全日常一键长草
  • netstat命令和ss命令详解
  • PythonVista:突破系统限制,为老旧Windows重新定义Python兼容性边界
  • 2026年高校学生财务入门类证书推荐
  • 开封市杞县2026有实力的叛逆孩子学校哪家好?口碑好的叛逆少年学校选购指南与真实对比 - 善良的阿良