目录
写在前面
Counters
Count15
Count10
Countslow
Counter1-12
Counter1000
Countbcd
Count clock
总结
本篇博客对 Circuits 部分的组合逻辑前两节做答案和部分解析,一些比较简单的题目就直接给出答案,有些难度再稍作讲解,每道题的答案不一定唯一,可以有多种解决方案,欢迎共同讨论。
生成一个4位二进制计数器,其计数范围为0到15(包括0和15),周期为16。复位输入是同步的,应将计数器复位为0。
module top_module (
input clk,
input reset,
output [3:0] q
);
always @(posedge clk) begin
if (reset) begin
q <= 'd0;
end
else begin
q <= q + 'd1;
end
end
endmodule
构建一个计数从 0 到 9(包括 0 和 9)的计数器,周期为 10。复位输入是同步的,应将计数器复位为0。
module top_module (
input clk,
input reset,
output [3:0] q
);
always @(posedge clk) begin
if (reset) begin
q <= 'd0;
end
else if (q == 'd9) begin
q <= 'd0;
end
else begin
q <= q + 'd1;
end
end
endmodule
Count1to10
制作一个计数为 1 到 10(包括 1)的计数器。复位输入是同步的,应将计数器复位为1。
module top_module (
input clk,
input reset,
output [3:0] q
);
always @(posedge clk) begin
if (reset) begin
q <= 'd1;
end
else if (q == 'd10) begin
q <= 'd1;
end
else begin
q <= q + 'd1;
end
end
endmodule
构建一个计数从 0 到 9(包括 0 和 9)的计数器,周期为 10。复位输入是同步的,应将计数器复位为0。我们希望能够暂停计数器,而不是总是在每个时钟周期递增,因此 slowena 输入指示计数器何时应该递增。
module top_module (
input clk,
input slowena,
input reset,
output [3:0] q
);
always @(posedge clk) begin
if (reset) begin
q <= 'd0;
end
else if (q == 'd9 && slowena) begin
q <= 'd0;
end
else if (q < 'd9 && slowena) begin
q <= q + 'd1;
end
end
endmodule
设计具有以下输入和输出的 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
从 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
生成 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) begin
if (reset) begin
one <= 'd0;
end
else if (one == 'd9) begin
one <= 'd0;
end
else begin
one <= one + 'd1;
end
end
//ten
always @(posedge clk) begin
if (reset) begin
ten <= 'd0;
end
else if (ten == 'd9 && one == 'd9) begin
ten <= 'd0;
end
else if (ena[1]) begin
ten <= ten + 'd1;
end
else begin
ten <= ten;
end
end
//hundred
always @(posedge clk) begin
if (reset) begin
hundred <= 'd0;
end
else if (hundred == 'd9 && ten == 'd9 && one == 'd9) begin
hundred <= 'd0;
end
else if (ena[2]) begin
hundred <= hundred + 'd1;
end
else begin
hundred <= hundred;
end
end
//thousand
always @(posedge clk) begin
if (reset) begin
thousand <= 'd0;
end
else if (thousand =='d9 && hundred == 'd9 && ten == 'd9 && one == 'd9) begin
thousand <= 'd0;
end
else if (ena[3]) begin
thousand <= thousand + 'd1;
end
else begin
thousand <= 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
创建一组适合用作 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)begin
if(reset)begin
ss_ones <= 4'b0;
end
else if(add_ss_ones)begin
if(end_ss_ones)begin
ss_ones <= 4'b0;
end
else begin
ss_ones <= ss_ones + 4'b1;
end
end
end
assign add_ss_tens = end_ss_ones;
assign end_ss_tens = add_ss_tens && (ss_tens == 4'd5);
always @(posedge clk)begin
if(reset)begin
ss_tens <= 4'b0;
end
else if(add_ss_tens)begin
if(end_ss_tens)begin
ss_tens <= 4'b0;
end
else begin
ss_tens <= ss_tens + 4'b1;
end
end
end
assign add_mm_ones = end_ss_tens;
assign end_mm_ones = add_mm_ones && (mm_ones == 4'd9);
always @(posedge clk)begin
if(reset)begin
mm_ones <= 4'b0;
end
else if(add_mm_ones)begin
if(end_mm_ones)begin
mm_ones <= 4'b0;
end
else begin
mm_ones <= mm_ones + 4'b1;
end
end
end
assign add_mm_tens = end_mm_ones;
assign end_mm_tens = add_mm_tens && (mm_tens == 4'd5);
always @(posedge clk)begin
if(reset)begin
mm_tens <= 4'b0;
end
else if(add_mm_tens)begin
if(end_mm_tens)begin
mm_tens <= 4'b0;
end
else begin
mm_tens <= mm_tens + 4'b1;
end
end
end
assign 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)begin
if(reset)begin
hh_ones <= 4'd2;
end
else if(add_hh_ones)begin
if(end_hh_ones_0)begin
hh_ones <= 4'b0;
end
else if(end_hh_ones_1)begin
hh_ones <= 4'b1;
end
else begin
hh_ones <= hh_ones+4'b1;
end
end
end
assign 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)begin
if(reset)begin
hh_tens <= 4'b1;
end
else if(add_hh_tens)begin
if(end_hh_tens_0)begin
hh_tens <= 4'b0;
end
else if(end_hh_tens_1)begin
hh_tens <= hh_tens + 4'b1;
end
end
end
always@(posedge clk)begin
if(reset)begin
pm_temp <= 1'b0;
end
else if(pm_ding)begin
pm_temp <= ~pm_temp;
end
end
assign 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
这部分主要学习计数器的使用,这个在实际设计中用的非常多,尤其是在处理数据的时候,计数器设计不难,但是需要注意计数值到边缘时的处理,是否有延时等情况。