本帖最后由 正点原子运营 于 2023-3-23 16:26 编辑
第八章 LED灯闪烁实验
1)实验平台:正点原子 DFZU2EG/4EV MPSoC开发板
2) 章节摘自【正点原子】DFZU2EG/4EV MPSoC之FPGA开发指南 V1.0
6)FPGA技术交流QQ群:994244016
LED灯闪烁作为一个经典的入门实验,其地位堪比编程界的“Hello,World!”。对于很多电子工程师来说,LED灯闪烁都是他们在硬件上观察到的第一个实验现象。本章我们同样通过LED灯闪烁实验,带你进入MPSoC的精彩世界。 本章包括以下几个部分: 8.1 LED灯简介 8.2 实验任务 8.3 硬件设计 8.4 程序设计 8.5 下载验证
8.1 LED灯简介LED,又名发光二极管。LED灯工作电流很小(有的仅零点几毫安即可发光),抗冲击和抗震性能好,可靠性高,寿命长。由于这些优点,LED灯被广泛用在仪器仪表中作指示灯、液晶屏背光源等诸多领域。
不同材料的发光二极管可以发出红、橙、黄、绿、青、蓝、紫、白这八种颜色的光。图 8.1.1是可以发出黄、红、蓝三种颜色的直插型二极管实物图,这种二极管长的一端是阳极,短的一端是阴极。图 8.1.2是开发板上用的贴片二极管实物图。贴片二极管的正面一般都有颜色标记,有标记的那端就是阴极。 图 8.1.1 发光二极管实物图
图 8.1.2 贴片发光二极管实物图
发光二极管与普通二极管一样具有单向导电性。给它加上阳极正向电压后,通过5mA左右的电流就可以使二极管发光。通过二极管的电流越大,发出的光亮度越强。不过我们一般将电流限定在3~20mA之间,否则电流过大就会烧坏二极管。
8.2 实验任务本节实验任务是使DFZU2EG/4EV MPSoC开发板上的PLLED1和PL LED2以固定的频率交替闪烁。
8.3 硬件设计DFZU2EG/4EV MPSoC开发板上LED的原理图如下图所示: 图8.3.1LED灯硬件原理图
在图 8.3.1中,PL_LED1和PL_LED2连接到MPSoC的PL端,PS_LED1和PS_LED2连接到ZYNQ的PS端。在《DFZU2EG/4EV MPSoC之FPGA开发指南》中,我们只使用PL端的外设。
PL_LED1和PL_LED2的阴极通过330欧姆的电阻连到地(GND)上,阳极由ZYNQ PL的IO管脚控制,LED与地之间的电阻起到限流作用。
本实验中,系统时钟、按键复位以及两个LED端口的管脚分配如下表所示。 表 8.3.1 LED闪烁实验管脚分配
对应的XDC约束语句如下所示: - #IO管脚约束
- set_property IOSTANDARD DIFF_HSTL_I_12 [get_portssys_clk_p]
- set_property IOSTANDARD DIFF_HSTL_I_12 [get_portssys_clk_n]
- set_property PACKAGE_PIN AE5 [get_ports sys_clk_p]
- set_property PACKAGE_PIN AF5 [get_ports sys_clk_n]
- set_property -dict {PACKAGE_PIN AH11 IOSTANDARD LVCMOS33}[get_ports sys_rst_n]
- set_property -dict {PACKAGE_PIN AE10 IOSTANDARD LVCMOS33}[get_ports {led[0]}]
- set_property -dict {PACKAGE_PIN AF10 IOSTANDARD LVCMOS33}[get_ports {led[1]}]
- #时钟周期约束
- create_clock -name sys_clk_p -period 10.000 [get_portssys_clk_p]
复制代码
8.4 程序设计由于发光二极管的阳极与MPSoC的管脚相连,只需要改变与LED灯相连的MPSoC管脚的电平,LED灯的亮灭状态就会发生变化。当MPSoC管脚为高电平时,LED灯点亮;为低电平时,LED灯熄灭。
本次设计的模块端口及信号连接如下图所示: 图 8.4.1 LED灯模块原理图
其中,计数器对100MHz时钟进行计数,从而达到计时的目的。计数器在每次计时到1秒之后清零,然后重新开始计数,计数的值用于控制LED的显示状态。当计数器的值小于0.5s时,就把LED0点亮并把LED1熄灭;每当计数器的值大于0.5s时,就把LED0熄灭并把LED1点亮,以此实现两个LED的交替闪烁。
LED闪烁模块的代码如下: - 1 module led_twinkle(
- 2 input sys_clk_p, //系统差分输入时钟
- 3 input sys_clk_n, //系统差分输入时钟
- 4 input sys_rst_n, //系统复位,低电平有效
- 5
- 6 output [1:0 led //LED灯
- 7 );
- 8
- 9 //reg define
- 10 reg [26:0 cnt;
- 11
- 12 //*****************************************************
- 13 //** main code
- 14 //*****************************************************
- 15
- 16 //对计数器的值进行判断,以输出LED的状态
- 17 assign led = (cnt < 27'd5000_0000) ? 2'b01 : 2'b10;
- 18 //assign led = (cnt< 27'd5) ? 2'b01 :2'b10; //仅用于仿真
- 19
- 20 //转换差分信号
- 21 IBUFDS diff_clock
- 22 (
- 23 .I (sys_clk_p), //差分输入时钟
- 24 .IB(sys_clk_n), //系统差分输入时钟
- 25 .O (sys_clk) //输出系统时钟
- 26 );
- 27
- 28 //计数器在0~10000_0000之间进行计数
- 29 always @ (posedge sys_clk or negedge sys_rst_n) begin
- 30 if(!sys_rst_n)
- 31 cnt <= 27'd0;
- 32 else if(cnt < 27'd10000_0000)
- 33 //else if(cnt < 27'd10) //仅用于仿真
- 34 cnt <= cnt + 1'b1;
- 35 else
- 36 cnt <= 27'd0;
- 37 end
- 38
- 39 endmodule
复制代码本程序中输入时钟为MPSoC板载的时钟发生器输出的100MHz的差分信号时钟,代码中第20-26行利用原语将差分时钟转化为一个单端100MHz的时钟sys_clk作为PL端的系统时钟。
原语,即primitive,不同的厂商,原语不同;同一家的FPGA,不同型号的芯片,可以也不一样;原语类似最底层的描述方法。使用原语的好处,可以直接例化使用,不用定制IP,即可通过复制原语的语句,然后例化IP后就可使用。 IBUFDS是差分输入缓冲器,用于将来自时钟发生器输出的差分时钟信号转换成单端时钟信号使用。IBUFDS原语示意图如下所示: sys_clk一个时钟周期为10ns(1/100MHz)。因此计数器cnt通过对100MHz系统时钟计数,计时到1s,需要累加1s/10ns=10000_0000次。在代码第34行,每当计时到1s计数器清零一次。
同时,在代码的第17行,对根据计数器的计数值来赋值两个LED的状态。当计数值小于5000_0000即计时到1s中的前500ms时,LED0点亮LED1熄灭;当计数值大于等于5000_0000,即计时到1s中的后500ms时,LED0熄灭LED1点亮。当计数到1s时,计数器又会回0,重复此过程。以此实现两个LED的交替闪烁。
为了验证我们的程序,我们在Vivado内对代码进行仿真。为了更容易地看到仿真现象,我们将源代码中的计数器的最大计数值修改为5,然后再仿真,如下图所示: 图 8.4.3 仅用于仿真的代码
Testbench模块代码如下: - 1 `timescale 1ns /1ps
- 2
- 3 module tb_led_twinkle();
- 4
- 5 //输入
- 6 reg sys_clk_p;
- 7 reg sys_clk_n;
- 8 reg sys_rst_n;
- 9
- 10 //输出
- 11 wire [1:0 led;
- 12
- 13 //信号初始化
- 14 initial begin
- 15 sys_clk_p = 1'b0;
- 16 sys_clk_n = 1'b1;
- 17 sys_rst_n = 1'b0;
- 18 #200
- 19 sys_rst_n = 1'b1;
- 20 end
- 21
- 22 //生成时钟
- 23 always #5 sys_clk_p= ~ sys_clk_p;
- 24 always #5 sys_clk_n= ~ sys_clk_n;
- 25
- 26 //例化待测设计
- 27led_twinkle u_led_twinkle(
- 28 .sys_clk_p (sys_clk_p),
- 29 .sys_clk_n (sys_clk_n),
- 30 .sys_rst_n (sys_rst_n),
- 31 .led (led)
- 32 );
- 33
- 34 endmodule
复制代码仿真得到的波形图如下图所示: 图 8.4.4 仿真波形图
从图 8.4.4中可以看到,计数器cnt的值在0到10之间循环计数。当cnt的值小于5时,led0为高电平;大于5时led0为低电平。两个LED的状态随着计数器的计数循环翻转,实现LED闪烁的效果。
8.5 下载验证编译工程并生成比特流.bit文件后,点击Vivado左侧“Flow Navigator”窗口最下面的“Open Hardware Manager”按钮如下图所示。 图 8.5.1 Hardware Manager界面
首先将Xilinx下载器一端连接电脑,另一端与开发板上的JTAG接口相连接,然后连接开发板电源线。
注意!一定要先把下载器的一端连接到了电脑、另一端连接了JTAG接口之后,再给开发板上电!否则,对开发板的JTAG接口进行带电热插拔,有一定概率会损坏JTAG接口! 最后将开发板的电源拨码开关按键按照下图往电源指示灯的方向拨动对开发板进行上电,上电成功后开发板的电源指示灯会亮蓝灯。DFZU2EG/4EV MPSoC开发板的实物连接如下图所示: 图 8.5.2 DFZU2EG/4EV MPSoC开发板连接实物图
开发板连接好电源线和下载器后,点击“Hardware”窗口中的“Auto Connect”图标,如下图所示: 图 8.5.3 “Auto Connect”图标
在“Hardware”子窗口中出现如下界面就表示Vivado就已经和下载器连接成功了,如下图所示: 图 8.5.4 与下载器连接成功
我们点击上图中的“Program Device”,弹出的界面如下图所示: 图 8.5.5 下载比特流界面
此时Bitstream File一栏会自动识别到工程的比特流文件,我们直接点击“Program”按钮下载程序,程序下载完成后,PL配置完成灯会点亮(DONE灯,绿色),此时我们可以看到位于开发板上的两个LED灯在不断地闪烁,如下图所示: 图 8.5.6 两个PL LED灯交替闪烁 |