基于Smart Artix 的FPGA实验七 FPGA资源的PWM演示

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

  • 此章节内容适用于Smart Artix 的主板 ,如是本站其他板子请看对应板子目录
  • 本文在 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,在50mhz时钟下,1ms相当于振荡了50000次(对应二进制1100001101010000,即16位),所以这里定义一个16位的寄存器作计数用

reg [15:0] period_cnt;

计数的代码如下

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

// 从0-50000的计数器,即1ms计数器
always @(posedge CLK or negedge RSTn) begin
if (!RSTn) begin
time_count <= 16'd0;
end
else if (time_count == 16'd50_000) begin
time_count <= 16'd0;
end
else begin
time_count <= time_count + 1'b1;
end

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

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

wire LED=(time_count <16’d25_000)?1:0;

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

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

代码如下

reg [15:0] pwm_perid = 16'd0;
reg mode = 0; // mode为0则自增,mode为1则自减
always @(posedge CLK or negedge RSTn) begin
if (!RSTn) begin
pwm_perid <= 16'd0;
end
else if (time_count == 16'd50_000) begin
if (mode == 1'b0) begin
if (pwm_perid < 16'd50_000) pwm_perid <= pwm_perid + 50;
else mode <= 1'b1;
end
else if (mode == 1'b1) begin
if (pwm_perid > 16'd0) pwm_perid <= pwm_perid - 50;
else mode <= 1'b0;
end
end
end

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

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

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

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

增加约束文件如下

# Clock Constraints
set_property PACKAGE_PIN Y18 [get_ports CLK]
set_property IOSTANDARD LVCMOS33 [get_ports CLK]

# Reset Constraints (active-low reset)
set_property PACKAGE_PIN T20 [get_ports RSTn]
set_property IOSTANDARD LVCMOS33 [get_ports RSTn]

# LED Constraints
set_property PACKAGE_PIN R17 [get_ports LED]
set_property IOSTANDARD LVCMOS33 [get_ports LED]

# Define the clock period for 50 MHz
create_clock -period 20.000 -name CLK -waveform {0.000 10.000} [get_ports CLK]

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

本章节的工程:

  • 本文的完整工程下载:07_PWM_TEST (Smart Artix 50T)
  • VIVADO的版本:2018.3
  • 工程创建目录:E:\Smart_Artix\4_Code\07_PWM_TEST

发表回复

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