基于Lemon ZYNQ的FPGA实验七 FPGA资源的PWM演示 

PWM也即脉冲宽度调试技术,是电子领域的重要技术之一(广泛应用于开关电源,电机速度控制,LED灯亮度控制等领域),类似DSP,单片机,STM32等微处理器中都带有硬件PWM,本文将介绍如何使用VERILOG语言来写一个PWM,并通过呼吸灯的方式来进行效果的演示。

  • 此章节内容适用于Lemon ZYNQ主板,如是其他板子请看对应板子目录
  • 本文在 vivado2018.3版本上演示

一、PWM调整LED亮度的简单原理分析

我们先来看下PWM的标准波形,如下图所示, 其中上中下三个波形的周期T和频率F是相同的,第一个波形高电平占整个周期的T的时间是25%,第二个波形占50%,第三个占75%。

因为三个波形的周期T和频率F是相同的,比方说 三个PWM的波形都是1KHZ,那么1秒钟内,三个PWM波形都会出现1000个周期为T的方波。如果此时拿这3个波形分别去点亮3个LED灯,那3个LED都会闪烁1000次(只是因为人眼的视觉残留因素,所以感觉不到这个闪烁),但是因为3者的占空比不同(高电平占整个周期的百分比不同)导致最上面25%占空比的波形单位时间内亮的时间最少,75%占空比的波形亮的时间最久。反应到视觉上的结果就是 第三个波形点亮的LED灯最亮,第一个波形对应的LED灯最暗,这也就是PWM调光的简单原理。同样的借助这个方法同样可以分析电机等场景。

同样当占空比为0%时,LED灯完全熄灭,当占空比为100%时LED灯完全点亮,借助这个原理,我们只要将占空比从0%逐渐增加到100%,再从100%逐渐减少到0%不断变化,就可以实现呼吸灯的效果了。

二、代码编写

首先我们要设计一个周期性的计数器来来进行波形周期的计数,我们定义占空比的频率为1KHZ,那波形的一个周期就是1ms,在125mhz时钟下,1ms相当于振荡了125000次(对应二进制1100001101010000,即16位),所以这里定义一个16位的寄存器作计数用

reg [16:0] period_cnt;

计数的代码如下

reg  [16:0]  time_count=17'd0;

//从0-125000的计数器,即1ms计数器
always @(posedge clk or posedge rst) begin
if(rst)begin
time_count<=17'd0;
end
else if(time_count == 17'd125_000)
time_count <= 17'd0;
else
time_count <= time_count + 1'b1;
end

其中 if(rst)begin time_count <=17’d0; end 这句是负责复位用,外部rst信号接入到按键上(按键按下是高电平)

仅仅有计数器不能实现波形的输出功能,接下来我们简单写个 输出50%方波的程序,仅仅一句话就可以了

wire led=(time_count <17’d62_500)?1:0;

这句话相当于,在time_count由0计数到125_000的过程中,当小于62500时,输出1,当大于等于62500时候输出0,又因为整个周期是125_000,而62500刚好是一半,那样就产生了一半的高电平,一半的低电平,即标准的50%方波。

我们的目标是设计呼吸灯,那只要把62500变成一个由小到大又从大变到小的寄存器pwm_perid就可以了。

代码如下

reg  [16:0]  pwm_perid=17'd0;
reg mode=0;//mode为0则自增,mode为1为自减
always @(posedge clk or posedge rst) begin
if(rst)begin
pwm_perid<=17'd0;
end
else if(time_count== 17'd125_000)begin
if(mode==1'b0)begin
if(pwm_perid<17'd125_000) pwm_perid<=pwm_perid+25;
else mode<=1'b1;
end
else if(mode==1'b1)begin
if(pwm_perid>17'd0) pwm_perid<=pwm_perid-25;
else mode<=1'b0;
end
end
end

assign led=(time_count <pwm_perid)?1:0;

增减程序的改变周期为1ms,即1秒钟改变1000次,这里偷个懒,直接用上面的time_count计数器来作这边的改变周期用if(time_count== 17’d125_000),当然也可以自己重新写一个,都一样的

程序里有一个reg mode,这个是用来记录工作模式的,mode为0则pwm_perid自增,mode为1pwm_perid为自减

而mode切换的条件就是 占空比达到最大,或者占空比被减少到0%

代码很简单,直接编译综合并且下载进FPGA观测结果

增加约束文件如下

set_property IOSTANDARD LVCMOS33 [get_ports led]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports rst]
set_property PACKAGE_PIN H16 [get_ports clk]
set_property PACKAGE_PIN R14 [get_ports led]
set_property PACKAGE_PIN D19 [get_ports rst]

下载完后就能看到 LED0 (LD0)在不停的变亮变暗变亮变暗了,按下BTN0键(RST键)PWM会清零重置。

  • 本文的完整工程下载:07_PL_PWM_TEST
  • VIVADO的版本:2018.3
  • 工程创建目录: E:\Lemon_ZYNQ\FPGA\07_PL_PWM_TEST

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注