洗子的第一个FPGA实验,开始入门啦!在学习编程的时候"Hello World!"就是入门,硬件的入门就是流水灯。本节实验任务是使用启明星FPGA开发板上的两个LED灯,实现顺序点亮并熄灭,循环往复产生流水灯效果,流水时隔时间为0.5s。
一、项目总体思路的构建
首先,我们绘制一个思维导图,确定这个LED流水灯模块所需要的内容。
- 输入端口:由于流水灯输入的激励信号会随着时间的变化而变化,因此我们的输入端口包含系统时钟和系统复位信号。系统时钟用来计数,系统复位信号来使系统时钟复位重新计数。
- 输出端口:输出端口就为两个LED灯
- 系统时钟功能:使用系统时钟cnt计时0.5s
- LED控制:采用激励信号移位控制的方法
接下来,我们根据上述的思路绘制图像来模拟流水灯功能的实现,以下图像包含:LED灯的变化情况,架构的设计与波形图。
二、编写代码
我们要养成建立项目文件夹的习惯,文件夹的命名最好不要带有中文。建立doc、prj、rtl与sim文件夹。doc文件夹用来存储思路构建的文件,prj用来存储vivado的项目文件,rtl用来存储编写的verilog文件,sim用来存储仿真的tb文件。
进入rtl文件夹,在此文件夹内建立flow_led.v文件开始编写程序。
- 建立flow_led模块,定义输入输出变量
module flow_led(
input sys_clk,
input sys_rst_n,
output reg[1:0] led
);
endmodule
- 确定系统时钟代码块
我们使用计算器可以计算出系统时钟cnt为25位二进制数,因此位宽为[24:0]。我们建立一个循环当系统时钟处于上升沿或者复位信号处于下降沿时,执行代码块。如果复位信号为低电平时,系统时钟清零。如果系统时钟处于1~249999ns时,系统时钟一次累加1ns。
//系统时钟计时0.5s
reg [24:0] cnt;
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
cnt <= 25'd0;
else if(cnt < (25'd25000000 - 25'd1))
cnt <= cnt + 25'd1;
else
cnt <= 25'd0;
end
- 确定LED移位控制代码块
定义LED灯初始状态为右侧灯亮,左侧灯不亮。当系统时钟为249999ns时,第一位和第二位的逻辑数互换。
♾️ verilog 代码://LED移位控制
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
led <= 2'b01;
else if(cnt == (25'd25000000 - 25'd1))
led <= {led[0],led[1]}; //01 10 01
else
led <= led;
end
- 完整代码
module flow_led(
input sys_clk,
input sys_rst_n,
output reg[1:0] led
);
//系统时钟计时0.5s
reg [24:0] cnt;
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
cnt <= 25'd0;
else if(cnt < (25'd25000000 - 25'd1))
cnt <= cnt + 25'd1;
else
cnt <= 25'd0;
end
//LED移位控制
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
led <= 2'b01;
else if(cnt == (25'd25000000 - 25'd1))
led <= {led[0],led[1]}; //01 10 01
else
led <= led;
end
endmodule
三、验证仿真
在sim文件夹建立tb_flow_led.v文件,用来编辑仿真文件。
timescale 1ns/1ns
:这是一个仿真指令,用于指定仿真器的时间单位和时间精度。在这里,时间单位是1ns,时间精度也是1ns。这意味着仿真器将以1ns的粒度来模拟电路中的时间流逝。initial begin
初始化定义初始化系统时钟和复位信号。always #(CLK_PERIOD/2) sys_clk =~ sys_clk;
时钟信号半个周期翻转一次。u_flow_led
:这是实例化的一个名称,用来指代flow_led
模块的一个实例。.sys_clk (sys_clk)
:这表示将测试台中的sys_clk
信号连接到flow_led
模块的sys_clk
输入端口上。点号.
表示连接端口的语法,括号里的内容表示该连接的端口名称。
`timescale 1ns/1ns //仿真单位/仿真精度
module tb_flow_led();
parameter CLK_PERIOD = 20;
reg sys_clk;
reg sys_rst_n;
wire [1:0] led;
initial begin
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
#200
sys_rst_n <= 1'b1;
end
always #(CLK_PERIOD/2) sys_clk =~ sys_clk;
flow_led u_flow_led(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.led (led )
);
endmodule
打开ModleSim软件进行仿真。
File ---> new ---> project,项目名称命名为flow_led,项目地址定为到sim文件夹。
点击Add Existing File将flow_led.v和tb_flow_led.v文件导入。右键Compile ---> Compile All进行编译。
编译成功后选择点击work,选择tb文件进行仿真。
点击u_flow_led右键 ---> All Wave打开波形图程序。由于仿真250000ns时间过长,我们修改flow_led.v文件将时间改成25ns。这里只是为了提高效率,后续再将代码改回即可。重新编译文件。
在运行窗口输入:run 10us
。仿真10微秒。右键led ---> Radix ---> Binary改成二进制,右键cnt ---> Radix ---> Ufixed。由仿真图我们可以看出led在移位的间隔为500ns与我们的设计相同。因此,代码编写无误。
四、上板验证
打开vivado软件,新建工程,将文件路径定为到prj文件夹。
前面的RTL设置默认,添加RTL文件,添加约束文件先跳过。
添加开发板信息。
进行RTL ANALYSIS(RTL分析)。
查询开发板信息,查找输入和输出端IO口。
编辑IO口的信息。
保存,将文件命名为flow_led。
双击xdc文件,添加时序约束create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
。时序约束对于确保FPGA设计的正确性、性能和资源利用率都非常重要。通过添加适当的时序约束,设计者可以更好地控制设计的时序行为,从而确保设计在实际硬件中正常工作。
电脑接入开发板,Generate Bitstream ---> Open Target ---> program device,进行烧录,最终效果如下:
五、总结
第一次实验完成啦!实验内容其实还是蛮简单的,就是Verilog代码的编写思路需要练习,上板验证以及烧录操作较为繁琐要耐心。
好友
HelloGakki👍
💖
💯
💦
😄
🪙
博主
洗子 @HelloGakki👍
💖
💯
💦
😄
🪙