前言
本文主要介绍我在解决12小时计时器问题时的思路,代码以及总结,用于自己复习记录,希望也能帮助到其他人。
一.题目
HDL bit -12 hour clock题目地址
翻译:创建一组适合用作 12 小时制的计数器。计数器由一个快速运行的 clk 计时,每当时钟增加(即每秒一次)时,ena 就会有一个脉冲。
reset 将时钟重置为凌晨 12:00。pm 为 0 表示 AM,1 表示 PM。 hh、mm 和 ss 是两个 BCD(二进制编码十进制)数字,分别表示小时(01-12)、分钟 (00-59) 和秒(00-59)。
重置的优先级高于启用,即使未启用也可能发生。时序图显示了从上午 11:59:59 到下午 12:00:00 的翻转行为以及同步复位和启用行为。
二.方法1
1.完整代码:
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
reg [3:0] s0; //秒针的个位
reg [3:0] s1; //秒针的十位
//秒计数
always @(posedge clk) begin
if(reset) begin
s0<=4'h0;
end
else if(ena) begin
if (s0==4'h9) begin
s0<=4'h0;
end
else begin
s0<=s0+1'b1;
end
end
end
always @(posedge clk) begin
if(reset) begin
s1<=4'h0 ;
end
else if (ena&&s0==4'h9) begin
if (s1==4'h5) begin
s1<=4'h0;
end
else begin
s1<=s1+1'b1;
end
end
end
//分计数
reg [3:0] m0; //分针的个位
reg [3:0] m1; //分针的十位
always @(posedge clk) begin
if(reset) begin
m0<=4'd0;
end
else if(ena&&s0==4'h9&&s1==4'h5) begin//当秒计时到59时,就需要考虑分计时
if(m0==4'h9) begin //此时为 x9分59秒 此时显然m0需要置零
m0<=4'h0;
end
else begin
m0<=m0+1'b1 ; //当m0未满9时,继续计数
end
end
end
always @(posedge clk) begin
if(reset) begin
m1<=4'h0;
end
else if(ena&&s0==4'd9&&s1==4'd5&&m0==4'd9) begin
if(m1==4'h5) begin
m1<=4'h0;
end
else begin
m1<=m1+1'b1 ;
end
end
end
//时计数
reg[3:0]h0; //时的个位
reg[3:0]h1; //时的十位 只能取0,1;
always @(posedge clk) begin
if(reset) begin
h0<= 4'd2;
end
else if(ena&&s0==4'h9&&s1==4'h5&&m0==4'h9&&m1==4'h5&h0==4'h2&&h1==4'h1) begin
h0<=4'h1; //12:59:59 下一时刻为01:00:00
end
else if(ena&&s0==4'h9&&s1==4'h5&&m0==4'h9&&m1==4'h5) begin //此时为xx:59:59
if(h0==4'h9) begin
h0<=4'h0;//满9置零
end
else begin
h0<=h0+1'b1; //当h0未满9时,继续计数
end
end
end
always @(posedge clk) begin
if(reset) begin
h1<=4'h1;
end
else if(ena==1'b1&&s0==4'h9&&s1==4'h5&&m0==4'h9&&m1==4'h5&h0==4'h2&&h1==4'h1) begin //此时为12:59:59
h1<=4'h0;//01:00:00
end
else if(ena==1'b1&&s0==4'h9&&s1==4'h5&&m0==4'h9&&m1==4'h5&h0==4'h9) begin //x9:59:59 当h0未满9时h1不会改变
h1<=h1+1'b1;
end
else h1<=h1;
end
reg r_pm;
//am or pm
always @(posedge clk) begin
if (reset) r_pm<=1'b0;
else if (ena&&s0==4'h9&&s1==4'h5&&m0==4'h9&&m1==4'h5&&h0==4'h1&&h1==4'h1) begin
r_pm<=~r_pm; //pm每十二个小时翻转一次,即满足11:59:59下一状态pm翻转
end
end
//赋值
assign hh={h1,h0};
assign mm={m1,m0};
assign ss={s1,s0};
assign pm=r_pm;
endmodule
2.详解介绍
由于分秒简单、两者类似且都有注释,故取稍微复杂的时钟的第2个always块进行介绍,按原理逻辑上推即可。
always @(posedge clk) begin
if(reset) begin
h1<=4'h1;
end
else if(ena==1'b1&&s0==4'h9&&s1==4'h5&&m0==4'h9&&m1==4'h5&h0==4'h2&&h1==4'h1) begin //此时为12:59:59
h1<=4'h0;//01:00:00
end
else if(ena==1'b1&&s0==4'h9&&s1==4'h5&&m0==4'h9&&m1==4'h5&h0==4'h9) begin //x9:59:59 当h0未满9时h1不会改变
h1<=h1+1'b1;
end
else h1<=h1;
end
hh的十位只能取0,1。
if 语句:表示reset为1时,进行复位操作将时钟的十位复位为1,题目要求时钟重置为凌晨12:00:00。
第一个else if语句:当时间为12:59:59,下个时间需要跳到01:00:00,则十位置0。
第二个else if语句:当时间为x9:59:59,下一时刻十位需要发生改变,而其他时间不满足这个时间段时,h1不变。
二.方法2
此种方法学习于此
1.完整代码:
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
wire [6:1] enable;
wire [7:0] hh_r;
assign enable[1] = ena && (ss[3:0]==4'h9);
assign enable[2] = enable[1] && (ss[7:4]==4'h5);
assign enable[3] = enable[2] && (mm[3:0]==4'h9);
assign enable[4] = enable[3] && (mm[7:4]==4'h5);
assign enable[5] = enable[4] && (hh_r[3:0]==4'hb); //b=11
assign enable[6] = enable[5] && (hh_r[7:4]==4'h1);
//模块例化
BCD_count #(.START(4'h0),.END_r(4'h9)) ss9 (clk, reset, ena, ss[3:0]);
BCD_count #(.START(4'h0),.END_r(4'h5)) ss5 (clk, reset, enable[1], ss[7:4]);
BCD_count #(.START(4'h0),.END_r(4'h9)) mm9 (clk, reset, enable[2], mm[3:0]);
BCD_count #(.START(4'h0),.END_r(4'h5)) mm5 (clk, reset, enable[3], mm[7:4]);
BCD_count #(.START(4'h0),.END_r(4'hb)) hhb (clk, reset, enable[4], hh_r[3:0]);
BCD_count #(.START(4'h0),.END_r(4'h1)) hh1 (clk, reset, enable[5], hh_r[7:4]);
assign pm=(hh_r[7:4]==4'h1);
assign hh=(hh_r[3:0]==4'h0)?8'h12:((hh_r[3:0]>4'h9)?{4'h1,hh_r[3:0]-4'ha}:{4'h0,hh_r[3:0]});// a=10
endmodule
//BCD计数器模块
module BCD_count(
input clk,
input reset,
input ena,
output reg[3:0] q
);
parameter START=4'h0,END_r=4'h9;
always @(posedge clk) begin
if(reset) q<=START;
else if(!reset&&ena) q<=(q==END_r)?START:q+4'h1;
else if(!reset&&!ena) q<=q;
end
endmodule
2.介绍
这种方法是通过编写的一个BCD计数器模块,来对其进行例化,推荐采用这种方法,看起来更清晰。
声明的中间变量,[6:1]enable其中6个元素代表秒分时的进位信号,若为1,即重置对应的时间计数。
paramter参数可自行搜索学习,parameter在模块中声明后,后续编译时还可以被重新声明的值所覆盖。重新声明格式如下代码举例:文章来源:https://www.toymoban.com/news/detail-827894.html
BCD_count #(.START(4'h0),.END_r(4'h9)) ss9 (clk, reset, ena, ss[3:0]);
详情参考下面学习:
paramter参数详解介绍文章来源地址https://www.toymoban.com/news/detail-827894.html
到了这里,关于verilog1 HDLbits:12 hour clock(12小时计时器)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!