verilog手撕代码5——计数器(置位、加减、环形、扭环形、格雷码计数器实现)


前言

2023.5.12


一、二进制计数器(n位 2^n状态)

1.1 可置位计数器

编写一个十六进制计数器模块,计数器输出信号递增每次到达0,给出指示信号zero,当置位信号set 有效时,将当前输出置为输入的数值set_num
在这里插入图片描述
注意:这里zero=1和num=0是同一拍输出的,按道理如果根据num=0,然后去输出zero=1应该延迟一拍。所以这里考虑将number延迟一拍输出,就能和zero=1变化同步了。

module count_module(
	input clk,
	input rst_n,
	input set,
	input [3:0] set_num,
	output reg [3:0]number,
	output reg zero
	);
	reg [3:0] cnt;
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt<=0;
		else if(set)
			cnt<=set_num;
		else
			cnt<=(cnt==15)?0:cnt+1;
	end

	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			zero<=0;
		else 
			zero<=(cnt==0)?1:0;
	end

	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			number<=0;
		else 
			number<=cnt;
	end
endmodule

1.2 加减计数器

一个十进制计数器模块,当mode信号为1,计数器输出信号递增,当mode信号为0,计数器输出信号递减。每次到达0,给出指示信号zero。

module count_module(
	input clk,
	input rst_n,
	input mode,
	output reg [3:0]number,
	output reg zero
	);
    
    reg[3:0] number1;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            number1<=0;
        end
        else if(mode)
        	number1<=(number==9) ? 0 : number1+1;
        else if(~mode)       
            number1<=(number==0) ? 9 : number1-1;
        else
            number1<=number1;
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            number<=0;
        else
            number<=number1;
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            zero<=0;
        else if(number1==0)
            zero<=1;
        else
            zero<=0;
    end    
endmodule

二、环形计数器(n位 n状态)

0001-0010-0100-1000-0001
独热码,相邻两位之间会有两位不相同

优点:

  • 状态译码简单,设计简单,修改灵活

缺点:

  • 有许多无限状态
reg [3:0] count;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		count <= 4‘b0001;   //注意复位状态
	else
		count <= {count[2:0], count[3]};  //向左依次循环
end

2.1 移位寄存器首尾相连构成环形计数器

这种电路的问题在于自锁,无法自启动
在这里插入图片描述

对输出端进行反馈到输入,把Q2、Q1、Q0或非接到D0端,这样就能自启动了。

在这里插入图片描述

状态转移图如下所示。

在这里插入图片描述

三、扭环形计数器/Johnson计数器(n位 2*n状态)

1000-1100-1110-1111-0111-0011-0001-0000-1000
相邻两个数之间只有1bit位不同,比较可靠,不存在竞争冒险

reg [3:0] count;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		count <= 0;
	else
		count <= {~count[0], count[3:1]}; //这里是往右循环的计数
end

3.1 移位寄存器来构成扭环形计数器

在这里插入图片描述

在这里插入图片描述

四、格雷码计数器

分为三个部分:格雷码转二进制、二进制加法、二进制转格雷码。

module gray_counter(
   input   clk,
   input   rst_n,

   output  reg [3:0] gray_out
);

	reg [3:0] bin;
	wire [3:0] gray_r;
	reg [3:0] bin_add;
	
	always@(posedge clk or negedge rst_n)begin
	    if(!rst_n)
	        bin<=0;
	    else begin
	        bin[3]=gray_r[3];
	        bin[2]=gray_r[2]^bin[3];
	        bin[1]=gray_r[1]^bin[2];
	        bin[0]=gray_r[0]^bin[1];
	    end
	end
	
	always@(posedge clk or negedge rst_n)begin
	    if(!rst_n)
	        bin_add<=0;
	    else 
	        bin_add<=bin+1'b1;
	end
	
	assign gray_r = (bin_add>>1) ^ bin_add;
	
	always@(posedge clk or negedge rst_n)begin
	    if(!rst_n)
	        gray_out<=0;
	    else 
	        gray_out<=gray_r;
	end
endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值