使用 ESP32-S3 的 LED PWM 控制器控制 LED 亮度

引言

在物联网(IoT)设备中,LED 控制是一个常见的应用场景。ESP32-S3 开发板提供了强大的 LED PWM 控制器(LEDC),可以用来控制 LED 的亮度以及其他需要 PWM 信号的应用。本文将详细介绍如何使用 ESP-IDF 框架中的 LEDC 驱动程序来控制 LED 的亮度。

环境准备

在开始之前,请确保你已经安装了 ESP-IDF 开发环境,并且熟悉基本的 ESP32 项目构建流程。如果你还没有安装 ESP-IDF,可以从 Espressif 官网 获取安装指南。

LED PWM 控制器概述

简介

LED 控制器 (LEDC) 主要用于控制 LED,也可产生 PWM 信号用于其他设备的控制。该控制器有 8 路通道,可以产生独立的波形,驱动 RGB LED 等设备。LEDC PWM 控制器可在无需 CPU 干预的情况下自动改变占空比,实现亮度和颜色渐变。

功能概览

  1. 设置 LEDC 通道

    • 定时器配置:指定 PWM 信号的频率和占空比分辨率。
    • 通道配置:绑定定时器和输出 PWM 信号的 GPIO。
    • 改变 PWM 信号:输出 PWM 信号来驱动 LED。可通过软件控制或使用硬件渐变功能来改变 LED 的亮度。
  2. 电源管理

    • LEDC 驱动不使用电源管理锁来防止系统进入 Light-sleep。可以通过配置ledc_channel_config_t::sleep_mode来选择 LEDC 外设电源域状态和 PWM 信号在睡眠期间的输出行为。
  3. 频率和占空比分辨率支持范围

    • LED PWM 控制器主要用于驱动 LED。该控制器 PWM 占空比设置的分辨率范围较广。例如,PWM 频率为 5 kHz 时,占空比分辨率最大可为 13 位。然而,这些参数取决于为 LEDC 定时器计时的时钟信号。

示例代码

我们将使用 ESP-IDF 提供的示例代码来演示如何使用 LEDC 驱动程序控制 LED 的亮度。以下是完整的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include "driver/ledc.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

static const char* TAG = "example";

// LEDC 通道配置
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_OUTPUT_IO (2) // 根据你的硬件连接修改 GPIO
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_DUTY_RESOLUTION 10 // 占空比分辨率
#define LEDC_FREQUENCY (5000) // PWM 频率 (Hz)

void app_main(void)
{
// 配置 LEDC 定时器
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_MODE,
.timer_num = LEDC_TIMER,
.duty_resolution = LEDC_DUTY_RESOLUTION,
.freq_hz = LEDC_FREQUENCY,
.clk_cfg = LEDC_AUTO_CLK,
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));

// 配置 LEDC 通道
ledc_channel_config_t ledc_channel = {
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = LEDC_OUTPUT_IO,
.duty = 0, // 初始占空比
.hpoint = 0,
.flags = 0,
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));

// 循环改变 LED 亮度
while (1) {
for (int duty = 0; duty <= 1023; duty++) {
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
vTaskDelay(pdMS_TO_TICKS(10));
}
for (int duty = 1023; duty >= 0; duty--) {
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
vTaskDelay(pdMS_TO_TICKS(10));
}
}
}

代码解析

1. 包含头文件

1
2
3
4
#include "driver/ledc.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
  • driver/ledc.h:包含 LEDC 驱动程序的 API 声明。
  • esp_log.h:包含日志记录功能。
  • freertos/FreeRTOS.hfreertos/task.h:包含 FreeRTOS 任务管理功能。

2. 定义日志标签

1
static const char* TAG = "example";
  • 定义了一个日志标签,用于标识日志信息的来源。

3. 定义 LEDC 配置参数

1
2
3
4
5
6
#define LEDC_TIMER              LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_OUTPUT_IO (2) // 根据你的硬件连接修改 GPIO
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_DUTY_RESOLUTION 10 // 占空比分辨率
#define LEDC_FREQUENCY (5000) // PWM 频率 (Hz)
  • LEDC_TIMER:使用的定时器编号。
  • LEDC_MODE:速度模式,ESP32-S3 仅支持低速模式。
  • LEDC_OUTPUT_IO:输出 PWM 信号的 GPIO 编号。
  • LEDC_CHANNEL:使用的通道编号。
  • LEDC_DUTY_RESOLUTION:占空比分辨率。
  • LEDC_FREQUENCY:PWM 信号的频率。

4. 配置 LEDC 定时器

1
2
3
4
5
6
7
8
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_MODE,
.timer_num = LEDC_TIMER,
.duty_resolution = LEDC_DUTY_RESOLUTION,
.freq_hz = LEDC_FREQUENCY,
.clk_cfg = LEDC_AUTO_CLK,
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
  • 创建一个ledc_timer_config_t结构体,并设置定时器参数。
  • 使用ledc_timer_config函数配置定时器。

5. 配置 LEDC 通道

1
2
3
4
5
6
7
8
9
10
11
ledc_channel_config_t ledc_channel = {
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = LEDC_OUTPUT_IO,
.duty = 0, // 初始占空比
.hpoint = 0,
.flags = 0,
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
  • 创建一个ledc_channel_config_t结构体,并设置通道参数。
  • 使用ledc_channel_config函数配置通道。

6. 循环改变 LED 亮度

1
2
3
4
5
6
7
8
9
10
11
12
while (1) {
for (int duty = 0; duty <= 1023; duty++) {
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
vTaskDelay(pdMS_TO_TICKS(10));
}
for (int duty = 1023; duty >= 0; duty--) {
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
vTaskDelay(pdMS_TO_TICKS(10));
}
}
  • 在一个无限循环中,逐步增加和减少占空比,从而实现 LED 亮度的渐变。
  • 使用ledc_set_duty设置新的占空比,并使用ledc_update_duty使新配置生效。
  • 使用vTaskDelay设置任务延迟,控制亮度变化的速度。

使用中断

LEDC 驱动还可以配置中断,在渐变完成时触发中断。以下是一个简单的示例,展示如何注册中断处理程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void IRAM_ATTR ledc_fade_isr(void* arg)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// 处理中断事件
ESP_LOGI(TAG, "Fade complete");
portYIELD_FROM_ISR();
}

void app_main(void)
{
// 配置 LEDC 定时器和通道(同上)

// 注册中断处理程序
ledc_isr_register(ledc_fade_isr, NULL, ESP_INTR_FLAG_IRAM, NULL);

// 启用渐变功能
ledc_fade_func_install(0);

// 设置渐变参数并启动渐变
ledc_set_fade_with_time(LEDC_MODE, LEDC_CHANNEL, 1023, 1000);
ledc_fade_start(LEDC_MODE, LEDC_CHANNEL, LEDC_FADE_NO_WAIT);
}

7. 注册中断处理程序

1
ledc_isr_register(ledc_fade_isr, NULL, ESP_INTR_FLAG_IRAM, NULL);
  • 使用ledc_isr_register函数注册中断处理程序。
  • ledc_fade_isr:中断处理函数。
  • ESP_INTR_FLAG_IRAM:确保中断处理函数在 IRAM 中执行。

8. 启用渐变功能

1
ledc_fade_func_install(0);
  • 使用ledc_fade_func_install函数启用渐变功能。

9. 设置渐变参数并启动渐变

1
2
ledc_set_fade_with_time(LEDC_MODE, LEDC_CHANNEL, 1023, 1000);
ledc_fade_start(LEDC_MODE, LEDC_CHANNEL, LEDC_FADE_NO_WAIT);
  • 使用ledc_set_fade_with_time函数设置渐变参数。
  • 使用ledc_fade_start函数启动渐变。

总结

通过上述代码,我们可以轻松地在 ESP32-S3 上实现对 LED 的 PWM 控制,从而控制 LED 的亮度。这个示例展示了如何使用 ESP-IDF 提供的 LEDC 驱动程序进行基本的操作,包括定时器配置、通道配置和改变 PWM 信号。你可以根据实际需求,进一步扩展这个示例,比如控制多个 LED 或实现更复杂的渐变效果。

希望这篇博客笔记对你有所帮助!如果你有任何问题或建议,欢迎在评论区留言。

参考文档


使用 ESP32-S3 的 LED PWM 控制器控制 LED 亮度
https://bubao.github.io/posts/11756890.html
作者
一念
发布于
2025年5月18日
许可协议