HDL Bits(Counters答案)

文章详细介绍了如何设计4位二进制计数器、十进制计数器,以及包含不同条件的高级计数器,如计数范围、同步复位和多路复用输入等。讲解了计数器的基本结构和逻辑顺序,包括清零、复位和计数的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本节为时序电路的设计,需要重点掌握。

第一题:4-bits binary counters:

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

正确答案:

时序电路中,我总结了一个这样的习惯:

先设置清零的条件、其次为复位的条件、最后为计数(else);

注意在时序电路中如果要给输出赋值,应该使用<=符号,一般逻辑赋值语句使用=;

该题正确答案:因为该题的最大值即15,无需设置复位,4bits直接就是0-15;

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

第二题:count10:

构建一个从0到9(包括9)的十进制计数器,周期为10。复位输入是同步的,应该将计数器复位为0。上题已经讲过:一般时序电路我们可以以清零、复位(或进一)、计数(else)的逻辑先后顺序来进行。

正确答案:

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

解析:第一个if是清零信号,当reset==1时,可使q<=0;

第二个else if是复位信号,当q[3:0]==9时(注意4'd9指的是该位为4bits,d指的是十进制,9为十进制中的9)。

第三个else 指的是其他情况下(posedge clk)都可以进行计数。

本题也可以将清零和复位信号结合起来:


    always@(posedge clk)begin
        if(reset||q[3:0]==4'd9)begin
            q[3:0]<=0;
        end
        else begin
            q[3:0]<=q[3:0]+4'b1;
        end 
    end

第三题:Count1to10:

制作一个从1数到10的10秒计数器。复位输入是同步的,应该将计数器复位为1。

正确答案:

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

第四题:Countslow:

本题需要在slowena为1时才能计数,所以计数的该条件(slowena==1)为置数和计数的必要条件。

正确答案:

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

endmodule

第五题:exams:

设计1-12计数器,要求如下:

Reset同步活动高电平复位,强制计数器为1;

设置计数器运行的高值;

Clk正极触发时钟输入;

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

c_enable, c_load, c_d[3:0]进入提供的4位计数器的控制信号,因此可以验证正确的操作。

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, c_enable, c_load, c_d,Q);
    assign c_enable = enable;
    assign c_load =reset||((enable)&&(Q[3:0]==4'd12));
    assign c_d = c_load?4'd1:4'd0;
endmodule

第六题:Counter1000

正确答案:

module top_module (
    input clk,
    input reset,
    output OneHertz,
    output [2:0] c_enable
); //
    
    wire [3:0]a,b,c;
    
    assign OneHertz = (a[3:0]==4'd9)&&(b[3:0]==4'd9)&&(c[3:0]==4'd9);
    assign c_enable = {(a[3:0]==4'd9&&b[3:0]==4'd9),(a[3:0]==4'd9),1'b1};

    bcdcount counter0 (clk, reset, c_enable[0],a);
    bcdcount counter1 (clk, reset, c_enable[1],b);
    bcdcount counter2 (clk, reset, c_enable[2],c);  //分频器大概是把1000分成三部分的

endmodule

第七题:CountBCD:

构建一个4位BCD(二进制编码的十进制)计数器。每个十进制数字用4位编码:q[3:0]是个位数,q[7:4]是十位,等等。对于数字[3:1],还输出一个enable信号,指示何时应增加前三位数字中的每一位。enable信号有三位,其实就是这个四位数的前面三位一个一个地进位,个位进位使enable[1]=1;十位进位使enable[2]=1,以此类推。

您可以实例化或修改一些十位计数器。

先尝试写出来:

正确答案:
 

module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);
    
    
    //分开写,千位
    always@(posedge clk)begin
        if(reset)begin
            q[15:12]<=0;
        end
        else if(q[15:12]==4'd9&&q[11:8]==4'd9&&q[7:4]==4'd9&&q[3:0]==4'd9)begin
                q[15:12]<=0;
             end
        else if(q[11:8]==4'd9&&q[7:4]==4'd9&&q[3:0]==4'd9)begin 
             q[15:12]<=q[15:12]+1'b1;
             end
    end
    
    //百位:
        always@(posedge clk)begin
        if(reset)begin
            q[11:8]<=0;
        end
            else if(q[11:8]==4'd9&&q[7:4]==4'd9&&q[3:0]==4'd9)begin
                q[11:8]<=0;
             end
            else if(q[7:4]==4'd9&&q[3:0]==4'd9)begin 
                q[11:8]<=q[11:8]+1'b1;
             end
    end
    //十位
        always@(posedge clk)begin
        if(reset)begin
            q[7:4]<=0;
        end
            else if(q[7:4]==4'd9&&q[3:0]==4'd9)begin
            	q[7:4]<=0;
             end
            else if(q[3:0]==4'd9)begin 
                q[7:4]<=q[7:4]+1'b1;
             end
    end
    
    //个位:
        always@(posedge clk)begin
        if(reset)begin
            q[3:0]<=0;
        end
            else if(q[3:0]==4'd9)begin
                q[3:0]<=0;
             end
            else begin q[3:0]<=q[3:0]+1'b1;
             end
    end
    
    assign ena[1] = q[3:0]==4'd9;
    assign ena[2] = q[7:4]==4'd9&&ena[1];
    assign ena[3] = q[11:8]==4'd9&&ena[2];

endmodule

第八题:Count Clock

本题要求:

  创建一组适合作为12小时时钟使用的计数器(带有am/pm指示器)。您的计数器由一个快速运行的时钟进行计时,每当您的时钟应该增加时(即每秒一次),就会有一个脉冲。

  reset将时钟重置到12:00 AM。pm是0表示AM, 1表示pm。hh、mm和ss是两个BCD(二进制编码十进制)数字,分别表示小时(01-12)、分钟(00-59)和秒(00-59)。Reset具有比enable更高的优先级,并且即使在未启用时也可能发生。

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

正确答案:

PM的翻转模块,该模块仅仅是判断十二点时的早晚状态的,所以只需要写关于11:59:59&&ena的逻辑便可,再将值赋到output PM 上。

然后即秒个位(ena2_ss)、秒十位(ena1_ss)、分个位(ena2_mm)、分十位(ena1_mm)的逻辑编写,大同小异,都是在前一个位数满足跳变的基础上再加上ena电平给这个判断成功条件;如分个位(ena2_mm)是ena&&秒设置为59才可以触发。我在其中为了使代码看起来更简洁,将一些条件赋值为wire中间向量了。

其中时的设计有些难写,首先要满足假如时钟点为12的时候,计数器就变成01,然后再是判断ena&&09:59:59的复位情况,这种情况ena&&9X"59"59与情况12无关,所以我们要分开判断,不能在条件里嵌套,不然会非常混乱。

最后才是计数的判断,是出复位判断以外的ena&&09"59"59的条件,这是复位情况的母条件,所以可以嵌套来写。

整体就是这样的思路:需要注意的是,你必须将分、秒的个位十位都分开写,逻辑思路清晰的前提下,可以尽可能地使用赋值语句使代码更简洁,最后就是翻转模块。

正确答案:

module top_module(
    input clk,
    input reset,
    input ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 
    //思路:pm模块、时、分、秒十位个位分写的逻辑模块
    
    //声明部分:
    //1指的是十位的使能、复位、翻转
    wire [3:0]ena1_ss,end1_ss;//秒的十位
    wire [3:0]ena1_mm,end1_mm;//分的十位
    wire [3:0]ena1_hh,end1_hh;//包括使能键、复位键、翻转键,时的十位
    
    //2指的都是个位的使能、复位、翻转
    wire [3:0]ena2_ss,end2_ss;//秒的十位
    wire [3:0]ena2_mm,end2_mm;//分的十位
    wire [3:0]ena2_hh,end2_hh;//包括使能键、复位键\时的十位

    
    reg ena_pm;//时置一的信号
    wire ss1,ss2,mm1,mm2,hh1;
     
    
    assign ena2_ss = ss[3:0];
    assign ena1_ss = ss[7:4];
    assign ena2_mm = mm[3:0];
    assign ena1_mm = mm[7:4];
    assign ena2_hh = hh[3:0];
    assign ena1_hh = hh[7:4];

    
    
    assign ss1 = ena2_ss==4'd9;
    assign ss2 = ss1&&ena1_ss==4'd5;
    assign mm1 = ss2&&ena2_mm==4'd9;
    assign mm2 = mm1&&ena1_mm==4'd5;
    assign hh1 = mm2&&ena2_hh==4'd9;

       
   //时、分、秒
    always@(posedge clk)begin //时针的十位
        if(reset)begin //清零
            hh[7:4]<=1;
        end
        else if(ena2_hh==4'd2&&ena1_hh==4'd1&&ena&&mm2)begin
            hh[7:4]<=4'd0;
        end
        else if(ena&&hh1)begin //复位、翻转
            if(ena1_hh==4'd9)begin
            hh[7:4]<=4'd0;
            end
          else begin //计数
                hh[7:4]<=hh[7:4]+1'b1;
            end
        end
    end
        
    
    always@(posedge clk)begin //时针的个位
        if(reset)begin //清零
            hh[3:0]<=2;
        end
        else if(ena&&mm2&&ena2_hh==4'd2&&ena1_hh==4'd1)begin //复位、翻转
            hh[3:0]<=4'd1;
        end
        else if(ena&&mm2)begin
            if(ena2_hh==4'd9)begin
                hh[3:0]<=4'd0;
            end
        else begin //计数
            hh[3:0]<=hh[3:0]+1'b1;
            end
     end
   end
    
    
    
    always@(posedge clk)begin //分针的十位
        if(reset)begin //清零
            mm[7:4]<=0;
        end
        
        else if(ena&&mm1)begin //复位、进一
            if(ena1_mm==4'd5)begin
            mm[7:4]<=4'd0;
            end
            else begin //计数
            mm[7:4]<=mm[7:4]+1'b1;
            end
        end
    end
    
    
    always@(posedge clk)begin //分针的个位
        if(reset)begin //清零
            mm[3:0]<=0;
        end
        else if(ena&&ss2)begin 
            if(ena2_mm==4'd9)begin//复位、进一
            mm[3:0]<=4'd0;
            end
            else begin //计数
            mm[3:0]<=mm[3:0]+1'b1;
            end
        end
    end
    
    
    always@(posedge clk)begin //秒针的十位
        if(reset)begin //清零
            ss[7:4]<=0;
        end
        else if(ena&&ss1)begin 
            if(ena1_ss==4'd5)begin//复位、进一
            ss[7:4]<=4'd0;
            end
            else begin //计数
            ss[7:4]<=ss[7:4]+1'b1;
            end
        end
    end
    
    always@(posedge clk)begin //秒针的个位
        if(reset)begin //清零
            ss[3:0]<=0;
        end
        else if(ena)begin
            if(ss1)begin //复位、进一
                ss[3:0]<=4'd0;
            end
            else begin //计数
                ss[3:0]<=ss[3:0]+1'b1;
            end
        end
    end
    
    //ena_pm模块

    // PM位 		start
    always @(posedge clk) begin
        if (reset) begin
            pm <= 0;
        end
        else if (ena_pm) begin
            pm <= ~pm;				// pm信号翻转
        end
    end
    assign ena_pm = (ena&&mm2)&&(hh[7:4]==4'd1) && (hh[3:0]==4'd1);
endmodule

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值