时序逻辑2:计数器
1、四位二进制计数器
构建一个从0到15的4位二进制计数器,周期为16。同步复位,复位应该将计数器重置为0。
代码实现:
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always@(posedge clk) begin
if(!reset)
q <= q + 1'b1;
else
q <= 4'b0;
end
endmodule
验证结果:
2、十进制计数器1
构建一个从0到9(包括9)的十进制计数器,其周期为10。同步复位,复位应该将计数器重置为0。
代码实现:
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always@(posedge clk) begin
if(reset)
q <= 4'b0;
else begin
if(q < 9)
q <= q + 1'b1;
else
q <= 4'b0;
end
end
endmodule
验证结果:
3、十进制计数器2
制作一个从1到10的10进制计数器。同步复位,复位应该将计数器复位为1。
代码实现:
module top_module (
input clk,
input reset,
output [3:0] q);
always@(posedge clk) begin
if(reset)
q <= 4'd1;
else begin
if(q < 10)
q <= q + 1'b1;
else
q <= 4'd1;
end
end
endmodule
验证结果:
4、延迟十进制计数器
构建一个从0到9(包括9)的十进制计数器,其周期为10。同步复位,复位应该将计数器重置为0。我们希望能够暂停计数器,而不是总是在每个时钟周期中递增,因此slowena输入指示计数器应该何时递增。
代码实现:
module top_module (
input clk,
input slowena,
input reset,
output [3:0] q);
always@(posedge clk) begin
if(reset)
q <= 4'b0;
else
if(slowena) begin
if(q == 4'd9)
q <= 4'b0;
else
q<= q + 1'b1;
end
end
endmodule
验证结果:
5、1-12的计数器
设计一个具有以下输入和输出的 1-12 计数器:
Reset :同步高电平有效复位,强制计数器为 1
Enable: 计数器运行设置为高电平
Clk: 上升沿触发时钟输入
Q[3:0] :计数器的输出
c_enable, c_load, c_d[3:0]:控制信号到提供的4位计数器,这样就可以验证操作是否正确。
您可以使用以下组件:
(1)下面的4位二进制计数器(coun4),它具有使能和同步并行负载输入(负载优先级高于使能)。count4模块提供给您。在你的电路中实例化它。
(2)逻辑门
module count4(
input clk,
input enable,
input load,
input [3:0] d,
output reg [3:0] Q
);
c_enable、c_load和c_d输出分别是到内部计数器的enable、load和d输入的信号。它们的目的是为了检查这些信号的正确性。
代码实现:
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'b1 : 4'b0;
count4 counter(clk,c_enable,c_load,c_d,Q);
endmodule
验证结果:
6、 1kHz→1Hz 计数器
从 1000 Hz 时钟导出一个 1 Hz 信号,称为OneHertz,可以用来驱动一组小时/分钟/秒计数器的启用信号,以创建一个数字挂钟。因为我们想让时钟每秒计数一次,所以 1 Hz 信号必须精确地保持每秒一个周期。建立分频器使用模10 (BCD)计数器和尽可能少的其他门。还从您使用的每个 BCD 计数器输出启用信号(c_enable[0] 表示最快的计数器,c_enable[2] 表示最慢的计数器)。
为您提供了以下 BCD 计数器。Enable必须为高电平才能运行计数器。复位是同步的并设置为高电平以强制计数器归零。电路中的所有计数器必须直接使用相同的 1000 Hz 信号。
module bcdcount (
input clk,
input reset,
input enable,
output reg [3:0] Q
);
代码实现:
module top_module (
input clk,
input reset,
output OneHertz,
output [2:0] c_enable
);
wire [3:0] one,ten,hundred;
assign c_enable = {one ==4'd9 && ten == 4'd9, one ==4'd9 ,1'd1};
assign OneHertz = {one ==4'd9 && ten == 4'd9 && hundred ==4'd9};
bcdcount counter0 (clk, reset, c_enable[0],one);
bcdcount counter1 (clk, reset, c_enable[1],ten);
bcdcount counter2 (clk, reset, c_enable[2],hundred);
endmodule
验证结果:
7、 四位十进制计数器
构建一个4位BCD(二进制编码的十进制)计数器。每个十进制数字使用4位进行编码:q[3:0]是个位,q[7:4]是十位,以此类推。各进制上的进位时也需输出一个使能信号,指示三位数字何时应该增加。
代码实现:
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:1] ena,
output [15:0] q);
reg [3:0] ones,tens,hundreds,thousands;
always @(posedge clk) begin
if(reset)
ones <= 4'b0;
else if(ones == 4'd9)
ones <=4'b0;
else
ones <= ones + 4'd1;
end
always @(posedge clk)begin
if(reset)
tens <= 4'b0;
else if(tens == 4'd9 && ones == 4'd9)
tens <= 4'b0;
else if(ones == 4'd9)
tens <= tens + 4'd1;
end
always @(posedge clk)begin
if(reset)
hundreds <= 4'b0;
else if(hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9)
hundreds <= 4'b0;
else if(tens == 4'd9 && ones == 4'd9)
hundreds <= hundreds + 4'd1;
end
always @(posedge clk)begin
if(reset)
thousands <= 4'b0;
else if(thousands == 4'd9 && hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9)
thousands <= 4'b0;
else if(hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9)
thousands <= thousands + 4'd1;
end
assign q = {thousands,hundreds,tens,ones};
assign ena[1] = (ones == 4'd9) ? 1'b1 : 1'b0;
assign ena[2] = ((ones == 4'd9) && (tens == 4'd9)) ? 1'b1 : 1'b0;
assign ena[3] = ((ones == 4'd9) && (tens == 4'd9) && (hundreds == 4'd9)) ? 1'b1 : 1'b0;
endmodule
验证结果:
8、 12小时的时钟
创建一组适合作为12小时的时钟使用的计数器(带有am/pm指示器)。你的计数器是由一个快速运行的clk驱动,每次时钟增加时ena必须为1。reset将时钟重置到中午12点。上午时pm=0,下午时pm=0。hh,mm和ss分别是小时(01-12)、分钟(00-59)和秒(00-59)的两个BCD(二进制编码的十进制)数字。
Reset比enable具有更高的优先级,并且即使在没有启用时也会发生。
下面的时序图显示了从11:59:59 AM到12:00:00 PM的翻转行为以及同步的Reset和enable行为。
代码实现:
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;
reg [3:0] ss_ones,ss_tens,mm_ones,mm_tens,hh_ones,hh_tens;
wire add_ss_ones,end_ss_ones,add_ss_tens,end_ss_tens;
wire add_mm_ones,end_mm_ones,add_mm_tens,end_mm_tens;
wire add_hh_ones,end_hh_ones_0,end_hh_ones_1,add_hh_tens,end_hh_tens_0,end_hh_tens_1;
wire pm_ding;
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)
ss_ones <= 4'b0;
else
ss_ones <= ss_ones + 4'b1;
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)
ss_tens <= 4'b0;
else if(add_ss_tens)begin
if(end_ss_tens)
ss_tens <= 4'b0;
else
ss_tens <= ss_tens + 4'b1;
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)
mm_ones <= 4'b0;
else if(add_mm_ones)begin
if(end_mm_ones)
mm_ones <= 4'b0;
else
mm_ones <= mm_ones + 4'b1;
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)
mm_tens <= 4'b0;
else if(add_mm_tens)begin
if(end_mm_tens)
mm_tens <= 4'b0;
else
mm_tens <= mm_tens + 4'b1;
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)
hh_ones <= 4'd2;
else if(add_hh_ones)begin
if(end_hh_ones_0)
hh_ones <= 4'b0;
else if(end_hh_ones_1)
hh_ones <= 4'b1;
else
hh_ones <= hh_ones + 4'b1;
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)
hh_tens <= 4'b1;
else if(add_hh_tens)begin
if(end_hh_tens_0)
hh_tens <= 4'b0;
else if(end_hh_tens_1)
hh_tens <= hh_tens + 4'b1;
end
end
always@(posedge clk)begin
if(reset)
pm_temp <= 1'b0;
else if(pm_ding)
pm_temp <= ~pm_temp;
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
验证结果:
参考资料: Verilog计数器.