基于Verilog语言设计移位计数器和模50的计数器。

基于Verilog HDL语言设计移位计数器和模50(十进制)计数器。

修改:

 修改时间:2020/08/19
 修改内容:这次的模50计数器生产了锁存器,修改代码见文章

内容说明:

介绍移位计数器的设计思想并提供设计代码和测试代码。介绍模50计数器的设计思想(也可以是任意两位数)并提供设计代码和测试代码。

移位计数器

移位计数器?

移位计数器就是输出结果实现移位功能,但是移动的方式由设计者自己设计。现在设计两种移位计数器,使用同一测试代码测试。最后,观察结果。

移位计数器设计代码:

移位方式:0001——0010——0100——1000

module counter_3 (clk,rst,q);
input		clk,rst;
output	[3:0]	q;
reg	[3:0]	q;

always @ (posedge clk)	//同步
//always @ (posedge clk or negedge rst)	//异步
begin
	if(!rst)
		q<=4'b0001;
	else
	begin
		q<=q<<1;
		q[0]<=q[3];
	end
end

endmodule

移位方式:0000——0001——0011——0111——1111——1110——···——0000

module counter_4 (clk,rst,q);
input		clk,rst;
output	[3:0]	q;
reg	[3:0]	q;

always @ (posedge clk)
//always @ (posedge clk or negedge rst)
begin
	if(!rst)
		q<=4'b0000;
	else
	begin
		q<=q<<1;
		q[0]<=~q[3];
	end
end

endmodule

测试代码:

module counter_3_4_tb;
reg		clk,rst;
wire	[3:0]	q1,q2;
counter_3 t1 (clk,rst,q1);
counter_4 t2 (clk,rst,q2);
initial
begin
	clk=0;rst=0;
#10	rst=1;
#45	rst=0;
//#30	rst=1;
#10	rst=1;
#100	rst=0;
#10	$stop;
end

always #6 clk=~clk;
endmodule

说明:

#45	rst=0;
//#30	rst=1;	//如果加上这个语句,可以采集到复位信号
#10	rst=1;

由于时钟周期是16个单位,如果复位信号低电平时间只能维持10个单位,那么是无法采集到这个复位信号。所以,如果想要采集到复位信号,必须要超过16个单位的时间。

仿真结果:

同步移位计数器复位信号没有采集到结果见图1-1;同步移位计数器复位信号采集到结果见图1-2;异步移位计数器结果见图1-3;异步移位计数器结果局部放大结果见图1-4。
同步移位计数器复位信号没有采集到
图1-1:同步移位计数器复位信号没有采集到结果
同步移位计数器复位信号采集到结果
图1-2:同步移位计数器复位信号采集到结果
异步移位计数器结果
图1-3: 异步移位计数器结果
异步移位计数器结果局部放大结果
图1-4:异步移位计数器结果局部放大结果

模50计数器

模50计数器介绍:

模50计数器是使计数器实现0-9-19-29-39-49的计数功能,并且在计数达到49时输出一个标志位。同时具有同步复位和同步置数的功能。
注:数字电路的输入和输出在计算机中都是二进制,结果当然也是以二进制的形式存在,这个“模50”就是将二进制转换为十六进制。出现的“0-9-19-29-39-49”均是十六进制。

模50计数器设计代码:

module counter_5 (clk,rst,run,load,data,q,cout);
input		clk,rst,run,load;
input	[7:0]	data;
output		cout;
output	[7:0]	q;
reg	[7:0]	q;
always @ (posedge clk)
begin
	if(rst) 	q<=0;
	else if (load)	q<=data;

	else if (run)
	begin
		if (q[3:0]==9)
		begin
			q[3:0]<=0;
			if(q[7:4]==4)	
				q[7:4]<=0;
			else			
				q[7:4]<=q[7:4]+1;
		end
		else
			q[3:0]<=q[3:0]+1;
	end
end

assign cout = ((q==8'h49)&run) ? 1:0;

endmodule

修改代码:

module counter_5 (clk,rst,run,load,data,q,cout);
input		clk,rst,run,load;
input	[7:0]	data;
output		cout;
output	[7:0]	q;
reg	[7:0]	q;
always @ (posedge clk)
begin
	if(rst) 	q<=0;
	else if (load)	q<=data;

	else if (run)
	begin
		if (q[3:0]==9)
		begin
			q[3:0]<=0;
			if(q[7:4]==4)	
				q[7:4]<=0;
			else			
				q[7:4]<=q[7:4]+1;
		end
		else
			q[3:0]<=q[3:0]+1;
	end
	else
		q[7:0] <= 8'h00;
end

assign cout = ((q==8'h49)&run) ? 1:0;

endmodule

注:虽然两次代码对仿真没有什么影响,但是当电路复杂时,这种错误是致命的!!!

测试模块:

module counter_5_tb;
reg		clk,rst,run,load;
reg	[7:0]	data;
wire		cout;
wire	[7:0]	q;
counter_5 t1 (clk,rst,run,load,data,q,cout);

initial
        	clk=0;
always #5       clk=~clk;

initial
begin
	rst=1;
#15	rst=0;
end

initial
begin
	load=0;data=8'h30;run=1;
#600	load=1;
#10	load=0;
#100	$stop;
end

endmodule

仿真结果:

实现0-49计数结果见图2-1;实现置数功能结果见图2-2。
实现0-49计数结果
图2-1:实现0-49计数结果
实现置数功能结果
图2-2:实现置数功能结果

总结:

移位计数器的关键在设计者如何实现自己的“移位想法”编程方法比较简单。十进制计数器的难点如何把“通俗语言”写成“Verilog代码”。无论是什么学科,都会有通俗易懂的描述和确定标准的描述,可以“表述”这些东西就是进步。

感想:

猜你喜欢

转载自blog.csdn.net/yixiaoyaobd/article/details/107993893