HDLBits中文版,标准参考答案 | 3.2.2 Counters | 计数器

关注 望森FPGA  查看更多FPGA资讯

这是望森的第 13 期分享

作者 | 望森
来源 | 望森FPGA

目录

1 Four-bit binary counter | 四位二进制计数器

2 Decade counter | 十进制计数器

3 Decade counter again | 十进制计数器

4 Slow decade counter | 慢速十进制计数器

5 Counter 1-12 | 计数器 1-12

6 Counter 1000 | 计数器 1000

7 4-digit decimal counter | 4 位十进制计数器

8 12-hour clock | 12 小时制时钟


本文中的代码都能够正常运行,请放心食用😋~

练习的官方网站是:https://hdlbits.01xz.net/

注:作者将每个练习的知识点都放在了题目和答案之后


1 Four-bit binary counter | 四位二进制计数器

题目:

构建一个 4 位二进制计数器,计数范围从 0 到 15(含 0 和 15),周期为 16。复位输入是同步的,应将计数器复位为 0。

答案:

我的答案:
module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);

    always@(posedge clk)begin
        if (reset | q == 4'd15)begin
            q <= 4'd0;
        end
        else begin
            q <= q + 1;
        end
    end
    
endmodule

参考答案:
module top_module(
        input clk,
        input reset,
        output reg [3:0] q);
        
        always @(posedge clk)
                if (reset)
                        q <= 0;
                else
                        q <= q+1;                // Because q is 4 bits, it rolls over from 15 -> 0.
                // If you want a counter that counts a range different from 0 to (2^n)-1, 
                // then you need to add another rule to reset q to 0 when roll-over should occur.
        
endmodule

知识点:

相比我的答案,参考答案更简洁,因为4bit的q最大计数值就为15,可以利用这一点简化代码。


2 Decade counter | 十进制计数器

题目:

构建一个十进制计数器,计数范围从 0 到 9(含 0 和 9),周期为 10。复位输入是同步的,应将计数器复位为 0。

答案:

我的答案:
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'd0;
        end
        else begin
            q <= q + 1;
        end
    end
    
endmodule

参考答案:
module top_module(
        input clk,
        input reset,
        output reg [3:0] q);
        
        always @(posedge clk)
                if (reset || q == 9)        // Count to 10 requires rolling over 9->0 instead of the more natural 15->0
                        q <= 0;
                else
                        q <= q+1;
        
endmodule

知识点:

参考答案使用的 if 判断条件是“(reset || q == 9)”,此处使用了逻辑运算符“||”,更加严谨。


3 Decade counter again | 十进制计数器

题目:

制作一个十进制计数器,计数范围从 1 到 10(含 10)。复位输入是同步的,应将计数器复位为 1。

答案:

module top_module (
    input clk,
    input reset,
    output [3:0] q);

    always@(posedge clk)begin
        if (reset | q == 4'd10)begin
            q <= 4'd1;
        end
        else begin
            q <= q + 1;
        end
    end
    
endmodule

4 Slow decade counter | 慢速十进制计数器

题目:

构建一个十进制计数器,计数范围从 0 到 9(含 0 和 9),周期为 10。重置输入是同步的,应将计数器重置为 0。我们希望能够暂停计数器,而不是始终在每个时钟周期递增,因此 slowena 输入指示计数器应何时递增。

答案:

module top_module (
    input clk,
    input slowena,
    input reset,
    output [3:0] q);

    always@(posedge clk)begin
        if (reset)begin
            q <= 4'd0;
        end
        else if (slowena)begin
            if (q == 4'd9)
                q <= 4'd0;
            else
                q <= q + 1;
        end
        else begin
            q <= q;
        end
    end
    
endmodule

5 Counter 1-12 | 计数器 1-12

题目:

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

  • Reset 同步高电平有效复位,将计数器复位为 1

  • Enable 设置为高电平以使计数器运行

  • Clk 正沿触发时钟输入

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

  • c_enable、c_load、c_d[3:0] 控制信号进入提供的 4 位计数器,以便验证操作是否正确。

您有以下可用组件:

  • 下面的 4 位二进制计数器 (count4),具有 Enable 和同步并行 load 输入(load的优先级高于 enable)。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 输入的信号。其目的是检查这些信号的正确性。

答案:

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(clk), 
        .enable(c_enable), 
        .load(c_load), 
        .d(c_d),
        .Q(Q)
    );
    
    assign c_enable = enable;
    assign c_load = reset | (Q == 4'd12 && enable);
    assign c_d = c_load ? 1'b1 : 1'b0;

endmodule

知识点:

本题的意思是通过实例化已有的计数器模块,实现目标的计数器功能,因此,使用逻辑设计例化模块的控制信号即可。


6 Counter 1000 | 计数器 1000

题目:

从 1000 Hz 时钟中导出一个 1 Hz 信号,称为 OneHertz,该信号可用于驱动一组小时/分钟/秒计数器的启用信号,以创建数字挂钟。由于我们希望时钟每秒计数一次,因此 OneHertz 信号必须每秒精确地断言一个周期。使用模 10 (BCD) 计数器和尽可能少的其他门构建分频器。还要从您使用的每个 BCD 计数器输出启用信号(c_enable[0] 表示最快的计数器,c_enable[2] 表示最慢的计数器)。

为您提供以下 BCD 计数器。计数器 enable 必须启用高电平。reset 是同步的,设置为高电平以强制计数器归零。电路中的所有计数器必须直接使用相同的 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,ten,hundred;
    bcdcount counter0 (clk, reset, c_enable[0] , one);
    bcdcount counter1 (clk, reset, c_enable[1] , ten);
    bcdcount counter2 (clk, reset, c_enable[2] , hundred);
    
    assign OneHertz = (hundred == 4'd9) && (ten == 4'd9) && (one == 4'd9);
    assign c_enable[0] = 1'b1;
    assign c_enable[1] = (one == 4'd9);
    assign c_enable[2] = (ten == 4'd9) && (one == 4'd9);

endmodule

知识点:

信号声明时,注意信号位宽。


7 4-digit decimal counter | 4 位十进制计数器

题目:

构建一个 4 位 BCD(二进制编码的十进制)计数器。每个十进制数字使用 4 位进行编码:q[3:0] 为个位数字,q[7:4] 为十位数字,等等。对于数字 [3:1],还输出一个使能信号,指示何时应增加上三位数字。

您可能想要实例化或修改一些一位十进制计数器。

答案:

module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);

    wire [3:0] one,ten,hundred,thousand;
    
    assign ena[1] = (one == 4'd9);
    assign ena[2] = (one == 4'd9) && (ten == 4'd9);
    assign ena[3] = (one == 4'd9) && (ten == 4'd9) && (hundred == 4'd9);
    assign q = {thousand,hundred,ten,one};
    
    countBCD10 count_one(
        .clk(clk),
        .slowena(1'b1),
        .reset(reset),
        .q(one)
    );
    
    countBCD10 count_ten(
        .clk(clk),
        .slowena(ena[1]),
        .reset(reset),
        .q(ten)
    );
    
    countBCD10 count_hun(
        .clk(clk),
        .slowena(ena[2]),
        .reset(reset),
        .q(hundred)
    );
    
    countBCD10 count_thou(
        .clk(clk),
        .slowena(ena[3]),
        .reset(reset),
        .q(thousand)
    );
    
endmodule

module countBCD10 (
    input clk,
    input slowena,
    input reset,
    output [3:0] q);

    always@(posedge clk)begin
        if (reset)begin
            q <= 4'd0;
        end
        else if (slowena)begin
            if (q == 4'd9)
                q <= 4'd0;
            else
                q <= q + 1;
        end
        else begin
            q <= q;
        end
    end
    
endmodule

8 12-hour clock | 12 小时制时钟

题目:

创建一组适合用作 12 小时时钟(带 am/pm 指示器)的计数器。计数器由快速运行的 clk 计时,每当您的时钟需要递增时(即每秒一次),ena 上都会发出脉冲。

reset 将时钟重置为 12:00 AM。pm 为 0 表示 AM,为 1 表示 PM。hh、mm 和 ss 分别是小时(01-12)、分钟(00-59)和秒(00-59)的两个 BCD(二进制编码十进制)数字。reset 的优先级高于 enable ,即使未启用也会发生。

以下时序图显示了从 11:59:59 AM 到 12:00:00 PM 的滚动行为以及同步重置和启用行为。

提示:

请注意,11:59:59 PM 会前进到 12:00:00 AM,而 12:59:59 PM 会前进到 01:00:00 PM。没有 00:00:00。

答案:

我的答案:
module top_module(
    input clk,
    input reset,
    input ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 

    //AM/PM
    always@(posedge clk)begin
        if (reset)
            pm <= 1'b0;
        else if (ena && (ss[7:4] == 4'd5 && ss[3:0] == 4'd9) && (mm[7:4] == 4'd5 && mm[3:0] == 4'd9) 
                 && (hh[7:4] == 4'd1 && hh[3:0] == 4'd1)) begin
            pm <= ~pm;
        end
    end
    
    //hour
    always@(posedge clk)begin
        if (reset)
            hh[3:0] <= 4'd2;
        else if (ena && (ss[7:4] == 4'd5 && ss[3:0] == 4'd9) && (mm[7:4] == 4'd5 && mm[3:0] == 4'd9)) begin
            if (hh[7:4] == 4'd1 && hh[3:0] == 4'd2)
                hh[3:0] <= 4'b1;
            else if (hh[7:4] == 4'd0 && hh[3:0] == 4'd9)
                hh[3:0] <= 4'b0;
            else
                hh[3:0] <= hh[3:0] + 1;
        end
    end
    
    always@(posedge clk)begin
        if (reset)
            hh[7:4] <= 4'd1;
        else if (ena && (ss[7:4] == 4'd5 && ss[3:0] == 4'd9) && (mm[7:4] == 4'd5 && mm[3:0] == 4'd9)) begin
            if (hh[7:4] == 4'd0 && hh[3:0] == 4'd9)
                hh[7:4] <= 4'b1;
            else if (hh[7:4] == 4'd1 && hh[3:0] == 4'd2)
                hh[7:4] <= 4'b0;
            else
                hh[7:4] <= hh[7:4];
        end
    end
    
    //minute
    always@(posedge clk)begin
        if (reset)
            mm[3:0] <= 4'b0;
        else if (ena && (ss[7:4] == 4'd5 && ss[3:0] == 4'd9)) begin
            if (mm[3:0] == 4'd9)
                mm[3:0] <= 4'b0;
            else
                mm[3:0] <= mm[3:0] + 1;
        end
    end
    
    always@(posedge clk)begin
        if (reset)
            mm[7:4] <= 4'b0;
        else if (ena && (ss[7:4] == 4'd5 && ss[3:0] == 4'd9) && (mm[3:0] == 4'd9)) begin
            if (mm[7:4] == 4'd5)
                mm[7:4] <= 4'b0;
            else
                mm[7:4] <= mm[7:4] + 1;
        end
    end
    
    //second
    always@(posedge clk)begin
        if (reset)
            ss[3:0] <= 4'b0;
        else if (ena) begin
            if (ss[3:0] == 4'd9)
                ss[3:0] <= 4'b0;
            else
                ss[3:0] <= ss[3:0] + 1;
        end
    end
    
    always@(posedge clk)begin
        if (reset)
            ss[7:4] <= 4'b0;
        else if (ena && ss[3:0] == 4'd9) begin
            if (ss[7:4] == 4'd5 && ss[3:0] == 4'd9)
                ss[7:4] <= 4'b0;
            else
                ss[7:4] <= ss[7:4] + 1;
        end
    end
    
endmodule

- END -

公z号/CSDN搜索【望森FPGA】,查看更多FPGA资讯~

相关推荐文章,点击跳转:

望森FPGA的HDLBits专栏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

望森FPGA

谢谢你的支持,这对我很重要~

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

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

打赏作者

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

抵扣说明:

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

余额充值