fpga[1]计数器(附源码)

计数器

  • 介绍
    • 1.创建项目文件夹
    • 2.绘制波形图
    • 3.编写rtl代码
    • 4.编写testbench代码
    • 5.上板验证
    • 6.总结

介绍

计数器电路是在数字电子技术中应用的最多的时序逻辑电路。计数器不仅能用于对时钟脉冲计数,还可以用于分频、定时、产生节拍脉冲和脉冲序列以及进行数字运算等。
在许多大型电路中必然有计数器电路的身影,可以说了解并掌握计数器的设计方法是学习fpga的第一步。
本文使用的软件是Quartus II 13.1modelsimnotepad++,开发板是黑金的AX301

  • 下图是计数器的基本设计流程。
Created with Raphaël 2.3.0 绘制波形图 依照波形图编写rtl代码 仿真验证功能是否正确 上板验证 yes no

1.创建项目文件夹

首先我们先创建一个存放项目的文件夹:
fpga[1]计数器(附源码)_第1张图片
再分别在counter内创建用来存放工程文件、rtl代码和波形图的文件夹:
fpga[1]计数器(附源码)_第2张图片
然后,打开Quartus II软件,新建一个工程文件并存放在我们刚刚建立好的prj文件夹中,命名为counter
fpga[1]计数器(附源码)_第3张图片
我们使用的开发板是黑金AX301搭载的是Cyclone IV E系列的EP4CE6F17C8,选择对应的型号。
fpga[1]计数器(附源码)_第4张图片
为了方便后续的仿真,我们先将仿真软件设置为Modelsim语言为Verilog HDL
fpga[1]计数器(附源码)_第5张图片

2.绘制波形图

对于计数器这个时序逻辑电路来说,需要时钟的驱动,复位方式选择异步复位。
同时,需要定义一个变量cnt来对时钟进行计数(后续需要利用LED来验证代码,此处先将cnt的位宽设置为25),计数值满时将flag进行取反。
最后将文件存放在visio文件夹中
fpga[1]计数器(附源码)_第6张图片

3.编写rtl代码

我们在rtl文件夹下建立名为counter的.v文件
fpga[1]计数器(附源码)_第7张图片
notepad++ 是一款小巧且好用的代码编辑软件,我们在language选项中勾选Verilog语言。
可以看到,notepad++Verilog语言有了关键字提示。
fpga[1]计数器(附源码)_第8张图片
编写代码如下:

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中我们进行一次全编译,没有报错。
fpga[1]计数器(附源码)_第9张图片

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文件添加到工程中,并进行编译
fpga[1]计数器(附源码)_第10张图片
结果没有报错

fpga[1]计数器(附源码)_第11张图片
然后使用Quartus & Modelsim 联合仿真
我们可以在Quartus中点击Assignments→Settings→Simulation
在Simulation中的NativeLink Settings中添加文件()

fpga[1]计数器(附源码)_第12张图片
点击Test Benches添加自己写好的tb文件,这里注意文件名一定要与自己编写的tb_counter文件同名
fpga[1]计数器(附源码)_第13张图片
完成后回到主页面点击仿真按钮,Modelsim就会被启动,开始仿真
fpga[1]计数器(附源码)_第14张图片

在前面的rtl代码中,我们将CNT_MAX设置为了24_999,方便这部分的仿真
Instance栏目中我们点击counter_inst 使用ctrl+ W 将添加波形(因为默认的设置无法观察到我们设置的cnt变量)
fpga[1]计数器(附源码)_第15张图片
在波形管理页面我们按住ctrl + A 然后ctrl + G进行分组,方便我们观察
fpga[1]计数器(附源码)_第16张图片
点击这里可以隐藏变量地址
fpga[1]计数器(附源码)_第17张图片
然后点continue run
在这里插入图片描述
再查看全局波形
在这里插入图片描述
波形如下:
fpga[1]计数器(附源码)_第18张图片
我们需要对局部进行放大,可以看出:
当复位信号有效时(为低电平),cnt未开始计数,复位信号为高电平且时钟上升沿到来时计数开始

fpga[1]计数器(附源码)_第19张图片
每个时钟上升沿到来时cnt增加1(可以右键cnt变量在Radix中选择Unsigned设置为无符号数)
在这里插入图片描述
当计数到24_999时cnt清零,且flag翻转
在这里插入图片描述
fpga[1]计数器(附源码)_第20张图片
从这里看出来我们的设计是正确的。

为了更好的观察现象,我们把CNT_MAX设置为24_999_999,准备上板验证。

5.上板验证

我们需要绑定管脚,点击File→New→Tcl Script File

fpga[1]计数器(附源码)_第21张图片
为了更容易观察现象,我们将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

fpga[1]计数器(附源码)_第22张图片
点击Run来执行我们编写好的Tcl脚本
fpga[1]计数器(附源码)_第23张图片
执行成功

fpga[1]计数器(附源码)_第24张图片
我们可以在这里看到管脚连接(也可以直接在该界面绑定管脚)
在这里插入图片描述
fpga[1]计数器(附源码)_第25张图片
完成之后,我们进行一次全编译,然后就可以上板验证,点击这个按钮
在这里插入图片描述
连接开发板后我们可以在Hardware Settings中看到USB-0,需要进行选择(需要预先安装驱动)

fpga[1]计数器(附源码)_第26张图片
先给开发板上电,然后点击Startfpga[1]计数器(附源码)_第27张图片
在这里看到,操作成功了
fpga[1]计数器(附源码)_第28张图片
LED0会以亮0.5秒熄灭0.5秒的规律闪烁。
fpga[1]计数器(附源码)_第29张图片

6.总结

本次我们设计了一个计数器,产生了占空比为50%的1Hz方波,以此来控制LED灯的闪烁。后续我们可以通过对1Hz方波进行分频来实现多个LED等按照不同频率闪烁,也可以将计数器作为子模块添加到其他的顶层模块来作为时间基准(1秒),以此来进行其他项目的设计。

工程文件点这下载

你可能感兴趣的:(fpga开发)