ESP32-S3的软件脉冲宽度调制(SW_PWM)
引言
ESP32-S3 LED 控制器LEDC 主要用于控制 LED,也可产生PWM信号用于其他设备的控制。该控制器有 8 路通道,可以产生独立的波形,驱动 RGB LED 等设备。LED PWM 控制器可在无需CPU 干预的情况下自动改变占空比,实现亮度渐变。ESP32-S3 IDF 提供了两种方式改变 PWM,一种是通过软件改变 PWM 占空比,另一种是通过硬件改变PWM 占空比,本博客讲解软件脉冲宽度调制的方法
什么是脉冲宽度调制(PWM)🤔
脉冲宽度调制(PWM)是一种在数字系统中模拟模拟信号的方法。通过改变脉冲的宽度,我们可以控制电源的输出,从而控制例如LED的亮度或电机的速度。
ESP32-S3的SW_PWM 控制器
ESP32-S3 的LED PWM 控制器,简写为LEDC,用于生成控制LED 的脉冲宽度调制信号。 LED PWM 控制器具有八个独立的 PWM 生成器(即八个通道)。每个 PWM 生成器会从四个通用定时器中选择一个,以该定时器的计数值作为基准生成 PWM 信号👇。
✨LED PWM 控制器具有如下特性:
- 八个独立的 PWM 生成器(即八个通道)
- 四个独立定时器,可实现小数分频
- 占空比自动渐变(即 PWM 信号占空比可逐渐增加或减小,无须处理器干预),渐变完成时产生中断
- 输出 PWM 信号相位可调
- 低功耗模式 (Light-sleep mode) 下可输出 PWM 信号
- PWM 最大精度为 14 位
为了实现PWM 输出,先需要设置指定通道的PWM 参数:频率、分辨率、占空比,然后将该通道映射到指定引脚,同时LED PWM 控制器可在没有CPU 干预的情况下自动改变占空比,实现亮度以及颜色渐变。
ESP32-S3的SW_PWM功能允许我们通过软件来控制PWM,而不需要额外的硬件。这意味着我们可以使用任何GPIO引脚作为PWM输出,极大地提高了系统的灵活性。
如何使用ESP32-S3的SW_PWM
要使用ESP32-S3的SW_PWM,我们需要进行以下步骤:
- 配置LEDC 使用的定时器为定时器 1
- 配置LEDC 使用的通道为通道 1
- 配置LEDC 定时器占空比值
✨注意,与 ESP32 不同,ESP32-S3 仅支持设置通道为低速模式。
1️⃣配置 LEDC 使用的定时器为定时器1
需要注意的一点是,在首次配置LEDC 时,建议先配置定时器(调用函数 ledc_timer_config()),再配置通道(调用函数 ledc_channel_config())。这样可以确保 IO 引脚上的PWM 信号自输出开始那一刻起,其频率就是正确的。
✨要设置定时器,可调用函数ledc_timer_config()
esp_err_t ledc_timer_config(const ledc_timer_config_t *timer_conf);
函数形参描述:
形参 | 描述 |
---|---|
timer_conf | 指向配置LEDC定时器的结构体指针 |
函数返回值描述:
返回值 | 描述 |
---|---|
ESP_OK | 返回0,配置成功 |
ESP_ERR_INVALID_ARG | 参数错误 |
ESP_FAIL | 无法根据给定的频率和当前的duty_solution找到合适的预分频器编号 |
该函数使用ledc_timer_config_t类型的结构体变量传入LEDC的配置参数。
2️⃣配置 LEDC 使用的通道为通道1
✨调用ledc_channel_config()
来配置通道
esp_err_t ledc_channel_config(const ledc_channel_config_t *ledc_conf);
函数形参描述:
形参 | 描述 |
---|---|
ledc_conf | 指向配置LEDC通道的结构体指针 |
函数返回值描述:
返回值 | 描述 |
---|---|
ESP_OK | 返回0,配置成功 |
ESP_ERR_INVALID_ARG | 参数错误 |
该函数使用ledc_channel_config_t类型的结构体变量传入LEDC的通道配置参数。
3️⃣配置LEDC 定时器占空比值
✨ledc_set_duty
函数用于设置指定LEDC通道的占空比值
esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty);
函数形参描述:
形参 | 描述 |
---|---|
speed_mode | LEDC的速度模式,指定LED控制器的速度模式 |
channel | LEDC通道的索引,指定要配置的通道 |
duty | LEDC通道的占空比值,即PWM信号的占空比 |
🔮占空比怎么计算
如果设置了某个通道的PWM分辨率为16位,那么duty的值理论上可以在0到65535之间变化(因为2^16 = 65536,包括0和65535两个极端值),如果配置占空比为
70
%
70\%
70%
d
u
t
y
=
70
%
×
65535
=
0.7
×
65535
≈
45874
duty=70\% \times 65535 = 0.7 \times 65535 \approx 45874
duty=70%×65535=0.7×65535≈45874
函数返回值描述:
该函数返回ESP_OK(0)表示配置成功👌。
✨ledc_update_duty
函数用于更新指定LEDC通道的占空比值。
在调用 ledc_set_duty
函数设置占空比后,必须调用 ledc_update_duty
函数才能使设置生效。它的功能是更新指定通道的占空比,确保之前设置的占空比值在LEDC的通道中生效。
函数原型:
esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
函数形参描述:
形参 | 描述 |
---|---|
speed_mode | LEDC的速度模式,指定LED控制器的速度模式 |
channel | LEDC通道的索引,指定要更新占空比的通道 |
函数返回值描述:
该函数返回ESP_OK(0)表示更新成功👌。
示例如何使用ESP32-S3的SW_PWM来控制一个LED的亮度:
#include "driver/ledc.h"
#define LEDC_TIMER LEDC_TIMER_1 // LEDC定时器
#define LEDC_MODE LEDC_LOW_SPEED_MODE // LEDC模式
#define LEDC_CH1_GPIO (10) // LEDC通道1 GPIO引脚
#define LEDC_CH1_CHANNEL LEDC_CHANNEL_1 // LEDC通道1
#define LEDC_TEST_DUTY (4000) // LEDC测试占空比
#define LEDC_TEST_FADE_TIME (3000) // LEDC测试淡入淡出时间
void app_main(void)
{
// ①:配置LEDC使用的定时器为定时器1
ledc_timer_config_t ledc_timer = {
.duty_resolution = LEDC_TIMER_13_BIT, // PWM占空比分辨率
.freq_hz = 5000, // PWM信号频率
.speed_mode = LEDC_MODE, // 定时器模式
.timer_num = LEDC_TIMER // 定时器索引
};
// 使用之前准备好的配置设置定时器
ledc_timer_config(&ledc_timer);
// ②:配置LEDC使用的通道为通道1
ledc_channel_config_t ledc_channel = {
.channel = LEDC_CH1_CHANNEL, // LEDC通道号设置为通道1
.duty = 0, // 初始占空比为0
.gpio_num = LEDC_CH1_GPIO, // GPIO引脚设置为LEDC_CH1_GPIO
.speed_mode = LEDC_MODE, // 使用LEDC模式
.hpoint = 0, // 占空比更新点设为0
.timer_sel = LEDC_TIMER // 使用LEDC定时器1
};
// 使用之前准备好的配置设置LEDC通道
ledc_channel_config(&ledc_channel);
// ③:配置LEDC定时器占空比值
ledc_set_duty(ledc_channel.speed_mode, ledc_channel.channel, LEDC_TEST_DUTY);
ledc_update_duty(ledc_channel.speed_mode, ledc_channel.channel);
}
结论
参考资料乐鑫官方文档👇
🚩LED PWM 控制器