PWM驱动LED平滑调光与多彩灯效设计
硬件方案选型
核心器件配置
| 功能单元 | 技术指标 | 常用型号 |
|---|---|---|
| 主控芯片 | 硬件PWM输出,≥3路独立通道 | STM32F4系列、ESP32-S3 |
| 发光器件 | 三基色合成,支持模拟/数字驱动 | 共阴RGB LED、SK6812 |
| 限流元件 | 精度±1%,功耗适配 | 0603贴片电阻,100Ω~680Ω |
| 供电单元 | 纹波<50mV,瞬态响应快 | LD33/LD50 LDO或DC-DC模块 |
以ESP32-S3为例的接线示意:
ESP32-S3引脚 → RGB LED模组
-----------------------------
LEDC_CH0 (GPIO4) → 红色通道
LEDC_CH1 (GPIO5) → 绿色通道
LEDC_CH2 (GPIO6) → 蓝色通道
GND → 公共阴极
3.3V → 阳极供电(共阴方案)
关键参数核算
- 限流电阻选取:R = (VCC − VF − VCE(sat)) / IF,典型值3.3V系统选180Ω~330Ω
- PWM载波频率:人眼无闪烁阈值>100Hz,推荐1kHz~5kHz兼顾分辨率与EMI
核心算法实现
渐变插值引擎
// 色彩空间描述
typedef struct {
uint16_t cr; // 红色分量,Q16定点
uint16_t cg; // 绿色分量
uint16_t cb; // 蓝色分量
uint8_t ch_idx; // LEDC通道编号
} ColorChannel;
// 带缓动函数的渐变处理
void ease_fade_update(ColorChannel *grp, uint8_t ch_cnt,
const uint16_t *dest, uint16_t delta,
uint32_t tick_ms) {
static uint32_t last_tick = 0;
if (xTaskGetTickCount() - last_tick < tick_ms) return;
last_tick = xTaskGetTickCount();
for (uint8_t i = 0; i < ch_cnt; i++) {
int32_t err = (int32_t)dest[i] - grp[i].cr;
int32_t step = (err > 0) ? delta : -delta;
if (abs(err) < delta) step = err;
grp[i].cr += step;
ledc_set_duty(LEDC_LOW_SPEED_MODE, grp[i].ch_idx, grp[i].cr);
ledc_update_duty(LEDC_LOW_SPEED_MODE, grp[i].ch_idx);
}
}
STM32 HAL呼吸灯实现
// TIM2初始化:72MHz APB1,目标1kHz PWM
void TIM2_PWM_Config(void) {
__HAL_RCC_TIM2_CLK_ENABLE();
TIM_HandleTypeDef htim = {0};
htim.Instance = TIM2;
htim.Init.Prescaler = 71; // 分频至1MHz
htim.Init.Period = 999; // 1kHz周期
htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&htim);
TIM_OC_InitTypeDef oc = {0};
oc.OCMode = TIM_OCMODE_PWM1;
oc.Pulse = 0;
oc.OCPolarity = TIM_OCPOLARITY_HIGH;
oc.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim, &oc, TIM_CHANNEL_1);
HAL_TIM_PWM_ConfigChannel(&htim, &oc, TIM_CHANNEL_2);
HAL_TIM_PWM_ConfigChannel(&htim, &oc, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_3);
}
// 查表法正弦呼吸,256点/周期
void breathing_task(void) {
static const uint16_t sine_lut[256] = { /* 预计算0~999 */ };
static uint8_t phase = 0;
uint16_t r = sine_lut[phase];
uint16_t g = sine_lut[(phase + 85) & 0xFF];
uint16_t b = sine_lut[(phase + 170) & 0xFF];
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, r);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, g);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, b);
phase++;
HAL_Delay(20);
}
高级色彩合成
HSV转RGB硬件加速版
// 输入:H∈[0,360), S∈[0,1], V∈[0,1]
// 输出:16位PWM占空比
void hsv_to_pwm(float h, float s, float v,
uint16_t *r_out, uint16_t *g_out, uint16_t *b_out) {
float c = v * s;
float hh = h / 60.0f;
float x = c * (1.0f - fabsf(fmodf(hh, 2.0f) - 1.0f));
float m = v - c;
float r, g, b;
switch ((uint8_t)hh) {
case 0: r = c; g = x; b = 0; break;
case 1: r = x; g = c; b = 0; break;
case 2: r = 0; g = c; b = x; break;
case 3: r = 0; g = x; b = c; break;
case 4: r = x; g = 0; b = c; break;
default: r = c; g = 0; b = x; break;
}
*r_out = (uint16_t)((r + m) * 65535);
*g_out = (uint16_t)((g + m) * 65535);
*b_out = (uint16_t)((b + m) * 65535);
}
// 彩虹循环任务
void rainbow_cycle(void *pv) {
float hue = 0.0f;
uint16_t rd, gd, bd;
while (1) {
hsv_to_pwm(hue, 1.0f, 0.8f, &rd, &gd, &bd);
ledc_set_duty(LEDC_LOW_SPEED_MODE, R_CH, rd);
ledc_set_duty(LEDC_LOW_SPEED_MODE, G_CH, gd);
ledc_set_duty(LEDC_LOW_SPEED_MODE, B_CH, bd);
ledc_update_duty(LEDC_LOW_SPEED_MODE, R_CH);
ledc_update_duty(LEDC_LOW_SPEED_MODE, G_CH);
ledc_update_duty(LEDC_LOW_SPEED_MODE, B_CH);
hue += 0.5f;
if (hue >= 360.0f) hue = 0.0f;
vTaskDelay(pdMS_TO_TICKS(30));
}
}
工程化设计要点
驱动级保护机制
// 电流监测与过流关断
#define I_MAX_MA 350
#define R_SENSE 0.47f
#define ADC_FULLSCALE 4095
void safety_monitor_task(void *pv) {
while (1) {
uint16_t adc_val = HAL_ADC_GetValue(&hadc1);
float current = adc_val * 3.3f / ADC_FULLSCALE / R_SENSE;
if (current > I_MAX_MA) {
// 立即关闭所有PWM通道
TIM2->CCR1 = TIM2->CCR2 = TIM2->CCR3 = 0;
system_set_fault(FAULT_OVERCURRENT);
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
低功耗休眠唤醒
// 停止模式配置,保留GPIO状态
void enter_light_sleep(void) {
HAL_SuspendTick();
// 配置EXTI唤醒源
HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 唤醒后恢复时钟
SystemClock_Config();
HAL_ResumeTick();
}
void EXTI0_IRQHandler(void) {
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) {
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
}
}
场景化应用实例
自适应环境光照明
typedef struct {
uint16_t warm_white; // 暖色温通道
uint16_t cool_white; // 冷色温通道
float cct_target; // 目标色温
} AmbientLightCtx;
void adaptive_light_control(AmbientLightCtx *ctx) {
float lux = bh1750_read_lux();
uint16_t ambient = (uint16_t)(lux / 54612.0f * 65535); // 归一化
// 根据时段调整色温:早晨偏暖,正午偏冷
RTC_TimeTypeDef now;
HAL_RTC_GetTime(&hrtc, &now, RTC_FORMAT_BIN);
if (now.Hours >= 6 && now.Hours < 18) {
ctx->cct_target = 6500.0f; // 日光
} else {
ctx->cct_target = 2700.0f; // 暖白
}
// 混光计算并输出
uint16_t ww, cw;
cct_mix_calculate(ctx->cct_target, ambient, &ww, &cw);
ledc_set_duty(LEDC_LOW_SPEED_MODE, WW_CH, ww);
ledc_set_duty(LEDC_LOW_SPEED_MODE, CW_CH, cw);
}
可编程灯效状态机
typedef enum {
PAT_IDLE,
PAT_FADE_IN,
PAT_HOLD,
PAT_FADE_OUT,
PAT_RAINBOW,
PAT_STROBE
} LightPattern;
typedef struct {
LightPattern state;
uint32_t enter_tick;
uint16_t param_hue;
uint8_t param_speed;
} PatternState;
void pattern_engine_run(PatternState *sm) {
switch (sm->state) {
case PAT_RAINBOW: {
float h = (xTaskGetTickCount() - sm->enter_tick)
* sm->param_speed / 1000.0f;
uint16_t r, g, b;
hsv_to_pwm(fmodf(h, 360.0f), 1.0f, 1.0f, &r, &g, &b);
pwm_update_all(r, g, b);
break;
}
case PAT_STROBE: {
uint32_t phase = (xTaskGetTickCount() - sm->enter_tick) % 200;
uint16_t lvl = (phase < 20) ? 65535 : 0;
pwm_update_all(lvl, lvl, lvl);
break;
}
default:
pwm_update_all(0, 0, 0);
}
}