本次笔记记录的是计数器的使用
在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
仿真波形图:
异步计数:
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) );
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
波形图:
上图箭头所产生的时间极短的尖峰,在此可以不考虑,等后续笔记会做"竞争冒险"讲述
由于本人能力有限,出错之处的请各位给予帮助.谢谢!
更多资料参考
发烧友小梅哥专版 http://bbs.elecfans.com/zhuti_fpga_1.html
梦翼师兄的炼狱传奇
文章评论(0条评论)
登录后参与讨论