前言
你会FPGA吗?我会点灯!
一、概述
作为一名点灯高手,今天就来实际操练一下。
如何点亮?
开发板上带有8个LED灯,我们只需要控制它对应的管脚电平输入即可。
1:灭;0:亮。
如何实现流水灯?
通过 FPGA 内部的定时器,循环点亮每个 LED,达到流水灯的效果。如下图 所示,8 个 LED 指示灯,我们依次给它们赋值,每次只有一个 LED 点亮, 每次点亮某个 LED 的时间一定(固定延时)。8个 LED 依次被点亮一次,如此循环便能达到流水灯的效果。
二、代码
module flow_led(
input i_sys_clk, //外部输入50MHz时钟信号
input i_rst_n, //外部输入复位信号,低电平有效
output [7:0] o_led //8个LED指示灯接口,1--灭;0--亮
);
`define SIM //仿真时使用
`ifdef SIM
parameter MAX_CNT = 24'd10;
`else
parameter MAX_CNT = 24'd9_999_999;
`endif
//-------------------------------------
reg[23:0] cnt; //24位计数器
reg[7:0] led;
//cnt计数器进行循环计数,一个计数周期的时间为 10000000*20ns = 200ms
always @ (posedge i_sys_clk or negedge i_rst_n)
if(!i_rst_n) cnt <= 24'd0;
else if(cnt < MAX_CNT) cnt <= cnt+1'b1;
else cnt <= 24'd0;
//-------------------------------------
//计数器cnt计数到最大值时,切换点亮的指示灯
always @ (posedge i_sys_clk or negedge i_rst_n)
if(!i_rst_n) led <= 8'b1111_1110; //默认只点亮一个指示灯D2
else if(cnt == MAX_CNT) led <= {led[6:0],led[7]}; //200ms为一个计数周期,执行一次循环移位操作
assign o_led = led;
endmodule
2.1代码说明
`define SIM
`ifdef SIM
parameter MAX_CNT = 24'd10;
`else
parameter MAX_CNT = 24'd9_999_999;
`endif
表示如果代码中定义了 SIM,则执行 MAX_CNT = 24'd10 的赋值;否者执行 MAX_CNT = 24'd9_999_999 的赋值。那么我们使用这个定义,仿真和板级两种情况下 MAX_CNT 的取值不同,仿真时希望快速看到结果,那么计数值小一些,我们看到功能实现即可;而板 级情况下,流水灯的速度不能太快(太快就看不到流水灯的效果了),必须至少有几百毫秒 的延时才能够看清流水灯的效果。因此,在做仿真时,需要有“`define SIM”这个语句,而在实际板级编译时,则必须注释该语句。
三、仿真
`timescale 1ns / 1ps
`timescale 1ns/1ps
module flow_led_tb();
reg sys_clk_i;
reg ext_rst_n;
wire[7:0] led;
flow_led u_flow_led(
.i_sys_clk(sys_clk_i),
.i_rst_n(ext_rst_n),
.o_led(led)
);
initial begin
sys_clk_i = 0;
ext_rst_n = 0; //复位中
#1000;
@(posedge sys_clk_i); #2;
ext_rst_n = 1; //复位结束,正常工作
#5000;
$finish;
end
always #10 sys_clk_i = ~sys_clk_i; //50MHz时钟产生
endmodule
为了便于查看,我们先选中 led[7:0]这个信号,然后在 Value 这一列中右键单击,如下图所示,弹出菜单中点击 Radix --> Binary,表示以 2 进制方式显示。
led 信号以 2 进制显示,我们可以更直观的看到 8 位数据中有 1 位是 0,且不断的向左移动,到最高位后又回到最低位。
四、上板子
生成bit/mcs文件的流程就不啰嗦了,这里简单看下约束文件:
set_property IOSTANDARD LVTTL [get_ports sys_clk_i]
set_property PACKAGE_PIN N11 [get_ports sys_clk_i]
set_property IOSTANDARD LVTTL [get_ports ext_rst_n]
set_property PACKAGE_PIN T2 [get_ports ext_rst_n]
set_property IOSTANDARD LVTTL [get_ports {led[0]}]
set_property PACKAGE_PIN M1 [get_ports {led[0]}]
set_property IOSTANDARD LVTTL [get_ports {led[1]}]
set_property PACKAGE_PIN N1 [get_ports {led[1]}]
set_property IOSTANDARD LVTTL [get_ports {led[2]}]
set_property PACKAGE_PIN P1 [get_ports {led[2]}]
set_property IOSTANDARD LVTTL [get_ports {led[3]}]
set_property PACKAGE_PIN R2 [get_ports {led[3]}]
set_property IOSTANDARD LVTTL [get_ports {led[4]}]
set_property PACKAGE_PIN T3 [get_ports {led[4]}]
set_property IOSTANDARD LVTTL [get_ports {led[5]}]
set_property PACKAGE_PIN R5 [get_ports {led[5]}]
set_property IOSTANDARD LVTTL [get_ports {led[6]}]
set_property PACKAGE_PIN R6 [get_ports {led[6]}]
set_property IOSTANDARD LVTTL [get_ports {led[7]}]
set_property PACKAGE_PIN T7 [get_ports {led[7]}]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design]
上板效果:
略。
后期图像采集和以太网通信等等项目再上板子。
后记
其他常见的什么加法器、按键消抖、FIFP IP创建等等凑字数的东西,这个系列就不写了,专栏文章如同《FPGA接口篇》一样,实用为主。
下个项目,开始虚拟项目教学,一般作为公司的入职培训。
咱们下期见~