Verilog学习笔记HDLBits——Counters

本文档介绍了使用Verilog语言设计不同类型的计数器,包括二进制计数器、十进制计数器、带有使能和复位控制的计数器、BCD计数器以及12小时时钟计数器。通过实例化和逻辑门组合,实现了计数器的同步复位、使能控制以及频率分频等功能。同时,对于12小时时钟计数器,还考虑了AM/PM的切换。这些计数器的设计展示了在数字逻辑设计中如何处理计数和控制信号的交互。
摘要由CSDN通过智能技术生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

一、Counters

1. Four-bit binary counter

Practice:Build a 4-bit binary counter that counts from 0 through 15, inclusive, with a period of 16. The reset input is synchronous, and should reset the counter to 0.
翻译:构建一个4位二进制计数器,从0到15(包括15),周期为16。复位输入是同步的,应该将计数器复位为0。
在这里插入图片描述

Solution(不唯一,仅供参考):

module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output reg [3:0] q);
    always @(posedge clk)begin
        if(reset)begin
           q<=0; 
        end
        else begin
            if(q==4'b1111)begin
                q<=0;
            end
            else begin
               q<=q+1; 
            end
        end
    end
endmodule

Timing Diagram
在这里插入图片描述

2. Decade counter

Practice:Build a decade counter that counts from 0 through 9, inclusive, with a period of 10. The reset input is synchronous, and should reset the counter to 0.
翻译:同样是 4bit 计数器,本题只计数到 0~9,周期(period)为 10,同步复位且复位为 0。时序图如下:
在这里插入图片描述

Solution(不唯一,仅供参考):

module top_module (
    input clk,
    input reset,        // Synchronous active-high reset
    output reg [3:0] q);
 	always @(posedge clk)begin
        if(reset)begin
           q<=0; 
        end
        else begin
            if(q==4'b1001)begin
                q<=0;
            end
            else begin
               q<=q+1; 
            end
        end
    end
endmodule

Timing Diagram
在这里插入图片描述

3. Decade counter again

Practice:Make a decade counter that counts 1 through 10, inclusive. The reset input is synchronous, and should reset the counter to 1.
翻译:本题与上题类似,只需计数1-10,复位到1.
在这里插入图片描述

Solution(不唯一,仅供参考):

module top_module (
    input clk,
    input reset,
    output reg [3:0] q);
    always @(posedge clk)begin
        if(reset)begin
           q<=1;
        end
        else begin
            if(q==4'b1010)begin
               q<=1; 
            end
            else begin
               q<=q+1;
            end
        end
    end
endmodule

Timing Diagram
在这里插入图片描述

4. Slow decade counter

Practice:Build a decade counter that counts from 0 through 9, inclusive, with a period of 10. The reset input is synchronous, and should reset the counter to 0. We want to be able to pause the counter rather than always incrementing every clock cycle, so the slowena input indicates when the counter should increment.

翻译:设计一个 0~9 的计数器,共 10 个周期。该计数器采用同步复位且复位为 0。但是本题是希望该计数器并不是随着 clk 的变化而递增,而是随着一个 slowena 使能信号来控制增加。时序图如下图所示:
在这里插入图片描述
Solution(不唯一,仅供参考):

module top_module (
    input clk,
    input slowena,
    input reset,
    output reg [3:0] q);
    always @(posedge clk)begin
        if(reset)begin
           q<=0; 
        end
        else if(slowena)begin
            if(q==4'b1001)begin
            	q<=0;
            end
       		else begin
            	q<=q+1;
            end
        end
    	else begin
           q<=q; 
        end
    end
endmodule

Timing Diagram
在这里插入图片描述
在这里插入图片描述

5. Counter 1-12

Practice:Design a 1-12 counter with the following inputs and outputs:
Reset: Synchronous active-high reset that forces the counter to 1
Enable:Set high for the counter to run
Clk :Positive edge-triggered clock input
Q[3:0] :The output of the counter
c_enable, c_load, c_d[3:0] :Control signals going to the provided 4-bit counter, so correct operation can be verified.
翻译:根据以下输入输出信号设计一个计算 1~12 的计数器:

  • Reset:同步复位信号,高复位,将计数器复位为 1

  • Enable:使能信号高有效

  • Clk:时钟上升沿触发计数器工作

  • Q[3:0]:计数器输出

您需要准备以下组件:

  • 下面的4位二进制计数器(coun4),它具有使能和同步并行载入(载入优先级高于使能)。count4模块将提供给您。在你的电路中实例化它。

  • 逻辑门

c_enable, c_load(同步置位), c_d[3:0]:题目提供了一个 4-bit 的计数器,这三个信号是用于该 4-bit 计数器的控制信号。

题目提供的 4-bit 计数器:

有 enable 信号,带复位和置位的计数器,将该计数器例化至我们的代码中。(load 优先级高于 enable)
再用一些其他的逻辑门来完成本题。

module count4(
    input clk,
    input enable,
    input load,
    input [3:0] d,
    output reg [3:0] Q
);

Solution(不唯一,仅供参考):
没想出来,借鉴了一下大佬的

module top_module (
    input clk,
    input reset,
    input enable,
    output [3:0] Q,
    output c_enable,
    output c_load,
    output [3:0] c_d
); //
    count4 the_counter (clk, c_enable, c_load, c_d, Q );
    assign c_enable = enable;
    assign c_load = reset|((Q==4'b1100)&(enable==1'b1));
	assign c_d = c_load ? 4'b1 : 4'bx;
endmodule

load 的作用:load 有效时把 d 数值加载到 Q 端口。

注意:reset 是同步复位,用 assign 会使得 c_load 立即变为 1,但 c_load 是同步置位,等到下一个时钟上升沿才会赋值,效果相当于同步复位。
Timing Diagram
在这里插入图片描述

6. Counter 1000

Practice:From a 1000 Hz clock, derive a 1 Hz signal, called OneHertz, that could be used to drive an Enable signal for a set of hour/minute/second counters to create a digital wall clock. Since we want the clock to count once per second, the OneHertz signal must be asserted for exactly one cycle each second. Build the frequency divider using modulo-10 (BCD) counters and as few other gates as possible. Also output the enable signals from each of the BCD counters you use (c_enable[0] for the fastest counter, c_enable[2] for the slowest).
翻译: 从一个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。

Solution(不唯一,仅供参考):

module top_module (
    input clk,
    input reset,
    output OneHertz,
    output [2:0] c_enable
); //
    wire [3:0] one,ten,hundred;
    assign c_enable[0] = 1'b1;
    assign c_enable[1] = (1'b1)&&(one==4'd9);
    assign c_enable[2] = (1'b1)&&(one==4'd9)&&(ten==4'd9);
    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

TIming Diagram
在这里插入图片描述

7. 4-digit decimal counter

Practice:Build a 4-digit BCD (binary-coded decimal) counter. Each decimal digit is encoded using 4 bits: q[3:0] is the ones digit, q[7:4] is the tens digit, etc. For digits [3:1], also output an enable signal indicating when each of the upper three digits should be incremented.
翻译:构建一个4位BCD(二进制编码的十进制)计数器。每个十进制数字使用4位进行编码:q[3:0]是个位,q[7:4]是十位,以此类推。各进制上的进位时也需输出一个使能信号,指示三位数字何时应该增加。
在这里插入图片描述

Solution(不唯一,仅供参考):

module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output reg [15:0] q);
	//定义个位,十位,百位,千位计数器
    reg [3:0] ones,tens,hundreds,thousands;
    //定义个、十、百、千计数器的使能信号
    wire ones_ena,tens_ena,hundreds_ena,thousands_ena;
    //定义个、十、百、千计数器的清零信号
    wire ones_end,tens_end,hundreds_end,thousands_end;
    
    assign ones_ena = 1'b1;             //个计数器一直计数
    assign tens_ena = ones_end;         //十计数器在个计数器清零一次(计数到最大值)计数+
    assign hundreds_ena = tens_end;     //百计数器在十计数器清零一次(计数到最大值)计数+1
    assign thousands_ena = hundreds_end;//千计数器在百计数器清零一次(计数到最大值)计数+1
    
    assign ones_end = (ones==4'd9);
    assign tens_end = ((ones==4'd9)&&(tens==4'd9));
    assign hundreds_end = ((ones==4'd9)&&(tens==4'd9)&&(hundreds==4'd9));
    assign thousands_end = ((ones==4'd9)&&(tens==4'd9)&&(hundreds==4'd9)&&(thousands==4'd9));
    
    //计数模块
    always @(posedge clk)begin
        if(reset)begin
            ones<=4'd0;
        end
        else if(ones_end) begin
            ones<=4'd0;
        end
        else if(ones_ena)begin
            ones<=ones+1'b1;
        end
    end
        always @(posedge clk)begin
        if(reset)begin
            tens<=4'd0;
        end
            else if(tens_end) begin
            tens<=4'd0;
        end
            else if(tens_ena)begin
            tens<=tens+1'b1;
        end
    end
    always @(posedge clk)begin
        if(reset)begin
            hundreds<=4'd0;
        end
        else if(hundreds_end) begin
            hundreds<=4'd0;
        end
        else if(hundreds_ena)begin
            hundreds<=hundreds+1'b1;
        end
    end
     always @(posedge clk)begin
        if(reset)begin
            thousands<=4'd0;
        end
         else if(thousands_end) begin
            thousands<=4'd0;
        end
         else if(thousands_ena)begin
            thousands<=thousands+1'b1;
        end
    end
    
    assign q={thousands,hundreds,tens,ones};
    assign ena[1] = tens_ena;
    assign ena[2] = hundreds_ena;
    assign ena[3] = thousands_ena;
endmodule

Timing Diagram
在这里插入图片描述

8. 12-hour clock

Practice:Create a set of counters suitable for use as a 12-hour clock (with am/pm indicator). Your counters are clocked by a fast-running clk, with a pulse on ena whenever your clock should increment (i.e., once per second).
翻译:创建一组适合作为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行为.

Solution(不唯一,仅供参考):
本题可参考孤独的单刀博主,写的特别详细

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;		//秒个位计数器
    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		ss_ones_ena;	//秒个位计数使能
    wire		ss_tens_ena;	//秒十位计数使能
    wire		mm_ones_ena;	//分个位计数使能
    wire		mm_tens_ena;	//分十位计数使能
    wire		hh_ones_ena;	//时个位计数使能
    wire		hh_tens_ena;	//时十位计数使能
	
    wire		ss_ones_end;	//秒个位计数完成
    wire		ss_tens_end;	//秒个位计数完成
    wire		mm_ones_end;    //分个位计数完成
    wire		mm_tens_end;    //分十位计数完成
    wire		hh_ones_0_end;	//时个位计数完成(十位为0)
    wire		hh_ones_1_end;	//时个位计数完成(十位为1)
    wire		hh_tens_0_end;	//时十位计数完成(十位为0)
    wire		hh_tens_1_end;  //时十位计数完成(十位为1)
	
    wire		pm_inv;			//PM跳转标志
 
//时、分、秒计数使能条件   
    assign ss_ones_ena = ena;								//使能信号有效秒钟各位开始计数
	assign ss_tens_ena = ss_ones_end;						//秒钟个位计数完成后,秒钟十位开始计数
    assign mm_ones_ena = ss_tens_end;						//秒钟个位计数完成后,分钟个位开始计数
    assign mm_tens_ena = mm_ones_end;						//分钟个位计数完成后,秒钟十位开始计数
    assign hh_ones_ena = mm_tens_end;						//分钟十位计数完成后,时钟个位开始计数
    assign hh_tens_ena = mm_tens_end;						//时钟个位计数完成后,时钟十位开始计数
 
//时、分、秒计数完成判断	
    assign ss_ones_end = ss_ones_ena && (ss_ones == 4'd9);	//秒钟个位计数使能信号有效,且秒钟个位计数到最大值9
    assign ss_tens_end = ss_tens_ena && (ss_tens == 4'd5);	//秒钟十位计数使能信号有效,且秒钟十位计数到最大值5
    assign mm_ones_end = mm_ones_ena && (mm_ones == 4'd9);	//时钟个位计数使能信号有效,且时钟个位计数到最大值9
    assign mm_tens_end = mm_tens_ena && (mm_tens == 4'd5);  //时钟十位计数使能信号有效,且时钟十位计数到最大值5
	//时钟个位计数使能信号有效,且时钟个位计数到最大值9(十位为0)
    assign hh_ones_0_end = hh_ones_ena && ((hh_ones == 4'd9) && (hh_tens == 4'd0));
	//时钟个位计数使能信号有效,且时钟个位计数到最大值2(十位为1)					
    assign hh_ones_1_end = hh_ones_ena && ((hh_ones == 4'd2) && (hh_tens == 4'd1));
    assign hh_tens_0_end = hh_tens_ena && hh_ones_1_end;	//时钟十位计数使能信号有效,且时钟个位计数完成(十位为0)
    assign hh_tens_1_end = hh_tens_ena && hh_ones_0_end;	//时钟十位计数使能信号有效,且时钟个位计数完成(十位为1)
//pm跳转条件判断	
	assign pm_inv = hh_tens == 4'd1 && hh_ones == 4'd1 && mm_tens_end;
 
//pm标志位输出   	
	assign pm = pm_temp;	
//时、分、秒输出
    assign ss = {ss_tens, ss_ones};		//十位、个位拼接
    assign mm = {mm_tens, mm_ones};		//十位、个位拼接
    assign hh = {hh_tens, hh_ones};		//十位、个位拼接	
//秒钟的个位计数	
    always @(posedge clk)begin
        if(reset)begin
            ss_ones <= 4'b0;				//复位清零
        end
        else if(ss_ones_ena)begin			//使能有效
            if(ss_ones_end)begin			//计数完成则清零
                ss_ones <= 4'b0;
            end
            else begin
                ss_ones <= ss_ones + 4'b1;	//计数递加1
            end
        end
    end
//秒钟的十位计数   
    always @(posedge clk)begin
        if(reset)begin
            ss_tens <= 4'b0;
        end
        else if(ss_tens_ena)begin
            if(ss_tens_end)begin
                ss_tens <= 4'b0;
            end
            else begin
                ss_tens <= ss_tens + 4'b1;
            end
        end
    end
//分钟的个位计数
    always @(posedge clk)begin
        if(reset)begin
            mm_ones <= 4'b0;
        end
        else if(mm_ones_ena)begin
            if(mm_ones_end)begin
                mm_ones <= 4'b0;
            end
            else begin
                mm_ones <= mm_ones + 4'b1;
            end
        end
    end   
//分钟的十位计数
	always @(posedge clk)begin
        if(reset)begin
            mm_tens <= 4'b0;
        end
        else if(mm_tens_ena)begin
            if(mm_tens_end)begin
                mm_tens <= 4'b0;
            end
            else begin
                mm_tens <= mm_tens + 4'b1;
            end
        end
    end
//时钟的个位计数    
    always @(posedge clk)begin
        if(reset)begin
            hh_ones <= 4'd2;
        end
        else if(hh_ones_ena)begin
            if(hh_ones_0_end)begin
                hh_ones <= 4'b0;
            end
            else if(hh_ones_1_end)begin
                hh_ones <= 4'b1;
            end
            else begin
                hh_ones <= hh_ones+4'b1;
            end
        end
    end
//时钟的十位计数
    always @(posedge clk)begin
        if(reset)begin
            hh_tens <= 4'b1;
        end
        else if(hh_tens_ena)begin
            if(hh_tens_0_end)begin
                hh_tens <= 4'b0;
            end
            else if(hh_tens_1_end)begin
                hh_tens <= hh_tens + 4'b1;
            end
        end
    end
//pm跳转   
    always@(posedge clk)begin
        if(reset)begin
            pm_temp <= 1'b0;
        end
        else if(pm_inv)begin		//满足跳转条件则翻转
            pm_temp <= ~pm_temp;
        end
    end

endmodule

Timing Diagram
在这里插入图片描述

总结

1、 最后几题的代码是借鉴其他博主的,还要多看看,多练练
计数器这块都比较难,还是要多熟悉if-else 和例化的用法,多多练习
继续加油!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值