
题目要求
- 构建一个带有AM/PM指示标志的12小时时钟,
clk输入为1 pulse/sec。 - 复位输入
reset将时钟复位至AM 12:00,优先级高于使能输入enable。 - PM指示标志
pm为0时表示AM,1表示PM。 - hh,mm,ss的数据表示方式为BCD码。
题目分析
首先,12小时制与24小时制的所表示的时间段有如下对应规则:
| 12HR | 24HR |
| 12:00AM – 11:59AM | 0:00 – 11:59 |
| 12:00PM – 11:59PM | 12:00 – 23:59 |
所以,其实咱们不用做这个对应,只需要傻傻计时以及维护pm指示标志即可。
由于时分秒的计时范围分别为1-12,0-59,因此可以设计两个BCD计时模块,分别维护1-12的计时和pm标志,以及0-59的计时。
写出两模块分别如下:
module cnt12
(
input clk,
input reset,
input ena,
output reg [7:0] counter,
output reg pm
);
// 初始为上午12时
initial pm = 1'b0;
initial counter = 8'h12;
always @(posedge clk) begin
// reset高优先级
if (reset) begin
counter <= 8'h12;
pm <= 1'b0;
end
else begin
if (ena) begin
if (counter == 8'h11) begin
// 该改变PM标志了,要不等8'h112做非阻塞赋值就会有一个执行周期的延迟
pm <= !pm;
counter <= counter + 8'h1;
end
else if (counter == 8'h12) begin
// 计时循环结束
counter <= 8'h1;
end
else if (counter == 8'h9) begin
// 这里十位最高为1,仅需if判断即可,不需要使用vector操作
counter <= 8'h10;
end
else begin
// 计数+1
counter <= counter + 8'h1;
end
end
end
end
endmodule
module cnt60
(
input clk,
input reset,
input ena,
output reg [7:0] counter
);
always @(posedge clk) begin
// reset高优先级
if (reset) begin
counter <= 8'h0;
end
else begin
if (ena) begin
if (counter == 8'h59) begin
// 计时循环结束
counter <= 8'h0;
end
else if (counter[3:0] == 4'd9) begin
// 这里进位使用vector操作更方便,不需要大量if判断
counter[7:4] <= counter[7:4] + 4'd1;
counter[3:0] <= 4'd0;
end
else begin
// 计数+1
counter[3:0] <= counter[3:0] + 4'd1;
end
end
end
end
endmodule
接下来,在顶层模块中例化两个计时模块:
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
wire ena_mm, ena_hh;
// 分钟进位:59秒+1
assign ena_mm = ena & (ss == 8'h59);
// 小时进位:59分59秒+1,使用ena_mm进行简化
assign ena_hh = ena_mm & (mm == 8'h59);
cnt60 u_cnt60_ss(clk, reset, ena, ss);
cnt60 u_cnt60_mm(clk, reset, ena_mm, mm);
cnt12 u_cnt12_hh(clk, reset, ena_hh, hh, pm);
endmodule
