什么是PWM
PWM 是 Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调制,简称脉宽调制。
它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,其控制简单、灵活和动态响应好等优点而成为电力电子技术最广泛应用的控制方式,其应用领域包括测量,通信,功率控制与变换,电动机控制、伺服控制、调光、开关电源,甚至某些音频放大器,因此学习 PWM 具有十分重要的现实意义。
其实我们也可以这样理解,PWM 是一种对模拟信号电平进行数字编码的方法。PWM 信号仍然是数字的,因为在给定的任何时刻,直流供电要么完全有(ON),要么完全无(OFF)。电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到负载上去的。
什么是占空比
占空比的定义为:一个脉冲周期内,高电平时间占总时间的比例,以下分别为占空比50%,10%,30%和70%的脉冲波形。
简单生成PWM信号的方法
通过上面的了解,我们知道PWM信号的重要性,ESP32作为物联网行业非常受欢迎的单片机,必然也支持PWM信号的输出。
analogWrite这个函数的功能就是往某一个引脚输出指定占空比的PWM信号,再回顾一下该函数的签名
void analogWrite(uint8_t pin, int value);第一个参数为引脚编号,第二个参数为PWM占空比,取值范围为0~255,
我们首先使用该函数来完成LED灯的呼吸灯效果
实现原理很简单,LED灯正极接到ESP32某个GPIO,比如D23引脚,负极接到GND,并且加上一个限流电阻。然后通过程序往D23引脚输出占空比逐渐变大的PWM信号,当占空比到达最大值255时,再将占空比逐渐减少,以此来实现LED灯亮度逐渐变量,然后又逐渐变暗的过程。
#include <Arduino.h>
#define LED_PIN 23
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
// 占空比从0到255,逐渐变大,每次中间延迟10ms,不然程序运行太快眼睛无法查看效果
for (int i = 0; i < 256; i++) {
analogWrite(LED_PIN, i);
delay(10);
}
// 占空比从255到0,逐渐变小
for (int i = 255; i >= 0; i--) {
analogWrite(LED_PIN, i);
delay(10);
}
}更高级的生成PWM信号的方法
对于ESP32单片机,除了使用上述的analogWrite函数输出PWM波形外,还有另一种更加灵活的方法,可以输出特性占空比的PWM波形(其实上面analogWrite的方法底层也是基于本方法实现的)
在此之前,我们先来看一下ESP32官方文档中,关于PWM的描述:
LED_PWM 主要用于控制 LED 的亮度和颜色,也可以产生 PWM 信号用于其他用途。LED_PWM 有 16 路通道, 即 8 路高速通道和 8 路低速通道。这 16 路通道能够产生独立的数字波形来驱动 RGB LED 设备。高速或低速通 道可以由四个高速定时器之一或四个低速定时器之一进行驱动。PWM 控制器还能够自动逐渐增加或减少占空 比,在无须处理器干预的情况下实现亮度和颜色渐变
要使用ESP32上的LED_PWM,流程如下:
调用ledcSetup函数,设置通道、期望分辨率、PWM位宽三个参数;
调用ledcAttachPin函数将GPIO端口与通道进行绑定;
调用ledcWrite函数往通道中输出特定占空比的PWM信号
接下来详细介绍以上三个函数的用法
ledcSetup函数
函数签名如下
uint32_t ledcSetup(uint8_t chan, uint32_t freq, uint8_t bit_num)该函数有三个参数:
chan:为PWM通道编号,一共16个通道,编号0~15,其中0~7为高速通道,8~15为低速通道;
freq:期望的PWM脉冲信号频率,比如指定1000,就表示每秒钟会产生1000个脉冲信号;
bit_num:PWM占空比的位宽,如果位宽为8为,则PWM值的取值范围为0~255(2^8 - 1),如果位宽为10位,则PWM的取值范围为0~1023(2^10 - 1),所以位宽越大,PWM分辨率越高,控制经度更细,对于ESP32,该参数最大值为20
函数的返回值为最终设置成功的频率(参数中freq仅仅为期望频率,并不一定能完全匹配用户期望,最终频率以返回值为准)
ledcAttachPin函数
该函数的作用是将某个GPIO引脚绑定到某个PWM通道,绑定成功后,通道上产生的PWM信号会同步到该GPIO引脚,函数签名如下
void ledcAttachPin(uint8_t pin, uint8_t chan)该函数有两个参数:
pin:GPIO引脚编号,比如5,23等
chan:PWM通道号,0~15
ledcWrite函数
该函数的作用是往某个PWM通道输出指定占空比的PWM波形,函数签名如下
void ledcWrite(uint8_t chan, uint32_t duty)该函数有两个参数:
chan:PWM通道号,0~15
duty:占空比的值,取值范围根据ledcSetup函数设置的bit_num参数决定,为[0, 2^bit_num - 1]
实现呼吸灯效果
接下来我们使用上述三个函数来实现LED呼吸灯效果,代码如下:
#include <Arduino.h>
#define LED_PIN 23 // LED正极引脚连的GPIO
#define PWM_CHAN 0 // 使用的PWM通道号
#define BIT_WIDTH 10 // 设置的PWM位宽
#define FREQ 1000 // 设置的PWM频率
void setup() {
pinMode(LED_PIN, OUTPUT);
ledcSetup(PWM_CHAN, FREQ, BIT_WIDTH);
ledcAttachPin(LED_PIN, PWM_CHAN);
}
void loop() {
// 占空比从0到1023,逐渐变大,每次中间延迟1ms,不然程序运行太快眼睛无法查看效果
for (int i = 0; i < pow(2, BIT_WIDTH); i++) {
ledcWrite(PWM_CHAN, i);
delay(1);
}
// 占空比从1023到0,逐渐变小
for (int i = pow(2, BIT_WIDTH) - 1; i >= 0; i--) {
ledcWrite(PWM_CHAN, i);
delay(1);
}
}