HDLBits(八)学习笔记——Counters(计数器)

Count15

构建一个 4 位二进制计数器,该计数器的计数范围为 0 到 15(包括 15),周期为 16。复位输入是同步的,应将计数器复位至0
在这里插入图片描述
改题目两个注意点:

  • 同步复位
  • 图片可知低电平有效
module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q
);

    always @ (posedge clk )begin
        if(reset)begin
            q <= 0;
        end
        else 
            q <= q+4'b1;
    end
endmodule

Count10

构建一个从 0 到 9(含)计数的十进制计数器,周期为 10。复位输入是同步的,应将计数器复位至0。
在这里插入图片描述
此题与上题的注意点相同,不同主要在于q为4位,如果不进行清零操作,那么就会一直计数到15,因此要想周期为10,就要计数到9的时候清零。

module top_module (
    input clk,
    input reset,        // Synchronous active-high reset
    output [3:0] q

);
        always @ (posedge clk )begin
        if(reset)begin
            q <= 0;
        end
            else if (q == 4'd9)begin //q >= 4'd9也可
                q <= 0;
            end
        else begin
                q <= q+4'b1;
        end
    end

endmodule

Count 1to10

制作一个十进制计数器,包括 1 到 10。复位输入是同步的,应将计数器复位至1
在这里插入图片描述
此题的区别在于计数器的初值从1开始。

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

Countslow

构建一个从 0 到 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 + 4'b1; 
            end
         else
             q <= q;
    end
endmodule

Count 1-12

设计具有以下输入和输出的 1-12 计数器

  • 重置同步****高电平有效复位,强制计数器为 1
  • enable信号设置为高电平以使计数器运行
  • 时钟正边沿触发时钟输入 Q[3:0]计数器的输出
  • c_enable、c_load、c_d[3:0]输出分别是进入内部计数器使能、负载和d输入的信号。它们的目的是允许检查这些信号的正确性。

您有以下可用的组件:4 位二进制计数器 (count4)
如下,它具有使能enable和同步并行加载输入load(load的优先级高于enable)。count4 模块可在电路中实例化它。

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

代码如下:

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'd12) && (enable == 1'b1));
    assign c_d = c_load ? 4'd1 : 4'd0;
    
endmodule

Count 1000

从 1000 Hz 时钟派生一个 1 Hz 信号(OneHertz)(计数到999),该信号可用于驱动一组小时/分钟/秒计数器的 Enable 信号,以创建数字挂钟。
由于我们希望时钟每秒计数一次,因此必须每秒精确地置位一个周期的一赫兹信号。使用模 10 (BCD) 计数器和尽可能少的其他门构建分频器。同时输出来自您使用的每个BCD计数器的使能信号(c_enable[0]表示最快的计数器,c_enable[2]表示最慢的计数器)。

为您提供以下BCD计数器。启用必须为高电平,计数器才能运行。复位是同步的,并设置为高电平以强制计数器为零。电路中的所有计数器必须直接使用相同的 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;
    wire[3:0]	ten;
    wire[3:0]	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 u_counter0 (clk, reset, c_enable[0],one );
    bcdcount u_counter1 (clk, reset, c_enable[1],ten);
    bcdcount u_counter2 (clk, reset, c_enable[2], hundred);

endmodule

Count bcd

构建一个 4 位数的 BCD(二进制编码的十进制)计数器。每个十进制数字使用4位进行编码:q[3:0]是1位,q[7:4]是十位,依此类推。对于数字 [3:1],还要输出一个使能信号,指示上三位数字中的每一位何时应递增。在这里插入图片描述
建议将if else的所有情况的输出都给出,避免锁存器的生成

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)
        ones <= 4'b0;
    else if(ones == 4'd9)
        ones <= 4'b0;
    else 
        ones <= ones + 4'b1;
        
end

//十位计数器
always @ (posedge clk)begin
    if(reset)
        tens <= 4'b0;
    else if(ones == 4'd9 && tens == 4'd9  )
        tens <= 4'b0;
    else if(ones == 4'd9)  
        tens <= tens + 4'b1;
    else
        tens <= tens;
        
end

//百位计数器
always @ (posedge clk)begin
    if(reset)
        hundreds <= 4'b0;
    else if(ones == 4'd9 && tens == 4'd9  && hundreds == 4'd9  )
        hundreds <= 4'b0;
    else if(tens == 4'd9 && ones == 4'd9)
        hundreds <= hundreds + 4'b1;
    else
        hundreds <= hundreds ;
        
end

//千位计数器
always @ (posedge clk)begin
    if(reset)
        thousands <= 4'b0;
    else if(ones == 4'd9&& tens == 4'd9  && hundreds == 4'd9 && thousands == 4'd9 )
        thousands <= 4'b0;
    else if(hundreds == 4'd9 && tens == 4'd9 && ones == 4'd9)
        thousands <= thousands + 4'b1;
    else
        thousands <= thousands;
        
end
//输出q为四个四位的个位,十位,百位,千位拼接,且题目给出是从低位到高位  
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

Count clock

创建一组适合用作 12 小时时钟使用的的计数器(带 am/pm 指示器)。您的计数器由clk驱动,时钟clk每增加一次,(即每增加秒一次),就会在ena上发出脉冲(1)。

复位信号可将时钟重置为 中午12时(12:00 AM)。上午pm 为 0(AM),下午pm 为 1。hh、mm 和 ss 是两个 BCD(二进制编码十进制)数字,分别表示小时 (01-12)、分钟 (00-59) 和秒 (00-59)。

复位信号的优先级高于ena,即使ena无效,也可能发生复位。

以下时序图显示了从AM 11:59:59 到PM 12:00:00 的翻转行为以及同步复位和使能行为。
在这里插入图片描述
其中 ss mm hh 均包含个位和十位,因此对于这三个信号我们要设计六个计数器。

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个位的暂存
    reg [3:0] ss_tens; // SS十位的暂存
    reg [3:0] mm_ones; // mm个位的暂存
    reg [3:0] mm_tens; // mm十位的暂存
    reg [3:0] hh_ones; // hh个位的暂存
    reg [3:0] hh_tens; // hh十位的暂存
    
    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
        else
            ss_ones <= ss_ones;
    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
       else 
             ss_tens <= ss_tens;
    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
        else 
            mm_ones <= mm_ones;
    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
        else
            mm_tens <= mm_tens;
    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
        else
            hh_ones <= hh_ones ;  
    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
        else
            hh_tens <= hh_tens ;
    end
    
    always@(posedge clk)begin
        if(reset)begin
            pm_temp <= 1'b0;
        end
        else if(pm_ding)begin
            pm_temp <= ~pm_temp;
        end
        else
           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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fighting_FPGA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值