基于分频时钟的Verilog 0-9计数FPGA实现问题咨询
Hey there! Let's get your Cyclone V 0-9 counter up and running smoothly. I’ll walk you through fixing the clock division, refining the counter logic, and handling those finicky mechanical buttons—since those are usually the culprits behind weird behavior.
First: Fixing the 50MHz to 1Hz Conversion
Instead of generating a new 1Hz clock (which can cause timing issues in FPGAs), we’ll create a 1Hz enable signal synchronized to the 50MHz core clock. This is way more reliable. Here’s how it works:
- We need to count 50,000,000 cycles of 50MHz to make 1 second. So we’ll use a 26-bit counter (since 2^26 is ~67 million, which covers 50 million).
- When the counter hits 49,999,999, we set the enable signal high for one cycle, then reset the counter to start over.
Next: Handling Button Debouncing
Mechanical buttons like KEY0 and KEY1 bounce when pressed/released—this means the signal flickers for 10-20ms before stabilizing. If we don’t fix this, your reset or run control might trigger multiple times accidentally. We’ll use:
- Two sync registers to avoid metastability (since button inputs are asynchronous to the 50MHz clock).
- A counter to wait for the button signal to stay stable for 20ms (1,000,000 cycles at 50MHz) before trusting it.
The Main Counter Logic
We’ll build a synchronous counter (all operations tied to the 50MHz clock edge) with these rules:
- Reset Priority: If KEY0 is pressed, the counter immediately resets to 0, no matter what else is happening.
- Run Control: Only when KEY1 is pressed and the 1Hz enable signal is active does the counter increment.
- Loop Back: When the counter hits 9, it wraps around to 0 instead of overflowing.
Full Verilog Example
module counter_0_9( input clk_50mhz, input key0, // Assuming active-low (common on Cyclone V boards) input key1, // Active-low run enable output reg [3:0] cnt // BCD output (0-9) ); // 50MHz to 1Hz enable signal reg [25:0] div_counter; reg en_1hz; always @(posedge clk_50mhz) begin if (div_counter == 49999999) begin div_counter <= 0; en_1hz <= 1'b1; end else begin div_counter <= div_counter + 1'b1; en_1hz <= 1'b0; end end // Debounce KEY0 (reset) reg [1:0] key0_sync; reg [19:0] key0_debounce_cnt; reg key0_stable; always @(posedge clk_50mhz) begin key0_sync <= {key0_sync[0], key0}; if (key0_sync[1] != key0_sync[0]) begin key0_debounce_cnt <= 0; end else if (key0_debounce_cnt != 1000000) begin // 20ms wait key0_debounce_cnt <= key0_debounce_cnt + 1'b1; end else begin key0_stable <= key0_sync[1]; end end // Debounce KEY1 (run) reg [1:0] key1_sync; reg [19:0] key1_debounce_cnt; reg key1_stable; always @(posedge clk_50mhz) begin key1_sync <= {key1_sync[0], key1}; if (key1_sync[1] != key1_sync[0]) begin key1_debounce_cnt <= 0; end else if (key1_debounce_cnt != 1000000) begin key1_debounce_cnt <= key1_debounce_cnt + 1'b1; end else begin key1_stable <= key1_sync[1]; end end // Main counter logic always @(posedge clk_50mhz) begin // Reset takes top priority if (!key0_stable) begin cnt <= 4'd0; end else begin // Increment only if run is enabled and 1Hz tick hits if (!key1_stable && en_1hz) begin cnt <= (cnt == 4'd9) ? 4'd0 : cnt + 4'd1; end // Else, hold current value end end // Optional: Add BCD-to-7-segment decoder if using a display // reg [6:0] seg_out; // always @(*) begin // case(cnt) // 4'd0: seg_out = 7'b1000000; // Adjust based on common anode/cathode // 4'd1: seg_out = 7'b1111001; // 4'd2: seg_out = 7'b0100100; // 4'd3: seg_out = 7'b0110000; // 4'd4: seg_out = 7'b0011001; // 4'd5: seg_out = 7'b0010010; // 4'd6: seg_out = 7'b0000010; // 4'd7: seg_out = 7'b1111000; // 4'd8: seg_out = 7'b0000000; // 4'd9: seg_out = 7'b0010000; // default: seg_out = 7'b1111111; // endcase // end endmodule
Debugging Tips
- Test the Clock Divider: Use Intel’s SignalTap II to capture the
en_1hzsignal. It should pulse high once every second. - Verify Button Debouncing: Check the
key0_stableandkey1_stablesignals—they should only change after the button has been pressed/released for 20ms. - Validate Counter Behavior: Make sure the counter resets to 0 when KEY0 is pressed, increments once per second when KEY1 is held, and loops back to 0 after 9.
内容的提问来源于stack exchange,提问作者user8588899

