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”,直接编译上传即可(需包含,ESP32 Arduino内核已内置该驱动)。

验证方法

  • 观察现象:烧录后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。