4. RGB LED调色

任务目标

使用ESP32的三个PWM通道分别驱动RGB LED的红、绿、蓝引脚,通过调节各通道占空比实现颜色混合,最终输出指定的颜色(例如紫色:红255、绿0、蓝255)。

所需硬件与接线

  • ESP32开发板 ×1
  • 共阴RGB LED ×1(若为共阳,需反转占空比逻辑)
  • 220Ω电阻 ×3(分别串联在R、G、B引脚上)
  • 杜邦线若干
RGB LED引脚ESP32 GPIO
R(红)GPIO25
G(绿)GPIO26
B(蓝)GPIO27
GND(共阴)GND

实现原理

ESP32的LEDC(LED Control)外设可输出硬件PWM。本案例使用三个LEDC通道(0、1、2),分别绑定到上述三个GPIO。通过设置占空比(0~255)控制各颜色分量强度,利用人眼视觉暂留效应混合出目标颜色。代码中定义setColor(r, g, b)函数,一次调用即可输出任意RGB组合。

关键完整代码


#include <stdio.h>
#include "driver/ledc.h"
#include "esp_err.h"

#define LED_R_GPIO  25
#define LED_G_GPIO  26
#define LED_B_GPIO  27

#define LEDC_TIMER      LEDC_TIMER_0
#define LEDC_MODE       LEDC_LOW_SPEED_MODE
#define LEDC_DUTY_RES   LEDC_TIMER_8_BIT   // 8位分辨率,占空比0~255
#define LEDC_FREQ_HZ    5000               // 5kHz PWM频率

// 三个通道分别对应R、G、B
#define CH_R   LEDC_CHANNEL_0
#define CH_G   LEDC_CHANNEL_1
#define CH_B   LEDC_CHANNEL_2

// 初始化PWM定时器与三个通道
static void pwm_init(void) {
    ledc_timer_config_t timer_conf = {
        .speed_mode      = LEDC_MODE,
        .timer_num       = LEDC_TIMER,
        .duty_resolution = LEDC_DUTY_RES,
        .freq_hz         = LEDC_FREQ_HZ,
        .clk_cfg         = LEDC_AUTO_CLK
    };
    ledc_timer_config(&timer_conf);

    ledc_channel_config_t ch_conf = {
        .gpio_num   = LED_R_GPIO,
        .speed_mode = LEDC_MODE,
        .channel    = CH_R,
        .intr_type  = LEDC_INTR_DISABLE,
        .timer_sel  = LEDC_TIMER,
        .duty       = 0,
        .hpoint     = 0
    };
    ledc_channel_config(&ch_conf);

    ch_conf.gpio_num = LED_G_GPIO;
    ch_conf.channel  = CH_G;
    ledc_channel_config(&ch_conf);

    ch_conf.gpio_num = LED_B_GPIO;
    ch_conf.channel  = CH_B;
    ledc_channel_config(&ch_conf);
}

// 设置RGB颜色,r/g/b取值范围0~255
static void setColor(int r, int g, int b) {
    ledc_set_duty(LEDC_MODE, CH_R, r);
    ledc_update_duty(LEDC_MODE, CH_R);
    ledc_set_duty(LEDC_MODE, CH_G, g);
    ledc_update_duty(LEDC_MODE, CH_G);
    ledc_set_duty(LEDC_MODE, CH_B, b);
    ledc_update_duty(LEDC_MODE, CH_B);
}

void app_main(void) {
    pwm_init();

    // 输出紫色:红=255,绿=0,蓝=255
    setColor(255, 0, 255);
    printf("紫色输出中: R=255, G=0, B=255\n");

    // 每3秒切换一次颜色,便于观察
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(3000));
        setColor(0, 255, 0);    // 绿色
        printf("绿色输出中: R=0, G=255, B=0\n");
        vTaskDelay(pdMS_TO_TICKS(3000));
        setColor(255, 255, 0);  // 黄色
        printf("黄色输出中: R=255, G=255, B=0\n");
        vTaskDelay(pdMS_TO_TICKS(3000));
        setColor(0, 0, 255);    // 蓝色
        printf("蓝色输出中: R=0, G=0, B=255\n");
        vTaskDelay(pdMS_TO_TICKS(3000));
        setColor(255, 0, 255);  // 回到紫色
        printf("紫色输出中: R=255, G=0, B=255\n");
    }
}

编译与烧录

  1. 在ESP-IDF环境中创建项目,将上述代码保存为main.c,替换项目中的默认源文件。
  2. 在项目根目录执行idf.py set-target esp32(如未设置)。
  3. 执行idf.py build编译。
  4. 连接开发板,执行idf.py -p /dev/ttyUSB0 flash monitor烧录并打开串口监视器(Windows端口号请按实际修改)。

验证方法与通过标准

  • 观察RGB LED颜色是否按串口日志顺序变化:紫色→绿色→黄色→蓝色→紫色循环,每3秒切换一次。
  • 若LED为共阳型,需将setColor中的占空值改为255 - r、255 - g、255 - b,否则颜色会互补。
  • 串口输出与LED实际颜色一致即判定通过。若颜色偏差明显,检查GPIO接线是否正确、电阻是否遗漏。

常见问题

  • LED不亮:检查GPIO号是否与代码一致,共阴LED的GND是否接对。
  • 颜色偏暗:确认PWM频率不低于1kHz,避免肉眼可见闪烁;检查电阻阻值是否过大。
  • 颜色不准:不同批次LED亮度曲线不同,可微调各通道占空比上限(如将255改为200)以平衡亮度。