Verilog计数器
HDLBits链接
前言
今天更新一个小节内容:计数器。计数器可以说是我们接触数字电路以后用的最频繁的模块之一了,无论是项目、应聘还是将来的工作,计数器都无处不在。
题库
题目描述1:
构建一个从0到15的4位二进制计数器,周期为16。同步复位,复位应该将计数器重置为0。
Solution1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| module top_module ( input clk, input 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| module top_module ( input clk, input 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| module top_module ( input clk, input 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
| 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列出,这样层次感更加清晰。