原文链接

本文讲解了上述6种计数器,部分计数器的源代码可以在公众号(IC媛)回复“计数器”获得。

一、常规带使能计数器
以带使能的模100异步清零计数器为例

1、设计文件

module cnt #(parameter COUNT=100)(
input clk,
input rst_n,
input cnt_en,
output reg [6:0]out//如果参数化中COUNT比较大,需要更改out的位宽来适配
    );
reg flg;	
always@(posedge clk or negedge rst_n)//异步清零
if(!rst_n)begin out<=7'd0;flg<=1'b0;end
else if(cnt_en)begin
//写法1if(out!=COUNT-1)begin
			out<=out+1'b1;flg<=1'b0;end
		else begin out<=7'd0;flg<=1'b1;end
/* 		
//写法2if(out==COUNT-1)
			begin out<=7'd0;flg<=1'b1;end
		else begin  out<=out+1'b1;flg<=1'b0;   end */
	end
else begin out<=7'd0;flg<=1'b0;end	//maybe

endmodule 

2、仿真文件

module cnt_tst();

reg       clk     ;
reg       rst_n   ;
reg       cnt_en  ;
wire [6:0]out     ;

cnt U_cnt(
.clk     (clk    ),
.rst_n   (rst_n  ),
.cnt_en  (cnt_en ),
.out     (out    )
);

initial
begin
clk=1;
rst_n=0;
cnt_en=0;
#10 rst_n=1;
cnt_en=1;
# 2000 cnt_en=0;
# 200 cnt_en=1;
#4000 cnt_en=0;
end
always #10 clk=~clk;


endmodule


二、加法减法计数器

module add_sub_cnt(
input clk,
input rst_n,
input [1:0]cnt_ctr,
output reg [2:0]cnt
    );
	
always@(posedge clk or negedge rst_n)
if(!rst_n)	
	cnt<=3'd0;
else begin
if(cnt_ctr==2'b00||cnt_ctr==2'b11)
	cnt<=cnt;
else if(cnt_ctr==2'b01)
	cnt<=cnt+1'b1;
else if(cnt_ctr==2'b10)
	cnt<=cnt-1'b1;
end
endmodule


三、环形计数器

环形计数器,n个触发器表示n个状态。所谓环形如下图所示,是指图中的“1”,在每一组数中出现的位置形成的效果图,像一个环一样,依次循环,以4bit环形计数器为例子,“1”的位置依次在第0bit、第1bit,第2bit,第3bit,再回到第0bit,依次类推,就像一个环。如 4bit环形计数器:复位有效时输出0001,复位释放后依次输出0010,0100,1000,0001,0010…,如下图所示:

1、设计文件

//环形计数器
module ring_counter#(parameter word_size=4)(
input clk,
input rst_n,
input enable,
output reg [word_size-1:0]count
);
always@(posedge clk,negedge rst_n)
if(!rst_n)count<={
   {
   (word_size-1){
   1'b0}},1'b1};
else if(enable==1'b1)count<={
   count[word_size-2:0],count[word_size-1]};
endmodule

2、仿真文件

module ring_counter_tst #(parameter word_size=4)();
reg clk;
reg rst_n;
reg enable;
wire [word_size-1:0]count;
ring_counter U_ring_counter(
.clk   (clk),
.rst_n (rst_n),
.enable(enable),
.count (count)
);    
 initial
 begin
 clk=0;
 rst_n=0;
 enable=0;
 #20 rst_n=1;
 #20 enable=1;

 end 
  
always #10 clk=~clk; 
    
endmodule


四、约翰逊计数器

约翰逊(Johnson)计数器又称扭环计数器,是一种用n位触发器来表示2n个状态的计数器。约翰逊(Johnson)计数器有一个非常明显地好处,相邻两组数只有一位不同,具体如下例子所示,因此在计数过程中不会存在竞争冒险问题。

以4bit约翰逊(Johnson)计数器为例,4bit约翰逊(Johnson)计数器,能表示8种状态,相邻两组数之间,仅有1bit不同:

0000 1000 1100 1110 1111 0111 0011

0001 0000 1000

为什么叫扭环形呢?小编的理解:相邻两组数的变化很像是扭了一下,如上图中1000 和1100,将1000的高三位放在1100中的低三位,再将1000中最低位0取反,放到1100中的最高位。
1、设计文件

参数化代码,位宽可以根据需求进行修改

module johnson_counter#(parameter WIDTH = 4)(
input clk,
input rst_n, 
output reg [WIDTH-1:0] cnt
);
  
  always@(posedge clk or negedge rst_n) begin
    if(!rst_n)
      cnt <= {
   WIDTH{
   1'b0}};
    else
      cnt <= {
   ~cnt[0],cnt[WIDTH-1:1]};
  end
endmodule

2、仿真文件

module johnson_counter_tst #(parameter WIDTH = 4)();
reg clk;
reg rst_n;
wire [WIDTH-1:0] cnt;

johnson_counter U_johnson_counter(
. clk(clk),
. rst_n(rst_n), 
. cnt(cnt)
);

initial
begin
clk=0;
rst_n=0;
#20 rst_n=1;

end

always #10 clk=~clk;
   
endmodule


这部分内容还可以去看这篇文章:https://mp.weixin.qq.com/s/0EDciIhtxLbVs6fg5aGFKw

五、线性反馈移位计数器(LFSR计数器)

以下内容来源于书籍《高级数字系统设计技术与实例分析》P73

LFSR计数器通过重复出现的某个随机序列作为实现计数器的基础。与常规计数器不同,它不进行常规的加法计数和减法计数。它由一组级联的移位寄存器加上异或门或者异或非门构成的反馈构成。下面给出LFSR计数器的特点、优点及不足。
(1)LFSR计数器工作速度更快,因为触发器之间不需要太多的组合逻辑。

(2)计数序列是随机的。例如,一个3位LFSR计数器的技术序列可能为001、110、011、111、101、100、010,它不是按照二进制计数方式增加的(001、010、011、100、101、110、111)。

(3)如果只使用最终的计数值来触发设计者所需要的的操作,那么LFSR计数器所输出的随机序列不会造成使用困难,但如果需要使用多个中间计数值,那么这种随机序列将会造成应用上的困难。

(4)计数器的计数序列通常具有(2n-1)种状态。但是,它可以被设计成具有2n个状态的计数器,此时需要使用n+1个触发器,然后截短输出序列。

(5)LFSR可以使用XOR反馈或者XNOR反馈。当使用XOR反馈时,全零(例如,3位LFSR为000)是一个非法的状态。同样,当使用XOR反馈时,全1是一种非法的状态。

(6)存在两种类型的LFSR(多到一,一到多)。对于多到一类型的,多个触发器的输出进行异或运算,输出结果进入一个寄存器。对于一到多类型的,一个触发器的输出进入异或函数,计算结果驱动多个触发器。

斐波那契LFSR也可称为多到一型LFSR,即多个触发器的输出通过异或逻辑来驱动一个触发器的输入。伽罗瓦LFSR为一到多型LFSR,即一个触发器的输出通过异或逻辑驱动多个触发器的输入。


上面两个图中的序列移动,建议大家自己动手推导一遍。

(7)一到多类型的LFSR能够具有比多到一类型的LFSR更快的工作速度,因为它需要的组合逻辑级数更少。

1、设计文件

以下为4位伽罗瓦LFSR计数器的verilog代码实现:

module lfsr_counter(
input clk,
input rst_n,
input new_cntr_preset,
output out
    );
wire [3:0]lfsr_cnt_xor;
reg [3:0]lfsr_cnt,lfsr_cnt_nxt;
assign lfsr_cnt_xor[0]=lfsr_cnt[1];
assign lfsr_cnt_xor[1]=lfsr_cnt[2];
assign lfsr_cnt_xor[2]=lfsr_cnt[3]^lfsr_cnt[0];
assign lfsr_cnt_xor[3]=lfsr_cnt[0];

always@(*)	
begin
	if(new_cntr_preset)
		lfsr_cnt_nxt=4'b1111;
	else lfsr_cnt_nxt=lfsr_cnt_xor;


end


always@(posedge clk or negedge rst_n)
	if(!rst_n)
		lfsr_cnt<=4'b1111;
	else lfsr_cnt<=lfsr_cnt_nxt;
assign out =(lfsr_cnt==4'b0111);
	
endmodule


2、仿真文件

module lfsr_counter_tst();
reg clk;
reg rst_n;
reg new_cntr_preset;
wire out;

lfsr_counter U_lfsr_counter(
.clk            (clk            ),
.rst_n          (rst_n          ),
.new_cntr_preset(new_cntr_preset),
.out            (out            )
    );

initial
begin
clk=1;
rst_n=0;
new_cntr_preset=0;
#20 rst_n=1;
#200
new_cntr_preset=1;
#20
new_cntr_preset=0;


end


always #10 clk=~clk;

endmodule



从图可得,波形图中的lfsr_cnt[3:0]的值和图4为伽罗瓦计数器是匹配的。

六、低功耗可恢复计数器

在网上看到有人面试华为的时候遇到让写低功耗可恢复计数器的,具体题目细节,小编也不知道,但是把题目提供给大家,在今后的学习中可以留心一下。

大家对文章中的内容如果有疑问,欢迎留言,我们看到了会给大家解答的。也欢迎大家加入下面的qq群或者添加IC媛加入微信群进行讨论交流!