Create a set of counters suitable for use as a 12-hour clock (with am/pm indicator). Your counters are clocked by a fast-running clk, with a pulse on ena whenever your clock should increment (i.e., once per second).
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.
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.
参考了知乎一个大佬的代码(侵删):
https://zhuanlan.zhihu.com/p/128621408
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
//例化计数器表示秒
wire ssl_2_ssh,ssh_2_mml; //地位向高位进位
cnt cnt_ssl(.clk(clk),.reset(reset),.count_start(ena),.count_end(4'd9),
.end_cnt(ssl_2_ssh),.count(ss[3:0]));
cnt cnt_ssh(.clk(clk),.reset(reset),.count_start(ssl_2_ssh),.count_end(4'd5),
.end_cnt(ssh_2_mml),.count(ss[7:4]));
//例化计数器表示分钟
wire mml_2_mmh, mmh_2_hh;
cnt cnt_mml(.clk(clk),.reset(reset),.count_start(ssh_2_mml),
.count_end(4'd9),.end_cnt(mml_2_mmh),.count(mm[3:0]));
cnt cnt_mmh(.clk(clk),.reset(reset),.count_start(mml_2_mmh),
.count_end(4'd5),.end_cnt(mmh_2_hh),.count(mm[7:4]));
//小时计数
reg a_2_p;
always @(posedge clk)begin
if(reset)begin
a_2_p <= 0;
hh <= 8'h12; // 初始条件 12:00:00 AM
end
else if(mmh_2_hh)begin
if(hh == 8'h12)
hh <= 8'h01;
else begin
hh <= hh + 1'b1;
if(hh == 8'h9)
hh <= 8'h10;
if(hh == 8'h11)
a_2_p <= ~ a_2_p;
end
end
end
assign pm = a_2_p;
endmodule
//计数器子模块,可以设置开始和结束条件
module cnt(
input clk,
input reset,
input count_start, //开始计数输入
input [3:0] count_end, //计数到多少停止计数
output end_cnt, //一次计数完成标志
output [3:0] count);
wire add_cnt;
always @(posedge clk)begin
if(reset)begin
count <= 4'd0;
end
else if(add_cnt)begin
if(end_cnt)
count <= 4'd0;
else
count <= count + 1'b1;
end
end
assign add_cnt = count_start; //计数开始条件,当满足了开始计数
assign end_cnt = add_cnt && (count == count_end); //计数结束产生一个标志
endmodule
首先我觉得这个计数器写的很不错,收藏一下以后可以直接用。
这里我在看代码的时候有两个地方不理解:
①为什么计数器模块的结束时间为5,不是6。如果是5的话,难道50~59就不记了吗?
②在时模块里,有一个部分就更看不懂了:
if(hh == 8'h9)
hh <= 8'h10;
为啥在9的时候就直接跳到10了?第九个小时不记录了吗?很迷。
针对第一个问题,我把结束标识设为了4’d6,针对把第二个问题把判断条件改为了 8’ha,都不正确。最后我想明白了,这是非阻塞赋值语句的原因,即变量的是不会因为赋值而立马改变的,而是所有语句执行完了后,一起改变。所以第一个问题,就应设置为5,模块会以此记录50~59,在所有的语句执行完了后,发现十位是5,然后重置计数器。如果设置为6的话,那模块就会记60-69,肯定就错了。
针对第二个问题,也是一样的。hh到了8’h9,模块依次记录第九个小时,然后计数执行完了后,所有变量的值一起改变,hh变到了8‘h10。
这样一跑所有的程序就通了,记录一下,如果有写错的地方欢迎纠正。