实现24小时制数字时钟,显示时:分:秒,支持时间设置。
数字时钟结构:
50MHz → 分频器 → 1Hz
│
┌─────▼─────┐ carry ┌─────▼─────┐ carry ┌─────▼─────┐
│ 秒计数器 │───────→│ 分计数器 │───────→│ 时计数器 │
│ 00-59 │ │ 00-59 │ │ 00-23 │
└───────────┘ └───────────┘ └───────────┘
│ │ │
sec[5:0] min[5:0] hour[4:0]// Digital Clock - 24小时制数字时钟
// 时:分:秒 级联计数器 + 时钟分频
module digital_clock(
input wire clk, // 50MHz
input wire rst,
input wire set_en, // 设置使能
input wire [4:0] set_hour, // 设置小时
input wire [5:0] set_min, // 设置分钟
output reg [4:0] hour, // 当前小时
output reg [5:0] minute, // 当前分钟
output reg [5:0] second, // 当前秒
output wire sec_pulse // 1秒脉冲
);
localparam DIV_1HZ = 26'd50_000_000;
reg [25:0] clk_div;
wire sec_carry, min_carry;
assign sec_pulse = (clk_div == DIV_1HZ - 26'd1);
// Clock divider: 50MHz -> 1Hz
always @(posedge clk or posedge rst) begin
if (rst) begin
clk_div <= 26'd0;
end else begin
if (clk_div >= DIV_1HZ - 26'd1)
clk_div <= 26'd0;
else
clk_div <= clk_div + 26'd1;
end
end
// Second counter: 0-59
always @(posedge clk or posedge rst) begin
if (rst) begin
second <= 6'd0;
end else if (set_en) begin
second <= 6'd0;
end else if (sec_pulse) begin
if (second == 6'd59)
second <= 6'd0;
else
second <= second + 6'd1;
end
end
assign sec_carry = sec_pulse && (second == 6'd59);
// Minute counter: 0-59
always @(posedge clk or posedge rst) begin
if (rst) begin
minute <= 6'd0;
end else if (set_en) begin
minute <= set_min;
end else if (sec_carry) begin
if (minute == 6'd59)
minute <= 6'd0;
else
minute <= minute + 6'd1;
end
end
assign min_carry = sec_carry && (minute == 6'd59);
// Hour counter: 0-23
always @(posedge clk or posedge rst) begin
if (rst) begin
hour <= 6'd0;
end else if (set_en) begin
hour <= set_hour;
end else if (min_carry) begin
if (hour == 5'd23)
hour <= 5'd0;
else
hour <= hour + 5'd1;
end
end
endmodule测试:复位后从00:00:00开始,秒从0计到59→分+1,分从0计到59→时+1,时从0计到23→归零。验证23:59:59→00:00:00。设置功能:set_en=1时正确加载新时间。
本实验所有Verilog代码已通过Verilator编译验证,功能行为正确。测试用例覆盖核心功能路径,确保设计满足规格要求。
数字时钟是RTC(实时时钟)芯片的基础。PC中的RTC芯片使用32.768kHz晶振,15位分频得到1Hz。智能手表在此基础上增加了闹钟、计时器、日历等功能。
尝试修改代码中的关键参数,观察仿真结果变化:
💡 Verilator会在位宽不匹配时给出Warning,这是学习的好机会
在现有基础上增加新功能:
🔧 增量开发:每次只改一个地方,验证通过后再改下一个
| 语法 | 说明 | 示例 |
|---|---|---|
reg [7:0] | 8位寄存器 | reg [7:0] data; |
wire | 组合逻辑连线 | wire valid = cnt > 5; |
always @(posedge clk) | 时序逻辑 | 上升沿触发 |
always @(*) | 组合逻辑 | 敏感列表自动推导 |
localparam | 局部常量 | localparam DIV = 50000000; |
case | 多分支选择 | 注意default分支 |
$display | 仿真打印 | 不可综合,仅仿真用 |
本设计在典型FPGA上的资源占用估算:LUT约20-120个,FF约30-100个,无BRAM/DSP依赖(特殊模块除外)。时钟频率可达50-100MHz+。Verilator仿真速度约5-10M周期/秒。