一、模塊設計
如若不清楚怎么模塊化,請看https://blog.csdn.net/szyugly/article/details/146379170?spm=1001.2014.3001.5501
1.1頂層模塊
module top_counter(input wire CLOCK_50, // 50MHz時鐘input wire KEY0, // 暫停/繼續按鍵output wire [6:0] HEX3, HEX2, HEX1, HEX0, // 4位七段數碼管output wire [3:0] DIGIT_EN // 數碼管位選
);wire clk_1hz; // 1Hz時鐘
wire clk_scan; // 掃描時鐘(1kHz)
wire pause_pulse; // 消抖后的暫停信號// 模塊實例化
clk_div u_clk_div(.clk_50m(CLOCK_50),.clk_1hz(clk_1hz),.clk_1k(clk_scan)
);debounce u_debounce(.clk(CLOCK_50),.key_in(KEY0),.key_out(pause_pulse)
);time_counter u_time_counter(.clk(clk_1hz),.pause(pause_pulse),.min_ten(min_ten),.min_unit(min_unit),.sec_ten(sec_ten),.sec_unit(sec_unit)
);display u_display(.clk(clk_scan),.min_ten(min_ten),.min_unit(min_unit),.sec_ten(sec_ten),.sec_unit(sec_unit),.seg_data({HEX3, HEX2, HEX1, HEX0}),.digit_en(DIGIT_EN)
);endmodule
1.2計數器模塊
module time_counter(input wire clk, // 1Hz時鐘input wire pause, // 暫停信號output reg [3:0] min_ten, // 分鐘十位output reg [3:0] min_unit, // 分鐘個位output reg [3:0] sec_ten, // 秒鐘十位output reg [3:0] sec_unit // 秒鐘個位
);reg pause_state; // 暫停狀態寄存器always @(posedge clk) beginif(pause) pause_state <= ~pause_state; // 切換暫停狀態
endalways @(posedge clk) beginif(!pause_state) begin // 非暫停狀態// 秒個位計數if(sec_unit == 4'd9) beginsec_unit <= 0;// 秒十位計數if(sec_ten == 4'd5) beginsec_ten <= 0;// 分鐘個位計數if(min_unit == 4'd9) beginmin_unit <= 0;// 分鐘十位計數if(min_ten == 4'd5) beginmin_ten <= 0;end else beginmin_ten <= min_ten + 1;endend else beginmin_unit <= min_unit + 1;endend else beginsec_ten <= sec_ten + 1;endend else beginsec_unit <= sec_unit + 1;endend
endendmodule
1.3按鍵消抖模塊
module debounce(input wire clk, // 50MHz時鐘input wire key_in, // 原始按鍵輸入output reg key_out // 消抖后輸出
);reg [19:0] counter; // 20ms計數器 (50MHz * 0.02s = 1,000,000)
reg key_reg;always @(posedge clk) beginkey_reg <= key_in; // 同步輸入if(key_reg != key_out) begin // 狀態變化counter <= 20'd0;end else if(counter < 20'd1_000_000) begincounter <= counter + 1;end else beginkey_out <= key_reg; // 穩定后更新輸出end
endendmodule
1.4顯示驅動模塊
module display(input wire clk, // 掃描時鐘(1kHz)input wire [3:0] min_ten,input wire [3:0] min_unit,input wire [3:0] sec_ten,input wire [3:0] sec_unit,output reg [6:0] seg_data, // 段選信號output reg [3:0] digit_en // 位選使能
);reg [1:0] scan_cnt; // 掃描計數器
reg [3:0] data_temp; // 當前顯示數據// 七段譯碼表(共陽極)
parameter [6:0] SEG_BCD [0:9] = {7'b1000000, // 07'b1111001, // 17'b0100100, // 27'b0110000, // 37'b0011001, // 47'b0010010, // 57'b0000010, // 67'b1111000, // 77'b0000000, // 87'b0010000 // 9
};always @(posedge clk) beginscan_cnt <= scan_cnt + 1;case(scan_cnt)2'b00: begindigit_en <= 4'b1110; // 最低位data_temp <= sec_unit;end2'b01: begindigit_en <= 4'b1101;data_temp <= sec_ten;end2'b10: begindigit_en <= 4'b1011;data_temp <= min_unit;end2'b11: begindigit_en <= 4'b0111; // 最高位data_temp <= min_ten;endendcaseseg_data <= SEG_BCD[data_temp]; // 查表輸出
endendmodule
1.5分頻模塊
module clk_div(input wire clk_50m, // 50MHz輸入output reg clk_1hz, // 1Hz輸出output reg clk_1k // 1kHz掃描時鐘
);// 1Hz分頻計數器 (50,000,000分頻)
reg [25:0] cnt_1hz;
always @(posedge clk_50m) beginif(cnt_1hz == 26'd49_999_999) begincnt_1hz <= 0;clk_1hz <= ~clk_1hz;end else begincnt_1hz <= cnt_1hz + 1;end
end// 1kHz分頻計數器 (50,000分頻)
reg [15:0] cnt_1k;
always @(posedge clk_50m) beginif(cnt_1k == 16'd49_999) begincnt_1k <= 0;clk_1k <= ~clk_1k;end else begincnt_1k <= cnt_1k + 1;end
endendmodule
二、效果展示
計數器