约翰逊计数器:实现循环计数的有效解决方案
一、基本原理
Johnson Counter,约翰逊计数器,是一种环形计数器,这种移位寄存器的主要优点是,与标准环形计数器相比,它只需要一半数量的触发器。“n级”约翰逊计数器将循环一个数据位,给出 2n 不同状态的序列,存在2n个模式的循环。
先简单介绍一下环形计数器:
环形计数器是由移位计数器加上一定的反馈电路构成的,用移位寄存器构成环形计数器的一般框图如图所示,它是由一个移位寄存器和一个组合反馈逻辑电路闭环构成,反馈电路的输出接向移位寄存器的串行输入端。

显而易见的是,这种方式极大的浪费了资源,N级的环形计数器计数长度为N,它有2^N-N个状态没有利用,它利用的有效状态很少。(4个触发器,计数长度只有4,效率低)
而约翰逊计数器的效率相比于环形计数器是大大增加的,计数长度是2N。
如图是约翰逊计数器的原理图:
和环形类似,只是改变了最后一个触发器的输出,改为取反,这使得反馈回路的输入发生变化。这种情况下的计数长度增倍。

二、基于verilog的实现
基于verilog的实现比较简单,这里以几种不同的方式描述一下。
思路一:移位寄存器
always语句示例如下:
always@(posedge clk or posedge rst)begin
if(rst) Q <= 0;
else Q <= {~Q[0], Q[3 : 1]};
end
思路二:状态机
三段式FSM,代码相对来说繁琐的多,不建议
parameter s0=0,s1=1,s2=2,s3=3,s4=4,s5=5,s6=6,s7=7;
reg [2:0] state,nextstate;
always @(posedge clk or posedge rst)
if(rst)
state<=0;
else
state<=nextstate;
always @(*)
case(state)
s0:nextstate<=s1;
s1:nextstate<=s2;
s2:nextstate<=s3;
s3:nextstate<=s4;
s4:nextstate<=s5;
s5:nextstate<=s6;
s6:nextstate<=s7;
s7:nextstate<=s0;
default:nextstate<=s0;
endcase
always @(*)
case(state)
s0:Q<=4'b0000;
s1:Q<=4'b1000;
s2:Q<=4'b1100;
s3:Q<=4'b1110;
s4:Q<=4'b1111;
s5:Q<=4'b0111;
s6:Q<=4'b0011;
s7:Q<=4'b0001;
default:Q<=4'b0000;
endcase
DONE!