目录
背景
这篇博客设计一个12小时的时钟,通过例化4bit BCD码计数器来设计,如果你给予的时钟周期是1s,则能够当做时钟来用哦。
原题复现
原题如下:
reset resets the clock to 12:00 AM. pm is 0 for AM and 1 for PM. hh, mm, and ss are two BCD (Binary-Coded Decimal) digits each for hours (01-12), minutes (00-59), and seconds (00-59). Reset has higher priority than enable, and can occur even when not enabled.
用计数器设计一个带am/pm的12小时时钟。该计数器通过一个CLK进行计时,用ena使能信号来驱动时钟的递增。
reset信号将时钟复位为12:00 AM。 信号pm为0代表AM,为1代表PM。hh、mm和ss由两个BCD计数器构成hours(01~12), minutes(00~59) , second(00~59)。Reset信号比enable信号有更高的优先级,即使没有enable信号也可以进行复位操作。
The following timing diagram shows the rollover behaviour from 11:59:59 AM to 12:00:00 PM and the synchronous reset and enable behaviour.
模块声明如下:
Module Declaration
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
审题
这个题目的几个要求:
- 能够进行12小时计数,那就要求有秒,分钟,小时;
- 使用BCD计数器来实现;
- 复位有效时,复位到12点;
- 要能够区分上下午,上午pm为0,下午pm为1;
- 复位比使能优先级更高;
- 由于是时钟,所以是从1点到12点;
我的设计
好了,这里为了解决这个大问题,我先设计一个秒和分钟的计数器,也就是能从0到59的模60BCD计数器:
module count60(
input clk,
input reset,
input en,
output reg [7:0] cnt_out
);
always@(posedge clk) begin
if(reset) cnt_out <= 0;
else if(en) begin
if(cnt_out == 8'h59) begin
cnt_out <= 0;
end
else if(cnt_out[3:0] == 9) begin
cnt_out[3:0] <= 0;
cnt_out[7:4] <= cnt_out[7:4] + 1;
end
else begin
cnt_out[3:0] <= cnt_out[3:0] + 1;
end
end
end
endmodule
在设计一个从1计数到12的模12 BCD计数器:
module count12 (
input clk, // Clock
input reset, // Asynchronous reset active high
input en,
output reg [7:0] cnt_out
);
always@(posedge clk) begin
if(reset) cnt_out <= 8'h12;
else if(en) begin
if(cnt_out == 8'h12) begin
cnt_out <= 1;
end
else if(cnt_out[3:0] == 9) begin
cnt_out[3:0] <= 0;
cnt_out[7:4] <= cnt_out[7:4] + 1;
end
else begin
cnt_out[3:0] <= cnt_out[3:0] + 1;
end
end
end
endmodule
最后,通过例化得到最终的12小时时钟:
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
count60 inst_second(
.clk(clk),
.reset(reset),
.en(ena),
.cnt_out(ss)
);
count60 inst_min(
.clk(clk),
.reset(reset),
.en(ena&(ss == 8'h59)),
.cnt_out(mm)
);
count12 inst_hour(
.clk(clk),
.reset(reset),
.en(ena&(ss == 8'h59)&(mm == 8'h59)),
.cnt_out(hh)
);
reg p;
always@(posedge clk) begin
if(reset) p <= 0;
else if(hh == 8'h11 && ss == 8'h59&& mm == 8'h59) p <= ~p;
else ;
end
assign pm = p;
endmodule
设计解释
上面代码的最后一部分用于产生pm指示上下午的信号:
reg p;
always@(posedge clk) begin
if(reset) p <= 0;
else if(hh == 8'h11 && ss == 8'h59&& mm == 8'h59) p <= ~p;
else ;
end
assign pm = p;
这样,设计就结束了。
通过例化模块的方式比在一个模块中写完整个设计要简洁,清晰,思路也更明朗了。
欢迎加入