计数器的最后一题。
题干:
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.
大意:设计一个钟表,可以显示时分秒以及上下午,当复位信号为高位时(同步复位,题目没有直接说明,但是从题目给出的参考图可以大概判断出来),将时间重置为12:00:00,PM=0(即AM)。
思路:
拿到题目的时候想直接用一个always来解决,但是写下来发现逻辑很混乱,于是参考了别人的思路,把时分秒和上下午的判断分为4个部分来写。
由于每个部分的判断很类似,因此整个代码写起来比较流畅。
附上代码:
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
//将时分秒以及PM分为四个部分
//秒
always@(posedge clk) begin
if(reset)//复位,将秒置0
ss <=0;
else if(ena) begin //若使能为高电平,则开始计数
if(ss==8'h59)//判断是否进位
ss<=0;
else begin
if(ss[3:0]<4'h9)
ss[3:0] <= ss[3:0]+1;
else begin
ss[7:4] <= ss[7:4]+1;
ss[3:0] <= 0;
end
end
end
end
//分
always@(posedge clk) begin
if(reset)//复位,将分置0
mm <=0;
else if(ena) begin
if(ss==8'h59)
if(mm==8'h59)//59分且59秒时,进位
mm<=0;
else begin
if(mm[3:0]<4'h9)
mm[3:0] <= mm[3:0]+1;
else begin
mm[7:4] <= mm[7:4]+1;
mm[3:0] <=0;
end
end
end
end
//时
always@(posedge clk) begin
if(reset)//复位,将时置12
hh<=8'h12;
else if(ena) begin
if(ss==8'h59&&mm==8'h59)
if(hh==8'h12)
hh<=1;
else begin
if(hh[3:0]<4'h9)
hh[3:0] <= hh[3:0]+1;
else begin
hh[7:4] <=1;
hh[3:0] <=0;
end
end
end
end
//PM
always@(posedge clk) begin
if(reset) pm<=0;
else if(hh==8'h11&&mm==8'h59&&ss==8'h59)//只有在11点59分59秒到12点0分0秒时昼夜切换,PM取反
pm=~pm;
end
endmodule
代码整体思路:
时分秒三个部分的区别在于,秒可以认为是独立工作的一个60进制计数器,根据题目给的条件,可以将一个8bits的数ss分为ss[7:4]和ss[3:0]两个部分,分别表示秒钟的十位数与个位数。因此在条件判断中只需要判断ss==8'h59,即是否进位,若不需要进位,则判断个位是否为ss[3:0]==4'h9,是否向十位进位。
一开始我在这个部分犯了个低级错误,BCD计数器本质是16进制的(4bits),而十进制是在设计时规定的,最先我进行ss[7:0]<h'59判断后,直接对整个ss进行+1运算,忽略了这个问题。
秒钟的计数部分设计完成后,分钟可以以此类推,不同的是,在考虑分钟是否进位时,不仅要判断分钟mm==8‘h59,还需要判断秒钟ss==8'h59,在ena==1时完成进位,将两者置0。
时钟与分钟类似,当秒钟与分钟满足条件时,时钟为hh==8'h12时进位,注意进位后hh<=1(复位时同理,置为12),本题的时钟不存在0时这个说法。、
上下午的判断,只需要考虑11点59分59秒时,AM与PM相互转化即可,即pm=~pm。
总结:
学习Verilog将近一周了,这题对于初学者来说难度还算中等,虽然整体代码较长,但是时分秒三个部分的设计较为雷同,可以依次类推得到。
计数器这部分题目里,最后几题的套路都一样。参考时分秒的进位方式,时需要同时判断分与秒,分需要同时判断秒,这与Countbcd和Exams/ece241 2014 q7b的解题思路如出一辙。