Verilog计数器
前言
今天更新一个小节内容:计数器。计数器可以说是我们接触数字电路以后用的最频繁的模块之一了,无论是项目、应聘还是将来的工作,计数器都无处不在。
题库
题目描述1:
构建一个从0到15的4位二进制计数器,周期为16。同步复位,复位应该将计数器重置为0。
Solution1:
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always @(posedge clk)begin
if(reset)begin
q<=4'b0;
end
else begin
q<=q+1'b1;
end
end
endmodule
题目描述2:
构建一个从0到9(包括9)的十进制计数器,其周期为10。同步复位,复位应该将计数器重置为0。
Solution2:
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always @(posedge clk)begin
if(reset || q >= 4'd9)begin
q<=4'b0;
end
else begin
q<=q+1'b1;
end
end
endmodule
题目描述3:
制作一个从1到10的10进制计数器。同步复位,复位应该将计数器复位为1。
Solution3:
module top_module (
input clk,
input reset,
output [3:0] q);
always @(posedge clk)begin
if(reset || q>=4'd10)begin
q<=4'b1;
end
else begin
q<=q+1'b1;
end
end
endmodule
题目描述4:
构建一个从0到9(包括9)的十进制计数器,其周期为10。同步复位,复位应该将计数器重置为0。我们希望能够暂停计数器,而不是总是在每个时钟周期中递增,因此slowena
输入指示计数器应该何时递增。
Solution4:
module top_module (
input clk,
input slowena,
input reset,
output [3:0] q);
always @(posedge clk)begin
if(reset)begin
q<=4'b0;
end
else if(slowena)begin
if(q==4'd9)begin
q<=4'b0;
end
else begin
q<=q+1'b1;
end
end
end
endmodule
题目描述4:
设计一个1-12计数器
Solution4:
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
题目描述5:
例化BCD模块实现降频操作,1kHz->1Hz。
Solution5:
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'b1};
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
题目描述6:
构建一个4位BCD(二进制编码的十进制)计数器。每个十进制数字使用4位进行编码:q[3:0]是个位,q[7:4]是十位,以此类推。各进制上的进位时也需输出一个使能信号,指示三位数字何时应该增加。
Solution6:
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:1] ena,
output [15:0] q);
reg [3:0] ones;
reg [3:0] tens;
reg [3:0] hundreds;
reg [3:0] thousands;
always @(posedge clk) begin
if(reset)begin
ones <= 4'b0;
end
else if(ones == 4'd9)begin
ones <=4'b0;
end
else begin
ones <= ones + 4'd1;
end
end
always @(posedge clk)begin
if(reset)begin
tens <= 4'b0;
end
else if(tens == 4'd9 && ones == 4'd9)begin
tens <= 4'b0;
end
else if(ones == 4'd9)begin
tens <= tens + 4'd1;
end
end
always @(posedge clk)begin
if(reset)begin
hundreds <= 4'b0;
end
else if(hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9)begin
hundreds <= 4'b0;
end
else if(tens == 4'd9 && ones == 4'd9) begin
hundreds <= hundreds + 4'd1;
end
end
always @(posedge clk)begin
if(reset)begin
thousands <= 4'b0;
end
else if(thousands == 4'd9 && hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9)begin
thousands <= 4'b0;
end
else if(hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9)begin
thousands <= thousands + 4'd1;
end
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
题目描述7:
创建一组适合作为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行为。
Solution7:
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;
reg [3:0] ss_tens;
reg [3:0] mm_ones;
reg [3:0] mm_tens;
reg [3:0] hh_ones;
reg [3:0] hh_tens;
wire add_ss_ones;
wire end_ss_ones;
wire add_ss_tens;
wire end_ss_tens;
wire add_mm_ones;
wire end_mm_ones;
wire add_mm_tens;
wire end_mm_tens;
wire add_hh_ones;
wire end_hh_ones_0;
wire end_hh_ones_1;
wire add_hh_tens;
wire end_hh_tens_0;
wire 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)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
总结
- 熟悉了基本计数器的代码编写。
- 时钟的进位条件应单独用assign列出,这样层次感更加清晰。