介绍
计数器电路是在数字电子技术中应用的最多的时序逻辑电路。计数器不仅能用于对时钟脉冲计数,还可以用于分频、定时、产生节拍脉冲和脉冲序列以及进行数字运算等。
在许多大型电路中必然有计数器电路的身影,可以说了解并掌握计数器的设计方法是学习fpga的第一步。
本文使用的软件是Quartus II 13.1、modelsim和notepad++,开发板是黑金的AX301。
- 下图是计数器的基本设计流程。
1.创建项目文件夹
首先我们先创建一个存放项目的文件夹:
再分别在counter内创建用来存放工程文件、rtl代码和波形图的文件夹:
然后,打开Quartus II软件,新建一个工程文件并存放在我们刚刚建立好的prj文件夹中,命名为counter
我们使用的开发板是黑金AX301搭载的是Cyclone IV E系列的EP4CE6F17C8,选择对应的型号。
为了方便后续的仿真,我们先将仿真软件设置为Modelsim语言为Verilog HDL
2.绘制波形图
对于计数器这个时序逻辑电路来说,需要时钟的驱动,复位方式选择异步复位。
同时,需要定义一个变量cnt来对时钟进行计数(后续需要利用LED来验证代码,此处先将cnt的位宽设置为25),计数值满时将flag进行取反。
最后将文件存放在visio文件夹中
3.编写rtl代码
我们在rtl文件夹下建立名为counter的.v文件
notepad++ 是一款小巧且好用的代码编辑软件,我们在language选项中勾选Verilog语言。
可以看到,notepad++ 对 Verilog语言有了关键字提示。
编写代码如下:
module counter
(
input sys_clk ,
input sys_rst_n, //输入端口为时钟和复位信号
output reg flag //输出端口为计数器计满时的标志信号
);
parameter CNT_MAX = 24_999; //定义计数最大值,方便后续修改
reg [24:0] cnt; //声明一个25位宽的变量cnt
always@(posedge sys_clk or negedge sys_rst_n) //复位方式设为异步复位
if(sys_rst_n == 1'b0)
cnt <= 25'd0; //复位信号为低电平时计数变量清零
else if(cnt == CNT_MAX)
cnt <= 25'd0; //计数器计满时清零
else
cnt <= cnt + 1'b1; //其他情况对时钟计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
flag <= 1'b0; //复位信号为低电平时标志信号设为低电平
else if(cnt == CNT_MAX)
flag <= ~flag; //计数器计满时将标志信号进行取反
else
flag <= flag; //其他情况标志信号保持不变
endmodule
在Quartus II中我们进行一次全编译,没有报错。
4.编写testbench代码
为了验证我们的设计,需要编写testbench文件进行仿真验证
我们编写testbench文件,是为了产生满足条件的激励信号,同时对模块的输出进行捕捉,测试输出是否满足要求。
编写代码如下:
`timescale 1ns/1ns //设置时间参数
module tb_counter(); //模块声明
reg sys_clk;
reg sys_rst_n;
wire flag; //声明端口(将原文件中wire类型和reg类型对换)
initial //初始化语句
begin
sys_rst_n = 1'b0; sys_clk = 1'b0; //设置初始参数
#50 //延迟50个时间单位
sys_rst_n = 1'b1;
end
always#10 sys_clk = ~sys_clk; //每10个时间单位sys_clk取反一次
counter counter_inst //例化语句
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.flag_0 (flag),
);
endmodule
将tb_counter文件添加到工程中,并进行编译
结果没有报错
然后使用Quartus & Modelsim 联合仿真
我们可以在Quartus中点击Assignments→Settings→Simulation
在Simulation中的NativeLink Settings中添加文件()
点击Test Benches添加自己写好的tb文件,这里注意文件名一定要与自己编写的tb_counter文件同名。
完成后回到主页面点击仿真按钮,Modelsim就会被启动,开始仿真
在前面的rtl代码中,我们将CNT_MAX设置为了24_999,方便这部分的仿真
在Instance栏目中我们点击counter_inst 使用ctrl+ W 将添加波形(因为默认的设置无法观察到我们设置的cnt变量)
在波形管理页面我们按住ctrl + A 然后ctrl + G进行分组,方便我们观察
点击这里可以隐藏变量地址
然后点continue run
再查看全局波形
波形如下:
我们需要对局部进行放大,可以看出:
当复位信号有效时(为低电平),cnt未开始计数,复位信号为高电平且时钟上升沿到来时计数开始
每个时钟上升沿到来时cnt增加1(可以右键cnt变量在Radix中选择Unsigned设置为无符号数)
当计数到24_999时cnt清零,且flag翻转
从这里看出来我们的设计是正确的。
为了更好的观察现象,我们把CNT_MAX设置为24_999_999,准备上板验证。
5.上板验证
我们需要绑定管脚,点击File→New→Tcl Script File
为了更容易观察现象,我们将flag信号引到LED0上,Tcl脚本如下
set_location_assignment PIN_E1 -to sys_clk
set_location_assignment PIN_N13 -to sys_rst_n
set_location_assignment PIN_E10 -to flag
将Tcl脚本保存到工程中,然后点击Tools→TCL Scripts→Tcl_script1.tcl
点击Run来执行我们编写好的Tcl脚本
执行成功
我们可以在这里看到管脚连接(也可以直接在该界面绑定管脚)
完成之后,我们进行一次全编译,然后就可以上板验证,点击这个按钮
连接开发板后我们可以在Hardware Settings中看到USB-0,需要进行选择(需要预先安装驱动)
先给开发板上电,然后点击Start
在这里看到,操作成功了
LED0会以亮0.5秒熄灭0.5秒的规律闪烁。
6.总结
本次我们设计了一个计数器,产生了占空比为50%的1Hz方波,以此来控制LED灯的闪烁。后续我们可以通过对1Hz方波进行分频来实现多个LED等按照不同频率闪烁,也可以将计数器作为子模块添加到其他的顶层模块来作为时间基准(1秒),以此来进行其他项目的设计。文章来源:https://www.toymoban.com/news/detail-424742.html
工程文件点这下载文章来源地址https://www.toymoban.com/news/detail-424742.html
到了这里,关于fpga[1]计数器(附源码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!