HDLBits count clock(12-hour clock)

基础单元-通用计数器

由于各个位数都是采用4位BCD码的编码方式,因此在这里考虑级联BCD计数器来实现。

由于模为60的BCD计数器可以通过模为6和模为10的计数器级联,模为12的可以考虑2*6,因此首先需要设计模为2,6,10的BCD计数器。

在这里参考

[如下博客]  https://blog.csdn.net/step__forward/article/details/124499102 

,应用带参数(parameter)的模块(module),通过修改参数来实现模不同的计数器,从而达到精简化代码的目的。代码如下:

module counter_4bit 
#( parameter    c_number = 4'd10)
(
    input       clk ,
    input       rst_n   ,
    input       cin ,
    output  reg cout    ,
    output  reg[3:0] q
);
always@(posedge clk )
begin
    if(rst_n)
        q <= 4'd0 ;
    else if(q == c_number-1'b1 && cin == 1'b1)
        q <= 4'd0 ;
    else if(cin == 1'b1)
        q <= q+1'b1;
    else    q <= q;
end
always@(*) begin
    if(q == c_number-1'b1 && cin == 1'b1)
        cout <= 1'b1;
    else    cout <= 1'b0;
end
endmodule
​

如上所设计模块为带进位的BCD计数器。

在大多数需要级联的计数器的设计中一般都会设计进位Carry_in与Carry_out ,因为若不使用Carry_in只使用Carry_out与时钟连接会导致reset信号可能在第二级就失效,若都不使用而使用输出q则只适用于模为2的n次方的计数器。这也是我在第一次尝试中失败的原因。

注意 :该写法中进位的状态转移进程不能用上升沿触发,因为两个进程是并行的,所以会在0时才输出进位。但是该写法进位会产生毛刺,如图:

 

但是该毛刺并不影响级联时功能的实现,原因还没找出,可能是因为该毛刺滞后于上升沿。

上述计数器的应用主要有以下两种:

  1. 对时钟进行计数

    设置cin为1即可实现。注意不是cin=clk,这会导致输出一直为0,如下图所示。

     但是cin = ~clk 可以实现,只不过引入了更多的门,因此不推荐。

  2. 级联实现倍数计数

    两个计数器连接到同一个高频系统时钟clk,再将低位的出位Carry_out连接到高位的Carry_out即可。

复位到非零的计数器 --1to12计数器

在设计中注意到 12的下一位为1:

Note that 11:59:59 PM advances to 12:00:00 AM, and 12:59:59 PM advances to 01:00:00 PM. There is no 00:00:00.

因此需要设计一个模为11,从1计数到12,复位到1的同步计数器。

在这里首先考虑将通用计数器更改为复位可调的计数器,即引入新的parameter,再进行级联。但是个位并不是每次2都会复位到1,因此需要在通用模块中添加输入信号十位数字来判断,这增加了设计中无用的逻辑门数量。因此在这里直接更改通用计数器的结构来实现最方便。代码如下:

module counter12 
#( parameter    c_number = {1'b1,4'd2})
(
    input       clk ,
    input       rst_n   ,
    input       cin ,
    output  reg cout    ,
    output  reg[4:0] q
    // 改为5位
);
always@(posedge clk)
begin
    if(rst_n)
        q <=  c_number ;
        // 更改复位数字
    else if(q == c_number && cin == 1'b1)
        q <= 5'd1 ;
        // 更改复位后的下一位
    else if(q == 5'd9 && cin == 1'b1)
        q <= {1'b1,4'd0} ;
        // BCD,跳过0x0A~0x0F
    else if(cin == 1'b1)
        q <= q+1'b1;
    else    q <= q;
​
    
end
​
always @(*) begin
        if(q == {1'b1,4'd1} && cin == 1'b1)
        // 计数器产生进位为最后一位,对应5,9
        cout <= 1'b1;
    else    cout <= 1'b0;
end
​
​
endmodule

最终连接

在级联时,注意根据题意处理好reset和ena的优先级,如下备注所示。因此不可用进位直连下一级。

最后,可以考虑到,pm就像小时的下一位,因此再使用一个counter2输出即可。

module top_module(input clk,
                  input reset,
                  input ena,
                  output pm,
                  output [7:0] hh,
                  output [7:0] mm,
                  output [7:0] ss);
​
    wire carryOutSS0,carryOutMM0,carryOutHH0 ;
    wire carryOutSS,carryOutMM,carryOutHH ;
​
    //assign clk0=clk&&ena;  
    //错误,因为reset有更高的优先级。上述写法会导致使能为低时的复位失效
    assign carryOutSS = carryOutSS0 && (ena);
    assign carryOutMM = carryOutMM0 && (ena);
    assign carryOutHH = carryOutHH0 && (ena);
​
​
    counter60 counterSS (clk , reset , ena ,carryOutSS0, ss);             
    counter60 counterMM  (clk , reset , carryOutSS ,carryOutMM0, mm);  
    counter12 countHH   (clk , reset , carryOutMM, carryOutHH0 , hh);
    
​
    counter_4bit
    #(.c_number(2))
    XM
    (
        .clk    (clk ),
        .rst_n  (reset),
        .cin    (carryOutHH ),
        .q      (pm)
    );
​
endmodule

完整代码

module top_module(input clk,
                  input reset,
                  input ena,
                  output pm,
                  output [7:0] hh,
                  output [7:0] mm,
                  output [7:0] ss);
​
    wire carryOutSS0,carryOutMM0,carryOutHH0 ;
    wire carryOutSS,carryOutMM,carryOutHH ;
​
    //assign clk0=clk&&ena;  
    //错误,因为reset有更高的优先级。上述写法会导致使能为低时的复位失效
    assign carryOutSS = carryOutSS0 && (ena);
    assign carryOutMM = carryOutMM0 && (ena);
    assign carryOutHH = carryOutHH0 && (ena);
​
​
    counter60 counterSS (clk , reset , ena ,carryOutSS0, ss);             
    counter60 counterMM  (clk , reset , carryOutSS ,carryOutMM0, mm);  
    counter12 countHH   (clk , reset , carryOutMM, carryOutHH0 , hh);
    
​
    counter_4bit
    #(.c_number(2))
    XM
    (
        .clk    (clk ),
        .rst_n  (reset),
        .cin    (carryOutHH ),
        .q      (pm)
    );
​
endmodule
​
​
​
module counter_4bit 
#( parameter    c_number = 4'd10)
(
    input       clk ,
    input       rst_n   ,
    input       cin ,
    output  reg cout    ,
    output  reg[3:0] q
);
always@(posedge clk )
begin
    if(rst_n)
        q <= 4'd0 ;
    else if(q == c_number-1'b1 && cin == 1'b1)
        q <= 4'd0 ;
    else if(cin == 1'b1)
        q <= q+1'b1;
    else    q <= q;
end
always@(*) begin
    if(q == c_number-1'b1 && cin == 1'b1)
        cout <= 1'b1;
    else    cout <= 1'b0;
end
endmodule
​
​
module counter60(
    input       clk  ,
    input       rst_n,
    input       cin  ,
    output      cout ,
    output  [7:0]   q
);
    wire    m1; 
counter_4bit       //对counter_4bit进行例化
#(.c_number(10))
u1
(
    .clk    (clk  ),
    .rst_n  (rst_n),
    .cin    (cin  ),
    .cout   (m1   ),
    .q      (q[3:0])
);
counter_4bit
#(.c_number(6))
u2
(
    .clk    (clk  ),
    .rst_n  (rst_n),
    .cin    (m1   ),
    .cout   (cout   ),
    .q      (q[7:4])
);
​
​
​
endmodule
​
​
module counter12 
#( parameter    c_number = {1'b1,4'd2})
(
    input       clk ,
    input       rst_n   ,
    input       cin ,
    output  reg cout    ,
    output  reg[4:0] q
    // 改为5位
);
always@(posedge clk)
begin
    if(rst_n)
        q <=  c_number ;
        // 更改复位数字
    else if(q == c_number && cin == 1'b1)
        q <= 5'd1 ;
        // 更改复位后的下一位
    else if(q == 5'd9 && cin == 1'b1)
        q <= {1'b1,4'd0} ;
        // BCD,跳过0x0A~0x0F
    else if(cin == 1'b1)
        q <= q+1'b1;
    else    q <= q;
​
    
end
​
always @(*) begin
        if(q == {1'b1,4'd1} && cin == 1'b1)
        // 计数器产生进位为最后一位,对应5,9
        cout <= 1'b1;
    else    cout <= 1'b0;
end
​
​
endmodule

运行结果

  1. HDLbits Success截图:

 

     2. Quartus 仿真结果:

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值