4. RGB LED调色
任务目标
使用ESP32的三个PWM通道分别驱动RGB LED的红、绿、蓝引脚,通过调节各通道占空比实现颜色混合。本案例提供手动调节接口,可独立调整红、绿、蓝分量,并实时观察混合颜色。
硬件与接线
- ESP32开发板 ×1
- 共阴RGB LED ×1(若为共阳,需将占空比逻辑取反)
- 220Ω电阻 ×3(分别串联在R、G、B引脚)
| RGB LED引脚 | ESP32 GPIO |
|---|---|
| R(红) | GPIO 25 |
| G(绿) | GPIO 26 |
| B(蓝) | GPIO 27 |
| GND(共阴) | GND |
实现原理
ESP32的LEDC(LED Control)外设提供硬件PWM输出。本案例使用三个LEDC通道(0、1、2),分别绑定到上述GPIO。PWM分辨率为8位(0~255),频率设为5kHz(LED无频闪且功耗合理)。通过修改每个通道的占空比,即可独立控制红绿蓝亮度,叠加后呈现目标颜色。
关键完整代码
#include <stdio.h>
#include "driver/ledc.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// GPIO定义
#define LEDC_R_GPIO 25
#define LEDC_G_GPIO 26
#define LEDC_B_GPIO 27
// PWM参数
#define LEDC_FREQ_HZ 5000
#define LEDC_RES LEDC_TIMER_8_BIT // 8位分辨率,占空比0~255
// 三个通道
#define LEDC_CH_R LEDC_CHANNEL_0
#define LEDC_CH_G LEDC_CHANNEL_1
#define LEDC_CH_B LEDC_CHANNEL_2
// 当前RGB值(全局变量,便于手动修改)
uint8_t g_red = 128;
uint8_t g_green = 64;
uint8_t g_blue = 192;
// 初始化单个LEDC通道
static void ledc_channel_init(ledc_channel_t ch, gpio_num_t gpio)
{
ledc_channel_config_t ch_cfg = {
.gpio_num = gpio,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = ch,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER_0,
.duty = 0,
.hpoint = 0,
};
ledc_channel_config(&ch_cfg);
}
// 更新三个通道的占空比
static void rgb_update(void)
{
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CH_R, g_red);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CH_G, g_green);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CH_B, g_blue);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CH_R);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CH_G);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CH_B);
}
void app_main(void)
{
// 配置定时器(三个通道共用Timer0)
ledc_timer_config_t timer_cfg = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = LEDC_RES,
.timer_num = LEDC_TIMER_0,
.freq_hz = LEDC_FREQ_HZ,
.clk_cfg = LEDC_AUTO_CLK,
};
ledc_timer_config(&timer_cfg);
// 初始化三个通道
ledc_channel_init(LEDC_CH_R, LEDC_R_GPIO);
ledc_channel_init(LEDC_CH_G, LEDC_G_GPIO);
ledc_channel_init(LEDC_CH_B, LEDC_B_GPIO);
// 应用初始颜色
rgb_update();
// 手动调节演示:循环改变RGB值
while (1) {
// 示例:每2秒切换一组颜色
g_red = 255; g_green = 0; g_blue = 0; rgb_update(); vTaskDelay(pdMS_TO_TICKS(2000));
g_red = 0; g_green = 255; g_blue = 0; rgb_update(); vTaskDelay(pdMS_TO_TICKS(2000));
g_red = 0; g_green = 0; g_blue = 255; rgb_update(); vTaskDelay(pdMS_TO_TICKS(2000));
g_red = 255; g_green = 255; g_blue = 0; rgb_update(); vTaskDelay(pdMS_TO_TICKS(2000));
g_red = 0; g_green = 255; g_blue = 255; rgb_update(); vTaskDelay(pdMS_TO_TICKS(2000));
g_red = 255; g_green = 0; g_blue = 255; rgb_update(); vTaskDelay(pdMS_TO_TICKS(2000));
g_red = 128; g_green = 128; g_blue = 128; rgb_update(); vTaskDelay(pdMS_TO_TICKS(2000));
}
}
编译与烧录
# 在ESP-IDF项目目录下(需先创建项目并复制上述代码到main.c)
idf.py set-target esp32
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor
若使用Arduino IDE,将上述代码放入.ino文件,开发板选择“ESP32 Dev Module”,直接编译上传即可(需包含
验证方法
- 观察现象:烧录后LED应按顺序显示红→绿→蓝→黄(红+绿)→青(绿+蓝)→紫(红+蓝)→白(等量混合),每种颜色持续2秒。
- 手动调节:在
while(1)循环中修改g_red、g_green、g_blue的赋值(0~255),重新编译烧录后,LED颜色应随设定值变化。例如设置g_red=255, g_green=128, g_blue=0时,LED应呈现橙色。 - 判定通过:若LED颜色与代码中RGB设定值对应的标准色一致(可参考下表),且切换顺序正确,则案例实现成功。
| RGB值 (R,G,B) | 预期颜色 |
|---|---|
| (255,0,0) | 红 |
| (0,255,0) | 绿 |
| (0,0,255) | 蓝 |
| (255,255,0) | 黄 |
| (0,255,255) | 青 |
| (255,0,255) | 紫 |
| (128,128,128) | 白(中等亮度) |
常见问题
- LED不亮:检查共阴/共阳接法。若为共阳LED,需将占空比取反(即
duty = 255 - value),且GND引脚应接3.3V而非GND。 - 颜色偏暗或偏色:确认三个串联电阻阻值一致(220Ω),否则各通道最大电流不同导致亮度不均衡。
- PWM频率过低出现闪烁:本案例使用5kHz,人眼无法分辨。若自行修改频率,建议不低于1kHz。