基础单元-通用计数器
由于各个位数都是采用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时才输出进位。但是该写法进位会产生毛刺,如图:
但是该毛刺并不影响级联时功能的实现,原因还没找出,可能是因为该毛刺滞后于上升沿。
上述计数器的应用主要有以下两种:
-
对时钟进行计数
设置cin为1即可实现。注意不是cin=clk,这会导致输出一直为0,如下图所示。

但是cin = ~clk 可以实现,只不过引入了更多的门,因此不推荐。
-
级联实现倍数计数
两个计数器连接到同一个高频系统时钟clk,再将低位的出位Carry_out连接到高位的Carry_out即可。
复位到非零的计数器 --1to12计数器
在设计中注意到 12的下一位为1:
Note that
11:59:59 PMadvances to12:00:00 AM, and12:59:59 PMadvances to01: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
运行结果
-
HDLbits Success截图:

2. Quartus 仿真结果:

最后
以上就是着急红酒最近收集整理的关于HDLBits count clock(12-hour clock)基础单元-通用计数器最终连接完整代码运行结果的全部内容,更多相关HDLBits内容请搜索靠谱客的其他文章。

发表评论 取消回复