本文主要是介绍【HDLBits 刷题 7】Circuits(3)Sequential Logic---Counters,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
写在前面
Counters
Count15
Count10
Countslow
Counter1-12
Counter1000
Countbcd
Count clock
总结
写在前面
本篇博客对 Circuits 部分的组合逻辑前两节做答案和部分解析,一些比较简单的题目就直接给出答案,有些难度再稍作讲解,每道题的答案不一定唯一,可以有多种解决方案,欢迎共同讨论。
Counters
Count15
生成一个4位二进制计数器,其计数范围为0到15(包括0和15),周期为16。复位输入是同步的,应将计数器复位为0。
module top_module (input clk,input reset, output [3:0] q
);always @(posedge clk) beginif (reset) beginq <= 'd0;endelse beginq <= q + 'd1;end
endendmodule
Count10
构建一个计数从 0 到 9(包括 0 和 9)的计数器,周期为 10。复位输入是同步的,应将计数器复位为0。
module top_module (input clk,input reset, output [3:0] q
);always @(posedge clk) beginif (reset) beginq <= 'd0;endelse if (q == 'd9) beginq <= 'd0; endelse beginq <= q + 'd1;end
end
endmodule
Count1to10
制作一个计数为 1 到 10(包括 1)的计数器。复位输入是同步的,应将计数器复位为1。
module top_module (input clk,input reset, output [3:0] q
);always @(posedge clk) beginif (reset) beginq <= 'd1;endelse if (q == 'd10) beginq <= 'd1; endelse beginq <= q + 'd1;end
end
endmodule
Countslow
构建一个计数从 0 到 9(包括 0 和 9)的计数器,周期为 10。复位输入是同步的,应将计数器复位为0。我们希望能够暂停计数器,而不是总是在每个时钟周期递增,因此 slowena 输入指示计数器何时应该递增。
module top_module (input clk,input slowena,input reset,output [3:0] q
);
always @(posedge clk) beginif (reset) beginq <= 'd0;endelse if (q == 'd9 && slowena) beginq <= 'd0; endelse if (q < 'd9 && slowena) beginq <= q + 'd1;end
endendmodule
Counter1-12
设计具有以下输入和输出的 1-12 计数器:
重置同步高电平有效复位,强制计数器达到1
.使设置高,使计数器运行
.时钟正边沿触发时钟输入
.问[3:0]计数器的输出
.c_enable、c_load c_d[3:0]控制信号进入提供的4位计数器,因此可以验证正确的操作。
module top_module (input clk,input reset,input enable,output [3:0] Q,output c_enable,output c_load,output [3:0] c_d
); assign c_enable = enable;assign c_load = reset | ((Q == 4'd12) && (enable == 1'b1));assign c_d = c_load ? 4'd1 : 4'd0;count4 the_counter (clk, c_enable, c_load, c_d , Q);endmodule
Counter1000
从 1000 Hz 时钟导出一个 1 Hz 信号,称为 OneHertz,可用于驱动一组小时/分/秒计数器的 Enable 信号,以创建数字挂钟。由于我们希望时钟每秒计数一次,因此必须每秒断言一个周期的OneHertz信号。使用模-10 (BCD) 计数器和尽可能少的其他门构建分频器。同时输出来自您使用的每个BCD计数器的使能信号(最快的计数器c_enable[0],最慢的计数器c_enable[2])。为您提供了以下 BCD 计数器。启用必须为高电平才能运行计数器。复位是同步的,设置为高电平以强制计数器归零。电路中的所有计数器必须直接使用相同的 1000 Hz 信号。
module top_module (input clk,input reset,output OneHertz,output [2:0] c_enable
);wire [3:0] a,b,c;
assign c_enable = {b=='d9 && a=='d9,a=='d9,1'b1};
assign OneHertz = a=='d9 && b=='d9 && c=='d9;bcdcount counter0 (clk, reset, c_enable[0], a);
bcdcount counter1 (clk, reset, c_enable[1], b);
bcdcount counter2 (clk, reset, c_enable[2], c);
endmodule
Countbcd
生成 4 位 BCD(二进制编码十进制)计数器。每个十进制数字使用4位编码:q[3:0]是1位数字,q[7:4]是十位数字,依此类推。对于数字 [3:1],还要输出一个使能信号,指示何时应递增上述三位数字中的每一位。
module top_module (input clk,input reset,output [3:1] ena,output [15:0] q
);
reg [3:0] one,ten,hundred,thousand;//one
always @(posedge clk) beginif (reset) beginone <= 'd0; endelse if (one == 'd9) beginone <= 'd0;endelse beginone <= one + 'd1; end
end//ten
always @(posedge clk) beginif (reset) beginten <= 'd0;endelse if (ten == 'd9 && one == 'd9) beginten <= 'd0;endelse if (ena[1]) beginten <= ten + 'd1;endelse beginten <= ten;end
end//hundred
always @(posedge clk) beginif (reset) beginhundred <= 'd0;endelse if (hundred == 'd9 && ten == 'd9 && one == 'd9) beginhundred <= 'd0;endelse if (ena[2]) beginhundred <= hundred + 'd1;endelse beginhundred <= hundred;end
end//thousand
always @(posedge clk) beginif (reset) beginthousand <= 'd0;endelse if (thousand =='d9 && hundred == 'd9 && ten == 'd9 && one == 'd9) beginthousand <= 'd0;endelse if (ena[3]) beginthousand <= thousand + 'd1;endelse beginthousand <= thousand;end
end//ena[1] ena[2] ena[3]
assign ena[1] = (one=='d9);
assign ena[2] = (ten=='d9 && one=='d9);
assign ena[3] = (hundred=='d9 && ten=='d9 && one=='d9);//q
assign q = {thousand, hundred, ten, one};endmodule
Count clock
创建一组适合用作 12 小时制的计数器(带有 am/pm 指示器)。计数器由快速运行的 clk 计时,只要您的时钟递增(即每秒一次),就会有一个脉冲。重置将时钟重置为 12:00 AM。pm 对于 AM为 0,对于 PM 为 1。hh、mm 和 ss 是两个 BCD(二进制编码十进制)数字,分别表示小时(01-12)、分钟 (00-59)和秒(00-59)。重置的优先级高于启用,即使未启用,也可能发生重置。以下时序图显示了从11:59:59 AM到12:00:00 PM的翻转行为以及同步重置和启用行为。
这里需要注意一点,就是小时、分钟、秒钟的个位十位都需要用十进制数表示,不能直接用十六进制表示,这是这道题的难点所在。
module top_module(input clk,input reset,input ena,output pm,output [7:0] hh,output [7:0] mm,output [7:0] ss
); reg pm_temp; //pm值寄存reg [3:0] ss_ones; //ss个位部分reg [3:0] ss_tens; //ss十位部分 reg [3:0] mm_ones; //mm个位部分 reg [3:0] mm_tens; //mm十位部分reg [3:0] hh_ones; //hh个位部分reg [3:0] hh_tens; //hh十位部分wire add_ss_ones; //ss个位计数开始信号wire end_ss_ones; //ss个位计数结束信号wire add_ss_tens; //ss十位计数开始信号wire end_ss_tens; //ss十位计数结束信号wire add_mm_ones; //mm个位计数开始信号wire end_mm_ones; //mm个位计数结束信号wire add_mm_tens; //mm十位计数开始信号wire end_mm_tens; //mm十位计数结束信号wire add_hh_ones; //hh个位计数开始信号wire end_hh_ones_0; //hh个位计数结束信号(十位为0)wire end_hh_ones_1; //hh个位计数结束信号(十位为1)wire add_hh_tens; //hh十位计数开始信号 wire end_hh_tens_0; //hh十位计数置0标志信号wire end_hh_tens_1; //hh十位计数置1标志信号wire pm_ding; //pm翻转标志信号assign add_ss_ones = ena;
assign end_ss_ones = add_ss_ones && (ss_ones == 4'd9);
always @(posedge clk)beginif(reset)beginss_ones <= 4'b0;endelse if(add_ss_ones)beginif(end_ss_ones)beginss_ones <= 4'b0;endelse beginss_ones <= ss_ones + 4'b1;endend
endassign add_ss_tens = end_ss_ones;
assign end_ss_tens = add_ss_tens && (ss_tens == 4'd5);
always @(posedge clk)beginif(reset)beginss_tens <= 4'b0;endelse if(add_ss_tens)beginif(end_ss_tens)beginss_tens <= 4'b0;endelse beginss_tens <= ss_tens + 4'b1;endend
endassign add_mm_ones = end_ss_tens;
assign end_mm_ones = add_mm_ones && (mm_ones == 4'd9);
always @(posedge clk)beginif(reset)beginmm_ones <= 4'b0;endelse if(add_mm_ones)beginif(end_mm_ones)beginmm_ones <= 4'b0;endelse beginmm_ones <= mm_ones + 4'b1;endend
endassign add_mm_tens = end_mm_ones;
assign end_mm_tens = add_mm_tens && (mm_tens == 4'd5);always @(posedge clk)beginif(reset)beginmm_tens <= 4'b0;endelse if(add_mm_tens)beginif(end_mm_tens)beginmm_tens <= 4'b0;endelse beginmm_tens <= mm_tens + 4'b1;endend
endassign add_hh_ones = end_mm_tens;
assign end_hh_ones_0 = add_hh_ones && (hh_ones == 4'd9);
assign end_hh_ones_1 = add_hh_ones && ((hh_ones == 4'd2) && (hh_tens == 4'd1));
always @(posedge clk)beginif(reset)beginhh_ones <= 4'd2;endelse if(add_hh_ones)beginif(end_hh_ones_0)beginhh_ones <= 4'b0;endelse if(end_hh_ones_1)beginhh_ones <= 4'b1;endelse beginhh_ones <= hh_ones+4'b1;endend
endassign add_hh_tens = end_mm_tens;
assign end_hh_tens_0 = add_hh_tens && end_hh_ones_1;
assign end_hh_tens_1 = add_hh_tens && end_hh_ones_0;
always @(posedge clk)beginif(reset)beginhh_tens <= 4'b1;endelse if(add_hh_tens)beginif(end_hh_tens_0)beginhh_tens <= 4'b0;endelse if(end_hh_tens_1)beginhh_tens <= hh_tens + 4'b1;endend
endalways@(posedge clk)beginif(reset)beginpm_temp <= 1'b0;endelse if(pm_ding)beginpm_temp <= ~pm_temp;end
endassign pm_ding = hh_tens == 4'd1 && hh_ones == 4'd1 && end_mm_tens;assign ss = {ss_tens, ss_ones};
assign mm = {mm_tens, mm_ones};
assign hh = {hh_tens, hh_ones};
assign pm = pm_temp;endmodule
总结
这部分主要学习计数器的使用,这个在实际设计中用的非常多,尤其是在处理数据的时候,计数器设计不难,但是需要注意计数值到边缘时的处理,是否有延时等情况。
这篇关于【HDLBits 刷题 7】Circuits(3)Sequential Logic---Counters的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!