当前位置:   article > 正文

刷完这套题,我才发现Verilog原来如此简单----HDLBits答案系列---- Counters_建立一个从0到9的十进制计数器,reset是高电平有效的同步复位信号,将计数器输出复

建立一个从0到9的十进制计数器,reset是高电平有效的同步复位信号,将计数器输出复

写在前面

全部答案汇总:刷完这套题,我才发现Verilog原来如此简单----HDLBits答案汇总

今天更新Circuits章节中Sequential Logic的1个小节:Counters


Four-bit binary counter

        题目:构建一个从0到15的4位二进制计数器,周期为16。同步复位,复位应该将计数器重置为0。

        个人思路:

                因为这个题目是4位宽的计数器且要求从0-15计数,那么可以不要设置清零条件(计数器到15后会溢出自动到0),所以只要在复位无效的情况下,计数器输出每周期递增一;

        复位有效时,计数器输出0。

  1. module top_module (
  2. input clk,
  3. input reset, // Synchronous active-high reset
  4. output [3:0] q);
  5. always@(posedge clk)begin
  6. if(reset)
  7. q <= 4'd0;
  8. else
  9. q <= q + 1'b1;
  10. end
  11. endmodule

Decade counter

        题目:构建一个从0到9的4位二进制计数器,周期为10。同步复位,复位应该将计数器重置为0。

        个人思路:

                这个题目是4位宽的计数器且要求从0-9计数,和上题不同的是,计数器到9后即要求恢复到0,所以不存在溢出的情况,需要手动清零。所以当计数器计数到9,计数器清零,其他

        时候计数器每周期递增一;复位有效时,计数器输出0。

  1. module top_module (
  2. input clk,
  3. input reset,
  4. output [3:0] q);
  5. always@(posedge clk)begin
  6. if(reset)
  7. q <= 4'd0;
  8. else if(q == 4'd9) //计数到最大值清零
  9. q <= 4'd0;
  10. else
  11. q <= q + 1'b1; //其他时候每周期+1
  12. end
  13. endmodule

Decade counter again

        题目:构建一个从1到10的4位二进制计数器。同步复位,复位应该将计数器重置为1。

        个人思路:

                和上题基本相同;只需要把复位重置为1,且从1-10计数(计数最大值为10)。

  1. module top_module (
  2. input clk,
  3. input reset,
  4. output [3:0] q);
  5. always@(posedge clk)begin
  6. if(reset)
  7. q <= 4'd1;
  8. else if(q == 4'd10)
  9. q <= 4'd1;
  10. else
  11. q <= q + 1'b1;
  12. end
  13. endmodule

Slow decade counter

        题目:构建一个从0到9(包括9)的十进制计数器,其周期为10。同步复位,复位应该将计数器重置为0。我们希望能够暂停计数器,而不是总是在每个时钟周期中递增,因此slowena输入指示计数器应该何时递增。

        个人思路:

                计数器在递增时应判断使能slowena是否有效,有效则递增或清零(计数到最大值),无效则保持。        

  1. module top_module (
  2. input clk,
  3. input slowena,
  4. input reset,
  5. output [3:0] q);
  6. always@(posedge clk)begin
  7. if(reset)
  8. q <= 4'd0;
  9. else if(slowena)begin
  10. if(q == 4'd9)
  11. q <= 4'd0;
  12. else
  13. q <= q + 1'd1;
  14. end
  15. else
  16. q <= q;
  17. end
  18. endmodule

Counter 1-12

题目:

使用以下条件设计一个1-12的计数器:

  • Reset:高电平有效的同步复位信号,复位到1
  • Enable:高电平有效的计数器计数使能信号
  • Clk:上升沿触发的时钟输入
  • Q[3:0]:计数器输出
  • c_enable, c_load, c_d[3:0] 控制信号到提供的4位计数器,因此可以验证正确的操作。

您需要准备以下组件:

  • 下面的4位二进制计数器(coun4),它具有使能和同步并行载入(载入优先级高于使能)。count4模块将提供给您。在你的电路中实例化它。
  • 逻辑门
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输入的信号。它们的目的是为了检查这些信号的正确性。

个人思路:

        题目提供了一个4位的计数器(0-15):

                使能信号enable:直接把c_enable连到这里就可以

                载入信号load:结合c_load可以实现复位清零,以及最大值清零

                载入值c_load:同上

  1. module top_module (
  2. input clk,
  3. input reset,
  4. input enable,
  5. output [3:0] Q,
  6. output c_enable,
  7. output c_load,
  8. output [3:0] c_d
  9. );
  10. assign c_enable = enable;
  11. assign c_load = reset | ((Q == 4'd12) && (enable == 1'b1)); //复位后者计数到最大值时进行载入
  12. assign c_d = c_load ? 4'd1 : 4'dx; //载入时载入值为1,其他时候不关心
  13. count4 the_counter (clk, c_enable, c_load, c_d , Q);
  14. endmodule

Counter 1000

题目:

        从一个1000hz的时钟,派生一个1hz的信号,称为OneHertz,它可以用来驱动一组小时/分钟/秒计数器的启用信号,以创建一个数字挂钟。因为我们想让时钟每秒计数一次,所以一hz信号必须精确地保持每秒一个周期。建立分频器使用模10 (BCD)计数器和尽可能少的其他门。还输出您使用的每个BCD计数器的启用信号(c_enable[0]表示最快的计数器,c_enable[2]表示最慢的计数器)。

        以下BCD模块将提供给您。Enable是高电平有效的计数器使能信号。Reset是高电平有效同步复位信号,复位值为0。电路中的所有计数器必须直接使用相同的1000hz信号。

        module bcdcount (
	        input clk,
	        input reset,
	        input enable,
	        output reg [3:0] Q
        );

个人思路:

        从1000hz--1hz输出,实际上就是要设计一个周期为1000的计数器(每次计数到999就输出一个信号,这个信号周期就是1hz)。题目给出了一个4位的BCD模块,我们可以例化三次这个模块,第一次例化计数10次(每个时钟周期+1),第二次例化计数10次(在第一次例化每计数10次时加+1),第三次例化计数10次(在第二次例化每计数10次时加+1),这样就实现了每1000个时钟周期+1,对应的输出信号的频率也就变成了1hz。

  1. module top_module (
  2. input clk,
  3. input reset,
  4. output OneHertz,
  5. output [2:0] c_enable
  6. );
  7. wire[3:0] one, ten, hundred;
  8. assign c_enable = {one == 4'd9 && ten == 4'd9, one == 4'd9, 1'b1};
  9. assign OneHertz = (one == 4'd9 && ten == 4'd9 && hundred == 4'd9);
  10. bcdcount counter0 (clk, reset, c_enable[0], one);
  11. bcdcount counter1 (clk, reset, c_enable[1], ten);
  12. bcdcount counter2 (clk, reset, c_enable[2], hundred);
  13. endmodule

4-digit decimal counter

题目:

        构建一个4位BCD(二进制编码的十进制)计数器。每个十进制数字使用4位进行编码:q[3:0]是个位,q[7:4]是十位,以此类推。各进制上的进位时也需输出一个使能信号,指示三位数字何时应该增加。

个人思路:
         千、百、十、个一共4位(每位4位宽,共16位宽),分别计数即可,设计的时候注意好计数使能条件和清零条件就好。细节看代码注释吧。

  1. module top_module (
  2. input clk,
  3. input reset,
  4. output [3:1] ena,
  5. output [15:0] q
  6. );
  7. //个、十、百、千计数器
  8. reg [3:0] ones;
  9. reg [3:0] tens;
  10. reg [3:0] hundreds;
  11. reg [3:0] thousands;
  12. //个、十、百、千计数器使能信号
  13. wire ones_ena;
  14. wire tens_ena;
  15. wire hundreds_ena;
  16. wire thousands_ena;
  17. //个、十、百、千计数器清零信号
  18. wire ones_end;
  19. wire tens_end;
  20. wire hundreds_end;
  21. wire thousands_end;
  22. //个、十、百、千计数器使能条件
  23. assign ones_ena = 1'b1; //个计数器一直计数
  24. assign tens_ena = ones_end; //十计数器在个计数器清零一次(计数到最大值)计数+1
  25. assign hundreds_ena = tens_end; //百计数器在十计数器清零一次(计数到最大值)计数+1
  26. assign thousands_ena = hundreds_end; //千计数器在百计数器清零一次(计数到最大值)计数+1
  27. //个、十、百、千计数器清零条件
  28. assign ones_end = (ones == 4'd9); //计数到最大值9清零
  29. assign tens_end = (tens == 4'd9 && ones == 4'd9);//计数到最大值99清零
  30. assign hundreds_end = (hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9);//计数到最大值999清零
  31. assign thousands_end = (thousands == 4'd9 && hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9);//计数到最大值9999清零
  32. //个计数器计数always块
  33. always@(posedge clk)begin
  34. if(reset)
  35. ones <= 4'd0;
  36. else if(ones_end)
  37. ones <= 4'd0;
  38. else if(ones_ena)
  39. ones <= ones + 1'b1;
  40. end
  41. //十计数器计数always块
  42. always@(posedge clk)begin
  43. if(reset)
  44. tens <= 4'd0;
  45. else if(tens_end)
  46. tens <= 4'd0;
  47. else if(tens_ena)
  48. tens <= tens + 1'b1;
  49. end
  50. //百计数器计数always块
  51. always@(posedge clk)begin
  52. if(reset)
  53. hundreds <= 4'd0;
  54. else if(hundreds_end)
  55. hundreds <= 4'd0;
  56. else if(hundreds_ena)
  57. hundreds <= hundreds + 1'b1;
  58. end
  59. //千计数器计数always块
  60. always@(posedge clk)begin
  61. if(reset)begin
  62. thousands <= 4'd0;
  63. end
  64. else if(thousands_end)begin
  65. thousands <= 4'd0;
  66. end
  67. else if(thousands_ena) begin
  68. thousands <= thousands + 1'b1;
  69. end
  70. end
  71. //输出
  72. assign q = {thousands, hundreds, tens, ones}; //个、十、百、千拼接输出
  73. assign ena[1] = (ones_end) ? 1'b1 : 1'b0;
  74. assign ena[2] = (tens_end) ? 1'b1 : 1'b0;
  75. assign ena[3] = (hundreds_end) ? 1'b1 : 1'b0;
  76. endmodule

12-hour clock

题目:

        创建一组适合作为12小时的时钟使用的计数器(带有am/pm指示器)。你的计数器是由一个快速运行的clk驱动,每次时钟增加时ena必须为1。reset将时钟重置到中午12点。上午时pm=0,下午时pm=1。hh,mm和ss分别是小时(01-12)、分钟(00-59)和秒(00-59)的两个BCD(二进制编码的十进制)数字。

        Reset比enable具有更高的优先级,并且即使在没有启用时也会发生。

        下面的时序图显示了从11:59:59 AM到12:00:00 PM的翻转行为以及同步的Reset和enable行为。

 个人思路:

        时、分、秒一共6位,分别计数即可,设计的时候注意好计数使能条件和清零条件就好。细节看代码注释吧。

  1. module top_module(
  2. input clk, //时钟
  3. input reset, //复位
  4. input ena, //计数使能信号
  5. output pm, //pm标志,1:PM;0:AM
  6. output [7:0] hh, //时BCD
  7. output [7:0] mm, //分BCD
  8. output [7:0] ss); //秒BCD
  9. reg pm_temp; //pm寄存值
  10. reg [3:0] ss_ones; //秒个位计数器
  11. reg [3:0] ss_tens; //秒十位计数器
  12. reg [3:0] mm_ones; //分个位计数器
  13. reg [3:0] mm_tens; //分十位计数器
  14. reg [3:0] hh_ones; //时个位计数器
  15. reg [3:0] hh_tens; //时十位计数器
  16. wire ss_ones_ena; //秒个位计数使能
  17. wire ss_tens_ena; //秒十位计数使能
  18. wire mm_ones_ena; //分个位计数使能
  19. wire mm_tens_ena; //分十位计数使能
  20. wire hh_ones_ena; //时个位计数使能
  21. wire hh_tens_ena; //时十位计数使能
  22. wire ss_ones_end; //秒个位计数完成
  23. wire ss_tens_end; //秒个位计数完成
  24. wire mm_ones_end; //分个位计数完成
  25. wire mm_tens_end; //分十位计数完成
  26. wire hh_ones_0_end; //时个位计数完成(十位为0
  27. wire hh_ones_1_end; //时个位计数完成(十位为1
  28. wire hh_tens_0_end; //时十位计数完成(十位为0
  29. wire hh_tens_1_end; //时十位计数完成(十位为1
  30. wire pm_inv; //PM跳转标志
  31. //时、分、秒计数使能条件
  32. assign ss_ones_ena = ena; //使能信号有效秒钟各位开始计数
  33. assign ss_tens_ena = ss_ones_end; //秒钟个位计数完成后,秒钟十位开始计数
  34. assign mm_ones_ena = ss_tens_end; //秒钟个位计数完成后,分钟个位开始计数
  35. assign mm_tens_ena = mm_ones_end; //分钟个位计数完成后,秒钟十位开始计数
  36. assign hh_ones_ena = mm_tens_end; //分钟十位计数完成后,时钟个位开始计数
  37. assign hh_tens_ena = mm_tens_end; //时钟个位计数完成后,时钟十位开始计数
  38. //时、分、秒计数完成判断
  39. assign ss_ones_end = ss_ones_ena && (ss_ones == 4'd9); //秒钟个位计数使能信号有效,且秒钟个位计数到最大值9
  40. assign ss_tens_end = ss_tens_ena && (ss_tens == 4'd5); //秒钟十位计数使能信号有效,且秒钟十位计数到最大值5
  41. assign mm_ones_end = mm_ones_ena && (mm_ones == 4'd9); //时钟个位计数使能信号有效,且时钟个位计数到最大值9
  42. assign mm_tens_end = mm_tens_ena && (mm_tens == 4'd5); //时钟十位计数使能信号有效,且时钟十位计数到最大值5
  43. //时钟个位计数使能信号有效,且时钟个位计数到最大值9(十位为0
  44. assign hh_ones_0_end = hh_ones_ena && ((hh_ones == 4'd9) && (hh_tens == 4'd0));
  45. //时钟个位计数使能信号有效,且时钟个位计数到最大值2(十位为1
  46. assign hh_ones_1_end = hh_ones_ena && ((hh_ones == 4'd2) && (hh_tens == 4'd1));
  47. assign hh_tens_0_end = hh_tens_ena && hh_ones_1_end; //时钟十位计数使能信号有效,且时钟个位计数完成(十位为0
  48. assign hh_tens_1_end = hh_tens_ena && hh_ones_0_end; //时钟十位计数使能信号有效,且时钟个位计数完成(十位为1
  49. //pm跳转条件判断
  50. assign pm_inv = hh_tens == 4'd1 && hh_ones == 4'd1 && mm_tens_end;
  51. //pm标志位输出
  52. assign pm = pm_temp;
  53. //时、分、秒输出
  54. assign ss = {ss_tens, ss_ones}; //十位、个位拼接
  55. assign mm = {mm_tens, mm_ones}; //十位、个位拼接
  56. assign hh = {hh_tens, hh_ones}; //十位、个位拼接
  57. //秒钟的个位计数
  58. always @(posedge clk)begin
  59. if(reset)begin
  60. ss_ones <= 4'b0; //复位清零
  61. end
  62. else if(ss_ones_ena)begin //使能有效
  63. if(ss_ones_end)begin //计数完成则清零
  64. ss_ones <= 4'b0;
  65. end
  66. else begin
  67. ss_ones <= ss_ones + 4'b1; //计数递加1
  68. end
  69. end
  70. end
  71. //秒钟的十位计数
  72. always @(posedge clk)begin
  73. if(reset)begin
  74. ss_tens <= 4'b0;
  75. end
  76. else if(ss_tens_ena)begin
  77. if(ss_tens_end)begin
  78. ss_tens <= 4'b0;
  79. end
  80. else begin
  81. ss_tens <= ss_tens + 4'b1;
  82. end
  83. end
  84. end
  85. //分钟的个位计数
  86. always @(posedge clk)begin
  87. if(reset)begin
  88. mm_ones <= 4'b0;
  89. end
  90. else if(mm_ones_ena)begin
  91. if(mm_ones_end)begin
  92. mm_ones <= 4'b0;
  93. end
  94. else begin
  95. mm_ones <= mm_ones + 4'b1;
  96. end
  97. end
  98. end
  99. //分钟的十位计数
  100. always @(posedge clk)begin
  101. if(reset)begin
  102. mm_tens <= 4'b0;
  103. end
  104. else if(mm_tens_ena)begin
  105. if(mm_tens_end)begin
  106. mm_tens <= 4'b0;
  107. end
  108. else begin
  109. mm_tens <= mm_tens + 4'b1;
  110. end
  111. end
  112. end
  113. //时钟的个位计数
  114. always @(posedge clk)begin
  115. if(reset)begin
  116. hh_ones <= 4'd2;
  117. end
  118. else if(hh_ones_ena)begin
  119. if(hh_ones_0_end)begin
  120. hh_ones <= 4'b0;
  121. end
  122. else if(hh_ones_1_end)begin
  123. hh_ones <= 4'b1;
  124. end
  125. else begin
  126. hh_ones <= hh_ones+4'b1;
  127. end
  128. end
  129. end
  130. //时钟的十位计数
  131. always @(posedge clk)begin
  132. if(reset)begin
  133. hh_tens <= 4'b1;
  134. end
  135. else if(hh_tens_ena)begin
  136. if(hh_tens_0_end)begin
  137. hh_tens <= 4'b0;
  138. end
  139. else if(hh_tens_1_end)begin
  140. hh_tens <= hh_tens + 4'b1;
  141. end
  142. end
  143. end
  144. //pm跳转
  145. always@(posedge clk)begin
  146. if(reset)begin
  147. pm_temp <= 1'b0;
  148. end
  149. else if(pm_inv)begin //满足跳转条件则翻转
  150. pm_temp <= ~pm_temp;
  151. end
  152. end
  153. endmodule

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/648824
推荐阅读
相关标签
  

闽ICP备14008679号