Augus

7.菜鸟初入FPGA之同步和异步计数器的使用

0
阅读(5492)


本次笔记记录的是计数器的使用

  在FPGA设计中,计数器的使用占据很大的比重,在后面接触的FPGA设计的,总少不了计数器的身影,有时候计数器的性能决定了一个项目的成败,本笔记中,我做了两种计数器的设计:第一种就是综合工具自动综合出来的计数器.第二种就是使用 IP 核的计数器


如果按照计数器中的触发器是否同时翻转分类,可将计数器分为同步计数器和异步计数器两种。

1.基本概念:每个不同的计数器,在设计之初,被设计者设定为感应固定的波形的某一部分(一般为瞬态感应),比如方波的下降沿(或上升沿);

2.同步计数:当你所购得的计数器为同步计数器,所谓同步,就是该计数器只有当输入信号的下降沿(或上升沿)来临时,计数器才会开始处理,其他时间无论高低电平,计数器都会无视;

3.异步计数:所谓异步,就是你随时达到所设定的值,它立刻就跳转,并不等待下一个下降沿(或上升沿)的到来;

综上可以看出,同步,异步说的都是相对于输入信号,计数器在达到最大计数值时的响应是同步于该输入信号,还是异步于它;


下面我们先分别看一下同步计数器和异步计数器的实现

同步计数器:

module counter(rst_n,clk,out_cnt);
input clk;
input rst_n;
output reg out_cnt;
reg [7:0]cnt;
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt <= 8'd0;
else if(cnt == 8'd125)
cnt <= 8'd0;
else
cnt <= cnt + 1'b1;
always @(posedge clk or negedge rst_n)
if(!rst_n)
out_cnt <= 1'b1;
else if(cnt == 8'd125)
out_cnt <= ~out_cnt;
else
out_cnt <= out_cnt;
endmodule

///////////////////`tb
`timescale 1ns/1ns
`define clock_period 20
module counter_tb;
reg clk;
reg rst_n;
wire out_cnt;

counter counter(.rst_n(rst_n),.clk(clk),.out_cnt(out_cnt));

initial clk = 1;
always #(`clock_period/2) clk = ~clk;
initial begin
rst_n = 1'b0;
#(`clock_period *20);
rst_n = 1'b1;
#(`clock_period *2000);
$stop;
end
endmodule

仿真波形图:

2016-03-27_111244.jpg

异步计数:

module asyn_counter(rst_n,clk,out_cnt,asyn_out);
	input clk;
	input rst_n;
	output reg out_cnt;
	output reg asyn_out;
	
	reg [7:0]cnt;
	
	always @(posedge clk or negedge rst_n)
		if(!rst_n) 
			cnt <= 8'd0;
		else if(cnt == 8'd125)
			cnt <= 8'd0;	
		else 
			cnt <= cnt + 1'b1;
			
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		out_cnt <= 1'b1;
	else if(cnt == 8'd125) 
		out_cnt <= ~out_cnt;
	else
		out_cnt <= out_cnt;
	
	//always @(clk or rst_n)	
	always @(cnt)
	if(!rst_n)
		asyn_out <= 1'b1;
	else if(cnt == 8'd125) 
		asyn_out <= ~asyn_out;
	else
		asyn_out <= asyn_out;
endmodule 


//////`tb 更改一下例化就行了
asyn_counter counter(
	.rst_n(rst_n),
	.clk(clk),
	.out_cnt(out_cnt),
	.asyn_out(asyn_out)
	);	

2016-03-27_121402.jpg


IP 核的计数器

ip核设置如下(Quartus 15.0):


计数到100清零,此程序中 carry_in /out 可以不选

如上图打开 可以找到例化模块  counter(.........)

设置ip/counter.qip为顶层文件

仿真代码:

`timescale 1ns/1ns
`define clock_period 20
module counter_tb;
	reg cin;	//进位输入
	reg clk;	//计数基准时钟	
	wire cout;//进位输出
	wire [7:0] q;

	counter counter0(
		.cin(cin),
		.clock(clk),
		.cout(cout),
		.q(q)
	);
	
	initial clk = 1;
	always #(`clock_period/2)clk = ~clk;	
	initial begin
		repeat(300)begin   //
			cin = 0;
			#(`clock_period*5)cin = 1;
			#(`clock_period)cin = 0;		
		end
		#(`clock_period*200);
		$stop;
	end
endmodule

波形图:

2016-03-27_125935.jpg

上图箭头所产生的时间极短的尖峰,在此可以不考虑,等后续笔记会做"竞争冒险"讲述



由于本人能力有限,出错之处的请各位给予帮助.谢谢!


 更多资料参考

                发烧友小梅哥专版 http://bbs.elecfans.com/zhuti_fpga_1.html

                   梦翼师兄的炼狱传奇