为何我的8位计数器卡在0或255?Verilog代码故障排查
Cyclone 4 FPGA上下计数器异常问题排查
我在Cyclone 4 FPGA上练习Verilog代码开发,原本的8位计数器在板载50MHz时钟下运行速度过快,LED变化无法肉眼观测,于是编写了如下分频模块:
module enableCounter( input clock_5, input reset, output reg enable_out); reg [3:0] counter; always @(posedge clock_5) begin if (reset) begin counter <= 4'b0000; end else begin counter <= counter + 1; if (counter == 4'b0000) enable_out <= 1; else enable_out <= 0; end end endmodule
理论上该模块可让enable_out仅在clock_5的1/16周期内为高电平。之后我编写了上下计数器模块:
module updown_counter( input up_down, input clk, input enable, input reset, output reg [7:0] count_out); always @ (posedge clk) begin if (up_down == 0) begin // 向上计数 if (reset) count_out <= 8'b0000_0000; else if (enable && count_out == 8'b1111_1111) count_out <= 8'b0000_0000; else if (enable && count_out != 8'b1111_1111) count_out <= count_out + 8'b0000_0001; else count_out <= count_out; end else if (up_down == 1) begin // 向下计数 if (reset) count_out <= 8'b1111_1111; else if (enable && count_out == 8'b0000_0000) count_out <= 8'b1111_1111; else if (enable && count_out != 8'b0000_0000) count_out <= count_out - 8'b0000_0001; else count_out <= count_out; end end endmodule
代码无编译错误,但连接count_out的8个LED始终全灭,按下复位按钮时全亮;切换up_down方向后现象相反,推测代码存在bug。
补充说明:在Quartus中通过BDF文件连接板载时钟到PLL模块,再接入上述两个模块,连接示意图如下:
问题分析与修复方案
1. 核心问题:分频系数过小
当前16分频后,计数器更新频率为50MHz/16≈3.125MHz,远高于人眼可分辨的20Hz以下阈值,LED高速闪烁会被肉眼识别为常亮/常灭,导致看不到计数变化。
2. 代码逻辑优化与修复
(1)增大分频系数
将分频模块的计数器位数提升至24位,使enable_out频率降至约2.98Hz,肉眼可清晰观测LED变化:
module enableCounter( input clock_5, input reset, output reg enable_out); reg [23:0] counter; // 改为24位计数器,实现约50MHz/2^24≈2.98Hz的分频 always @(posedge clock_5) begin if (reset) begin counter <= 24'd0; enable_out <= 1'b0; end else begin counter <= counter + 1'b1; // 取计数器最高位作为使能信号,获得50%占空比的低频信号 enable_out <= counter[23]; end end endmodule
(2)简化上下计数器逻辑
去除冗余代码,避免逻辑分支混乱:
module updown_counter( input up_down, input clk, input enable, input reset, output reg [7:0] count_out); always @ (posedge clk) begin if (reset) begin // 复位时根据计数方向设置初始值 count_out <= up_down ? 8'hFF : 8'h00; end else if (enable) begin if (!up_down) begin // 向上计数 count_out <= (count_out == 8'hFF) ? 8'h00 : count_out + 1'b1; end else begin // 向下计数 count_out <= (count_out == 8'h00) ? 8'hFF : count_out - 1'b1; end end // 未使能时保持原值,无需额外赋值 end endmodule
3. 硬件连接验证
- 确认PLL输出时钟已正确连接到两个模块的时钟引脚;
- 检查复位信号极性:若板载复位为低电平有效,需将代码中
if (reset)改为if (!reset); - 确认LED连接方式:共阳LED需低电平点亮,共阴LED需高电平点亮,根据实际情况调整代码或硬件接线。
内容的提问来源于stack exchange,提问作者johnny_1010
相关产品推荐
相关产品推荐

