: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_div2分频、o_clk_4_div4分频、o_clk_8_div8分频、o_clk_16_div16分频。异步复位i_rst高电平有效立即将所有寄存器清零。无毛刺寄存器输出所有分频信号均经过寄存器打拍输出稳定可靠。创新点“一计多用”的资源复用不再单独例化分频器而是直接抽取模 100 计数器的比特位实现 2~16 分频。这种方法节省了寄存器和组合逻辑资源。符号位显式处理在计数器自增时使用$signed将常量转为有符号数消除混合符号类型的综合警告提升代码可移植性本版代码未使用$signed但保留了有符号声明可根据需要添加。预留式模块框架顶层通过param / reg / wire / FSM / inst / combine_Logic / always等注释分区为后续扩展状态机或子模块留下清晰接口团队协作更高效。全覆盖条件写法always块用else if(1)保证条件树完整综合工具会自动优化冗余逻辑但代码阅读者可直观理解优先级。2. 模块代码与详细解析2.1 顶层模块topsmodule 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 endmodule2.2 代码解析1. 端口与寄存器o_cout10 位有符号计数器值直接由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为了验证计数器及分频功能编写如下 testbenchtimescale 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 1b1; i_rst 1b1; #100 i_rst 1b0; end always #5 i_clk ~i_clk; // 10ns 时钟周期 endmodule激励说明时钟周期 10 ns占空比 50%。复位初始高电平持续 100 ns覆盖前 10 个时钟周期确保可靠复位。观察信号计数器值o_cout和四路分频信号。4. 仿真结果与分析在 ModelSim 或 Vivado 中运行仿真可观察到以下波形文字描述0~100 ns复位期i_rst1o_cout0所有分频输出均为 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 ns2 倍时钟周期上升/下降沿与计数器 LSB 同步。o_clk4div周期为 40 nso_clk8div周期为 80 nso_clk16div周期为 160 ns。由于计数器的循环特性即使经过 99→0 的突变分频输出的连续性依然保持无异常脉冲。仿真截图建议实际发布时可插入波形图片展示复位释放瞬间的放大波形查看分频与计数器的时序关系。展示计数值从 98→99→0 时四个分频信号的电平变化。5. 总结与扩展总结tops模块通过一个简洁的模 100 计数器不仅输出带符号的计数值还免费获得了 2/4/8/16 分频信号。这种“一计多用”的思路有效降低了逻辑资源消耗同时寄存器输出消除了分频毛刺在低速接口、LED 闪烁控制、简单时序产生等场景中非常实用。扩展建议参数化模值引入parameter MAX 99并将判断条件改为ro_cout MAX便于修改计数上限。分频级数可配置通过参数控制抽取的比特位宽度实现更多分频级数。加入使能信号添加计数使能端在需要时才递增实现可控分频。消除非 2 次幂模值对分频占空比的影响若要求严格 50% 占空比可将计数器改为模 128 (2^7) 或直接使用独立的分频计数器。希望这篇博客能帮助你快速理解 Verilog 中“计数器分频”的复用设计。如果你有更巧妙的分频实现方式欢迎在评论区留言交流