赞
踩
风过如呼吸,云生似吐含。 ———————宋·苏轼《入峡》
大四毕业后白嫖了电子创新实验室的一块FPGA,这块板子适合做数电实验,为了物尽其用,趁这个暑假搭配特权同学做的《深入浅出玩转FPGA》视频学习入门一下,用它整点活。
让板载LED灯慢慢由灭到亮,持续4秒,又由亮到灭,持续4秒,循环。
RTL代码编写平台:Vivado 2019.1
FPGA开发板:Xilinx BASYS3
芯片型号:Artix-7家族 xc7a35tcpg236-1
1.呼吸灯原理
当LED灯亮灭切换的频率大于等于50Hz时,由于人眼的视觉暂留,使我们看不到LED灯闪烁,而是以亮度呈现在我们眼前。在本节实验中,我们让LED闪烁频率为50Hz,通过PWM技术来时刻改变一周期中高电平的脉宽,也就是改变占空比的方式改变亮度。
2.设计思路
以下图为例,LED闪烁的频率为50Hz,即led_out信号的频率为50Hz,我们可以通过调节cnt2来改变一周期中高电平的宽度,因为周期不变,所以等同改变了占空比。我们设cnt2为x,x可取0、2、4、6、8,最小取0,最大取8,x取的每一个值都代表着LED灯的一个亮度,不妨把每一个LED灯亮度的状态视作为整个“呼吸动画”的一帧,那么就需要有一个驱动这些一帧一帧“动画”运行的时钟,也就是下图右边的clk_div,我们也把它设置为50Hz,也就是每隔20ms“播放”一帧LED灯亮度的状态,并且状态之间的变化(指cnt2的变化)按照“亮度慢慢由灭到亮,再由亮到灭”运行(即cnt2由0->8,再由8->0,每个状态之间加一次或减一次,is为1就是加操作,is为0就是减操作)。
RTL代码如下图所示。
- module Blinker(
- input sys_clk, //100Mhz系统时钟
- input rst_n, //复位,高电平有效
- output reg led_out //led输出
- );
- reg[27:0] cnt; //产生“50Hz时钟”的计数值
- reg [27:0] cnt2; //可以调节输出LED占空比的计数值
- reg clk_div; //50Hz时钟
- reg is; //状态量,1为LED亮度增加状态,0为LED亮度减小状态
-
- /*产生频率50Hz的时钟*/
- always @ (posedge sys_clk or posedge rst_n)
- begin
- if(rst_n) cnt <= 28'd0;
- else if(cnt < 28'd1_999_999) cnt <= cnt+1'b1;
- else cnt <= 28'd0;
- end
-
- always @ (posedge sys_clk or posedge rst_n)
- begin
- if(rst_n) clk_div <= 1'b0;
- else if(cnt < 28'd999_999) clk_div <= 1'b1;
- else clk_div <= 1'b0;
- end
-
- /*产生50Hz信号给led输出,占空比受到cnt2控制*/
- always @ (posedge sys_clk or posedge rst_n)
- begin
- if(rst_n) led_out <= 1'b0;
- else if(cnt < cnt2) led_out <= 1'b1;
- else led_out <= 1'b0;
- end
-
- /*在50Hz时钟下降沿触发cnt2计数操作,即每隔20毫秒cnt2增或减一次*/
- always @ (posedge clk_div or posedge rst_n)
- begin
- if(rst_n) cnt2 <= 28'd0;
- else
- begin
- if(is)
- begin
- if(cnt2 < 28'd2_000_000) cnt2 <= cnt2+28'd10000;
- else is <= 1'b0;
- end
- else
- begin
- if(cnt2 > 28'd0) cnt2 <= cnt2-28'd10000;
- else is <= 1'b1;
- end
- end
- end
- endmodule
在代码中,cnt不只是作为计数变量产生50Hz时钟clk_div,驱动cnt2增减进行占空比的改变;还作为计数变量产生50HzPWM信号输出给LED灯,此时计数上限也就是cnt2。
下面再讲解一下“由灭到亮的4秒”是如何实现的,板子的系统时钟为100Mhz,要想得到50Hz频率信号,由于100MHz/50Hz=2M,就需要对系统时钟的上升沿计数,从0到1 999 999,可见计数上限为1 999 999,下限为0,当cnt2为999 999时占空比为50%,为1 999 999时占空比100%,在代码中cnt2每隔20ms加10 000,那么cnt2从0加到1 999 999需要200次(2 000 000/10 000) ,所以需要200次*20ms=4s时间来完成“LED由灭到亮”的过程,在下面一节的仿真中便可以看到。
注意,板子上的按钮为摁下接到高电平,松开接到低电平,原理图如下所示,这里我们用到的是5个中的1个,所以在设计仿真测试程序时要让rst信号由低电平跳上高电平然后过一点点时间再拉低。
仿真程序如下所示。
- module sim_blinker(
- );
- /*定义外部测试输入信号*/
- reg sys_clk; //100Mhz系统时钟
- reg rst_n; //复位,高电平有效
- wire led_out;
-
- /*例化模块*/
- Blinker text_blinker(
- .sys_clk(sys_clk), //100Mhz,10ns
- .rst_n(rst_n),
- .led_out(led_out)
- );
-
- /*测试流程初始化*/
- initial begin
- sys_clk = 0;
- rst_n = 0;
- #1000;
- @(posedge sys_clk);
- rst_n = 1;
- #1000;
- rst_n = 0;
- repeat(8) #1_000_000_000; //测试8秒
- $finish;
-
- end
-
- always #5 sys_clk = ~sys_clk; //每隔5ns翻转一次电平
-
- endmodule
行为仿真结果如下图所示,可以直观的看到图中is信号为高电平时,led_out信号(蓝色的那条)随着50Hz时钟信号clk_div(紫色的那条)高电平的脉宽在逐步增大。
下图显示了当is信号从高变低的时刻正好对应了4秒这个时刻(见红圈),此时LED灯的占空比为100%,亮度最高,即“由灭变亮”这一过程已结束,当is=0后开始“由亮变灭”这个过程,PWM占空比随着时钟逐渐减小变为0%,然后重新开始循环。
下图为综合后总模块的RTL原理图。
输入有系统时钟信号sys_clk和复位信号rst_n,输出为1位的led_out信号。由下图所示,100Mhz系统时钟输入到了W5引脚中,所以我们给sys_clk引脚配置为W5。
rst_n复位引脚我们配置为T17,原理图如下图所示。
led_out 引脚我们配置为V3,最后管脚的配置文件如下图所示。
- set_property PACKAGE_PIN V3 [get_ports led_out]
- set_property PACKAGE_PIN T17 [get_ports rst_n]
- set_property PACKAGE_PIN W5 [get_ports sys_clk]
- set_property IOSTANDARD LVCMOS33 [get_ports led_out]
- set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
- set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]
仿真、综合、布局布线、分配管脚后,可以生成bit文件,通过USB线给开发板上电,vivado连上器件xc7a35tcpg236-1后将bit文件烧录至开发板。
效果如下视频所示。
QQ视频20230713150000
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。