[应用相关] STM32 PWM调光RGB灯炫彩效果

[复制链接]
334|0
Puchou 发表于 2025-11-6 18:29 | 显示全部楼层 |阅读模式
以下是基于STM32控制普通RGB灯(共阴极)实现颜色变化的代码示例,通过PWM调光实现渐变、呼吸、彩虹循环等效果。代码使用STM32 HAL库,适配STM32F103系列,其他型号可参考修改定时器和引脚配置。

一、硬件与配置说明
硬件:共阴极RGB灯(R、G、B引脚分别接STM32的TIM2_CH1~CH3);
定时器:TIM2生成3路PWM(频率1kHz,占空比0~100%);
效果:实现彩虹循环、呼吸灯、单色渐变三种常用颜色变化效果。
二、完整代码
1. 头文件与宏定义(rgb_led.h)
#ifndef __RGB_LED_H
#define __RGB_LED_H

#include "stm32f1xx_hal.h"

// 定时器与通道定义(根据实际配置修改)
#define RGB_TIM_HANDLE &htim2
#define R_CHANNEL TIM_CHANNEL_1
#define G_CHANNEL TIM_CHANNEL_2
#define B_CHANNEL TIM_CHANNEL_3

// 亮度范围(0~255)
#define RGB_MAX_BRIGHTNESS 255
// PWM占空比最大值(对应定时器ARR值,需与CubeMX配置一致)
#define PWM_MAX_VALUE 999

// 函数声明
void rgb_init(void);
void rgb_set_color(uint8_t r, uint8_t g, uint8_t b);
void rgb_rainbow_cycle(uint16_t delay_ms);
void rgb_breath_effect(uint8_t r, uint8_t g, uint8_t b, uint16_t period_ms);
void rgb_fade_effect(uint8_t start_r, uint8_t start_g, uint8_t start_b,
                     uint8_t end_r, uint8_t end_g, uint8_t end_b, uint16_t duration_ms);

#endif






2. 源文件(rgb_led.c)
#include "rgb_led.h"

// 初始化RGB灯(启动PWM)
void rgb_init(void) {
    // 启动3路PWM输出(需确保定时器已初始化)
    HAL_TIM_PWM_Start(RGB_TIM_HANDLE, R_CHANNEL);
    HAL_TIM_PWM_Start(RGB_TIM_HANDLE, G_CHANNEL);
    HAL_TIM_PWM_Start(RGB_TIM_HANDLE, B_CHANNEL);
    // 初始化为黑色(全灭)
    rgb_set_color(0, 0, 0);
}

// 设置RGB颜色(r, g, b范围:0~255)
void rgb_set_color(uint8_t r, uint8_t g, uint8_t b) {
    // 将亮度值映射到PWM占空比(0~PWM_MAX_VALUE)
    uint32_t pwm_r = (r * PWM_MAX_VALUE) / RGB_MAX_BRIGHTNESS;
    uint32_t pwm_g = (g * PWM_MAX_VALUE) / RGB_MAX_BRIGHTNESS;
    uint32_t pwm_b = (b * PWM_MAX_VALUE) / RGB_MAX_BRIGHTNESS;

    // 设置PWM比较值(占空比)
    __HAL_TIM_SET_COMPARE(RGB_TIM_HANDLE, R_CHANNEL, pwm_r);
    __HAL_TIM_SET_COMPARE(RGB_TIM_HANDLE, G_CHANNEL, pwm_g);
    __HAL_TIM_SET_COMPARE(RGB_TIM_HANDLE, B_CHANNEL, pwm_b);
}

// 彩虹循环效果(依次显示红→橙→黄→绿→青→蓝→紫→红)
void rgb_rainbow_cycle(uint16_t delay_ms) {
    // 彩虹色序列(R, G, B)
    uint8_t rainbow_colors[][3] = {
        {255, 0, 0},    // 红
        {255, 165, 0},  // 橙
        {255, 255, 0},  // 黄
        {0, 255, 0},    // 绿
        {0, 255, 255},  // 青
        {0, 0, 255},    // 蓝
        {128, 0, 128},  // 紫
        {255, 0, 0}     // 回到红
    };
    uint8_t color_count = sizeof(rainbow_colors) / sizeof(rainbow_colors[0]);

    // 逐个颜色切换
    for (uint8_t i = 0; i < color_count; i++) {
        rgb_set_color(rainbow_colors[i][0], rainbow_colors[i][1], rainbow_colors[i][2]);
        HAL_Delay(delay_ms);
    }
}

// 呼吸灯效果(指定颜色的亮度渐变)
void rgb_breath_effect(uint8_t r, uint8_t g, uint8_t b, uint16_t period_ms) {
    uint16_t step_delay = period_ms / (2 * RGB_MAX_BRIGHTNESS);  // 每个亮度台阶的延时
    uint8_t brightness;

    // 亮度从0渐增到最大
    for (brightness = 0; brightness <= RGB_MAX_BRIGHTNESS; brightness++) {
        rgb_set_color(
            (r * brightness) / RGB_MAX_BRIGHTNESS,
            (g * brightness) / RGB_MAX_BRIGHTNESS,
            (b * brightness) / RGB_MAX_BRIGHTNESS
        );
        HAL_Delay(step_delay);
    }

    // 亮度从最大渐减到0
    for (brightness = RGB_MAX_BRIGHTNESS; brightness > 0; brightness--) {
        rgb_set_color(
            (r * brightness) / RGB_MAX_BRIGHTNESS,
            (g * brightness) / RGB_MAX_BRIGHTNESS,
            (b * brightness) / RGB_MAX_BRIGHTNESS
        );
        HAL_Delay(step_delay);
    }
}

// 颜色渐变效果(从起始色平滑过渡到目标色)
void rgb_fade_effect(uint8_t start_r, uint8_t start_g, uint8_t start_b,
                     uint8_t end_r, uint8_t end_g, uint8_t end_b, uint16_t duration_ms) {
    uint16_t steps = 100;  // 渐变步数(越多越平滑)
    uint16_t step_delay = duration_ms / steps;  // 每步延时
    int16_t dr = (end_r - start_r) / (int16_t)steps;  // R通道每步变化量
    int16_t dg = (end_g - start_g) / (int16_t)steps;  // G通道每步变化量
    int16_t db = (end_b - start_b) / (int16_t)steps;  // B通道每步变化量

    uint8_t current_r = start_r;
    uint8_t current_g = start_g;
    uint8_t current_b = start_b;

    // 逐步更新颜色
    for (uint16_t i = 0; i < steps; i++) {
        current_r += dr;
        current_g += dg;
        current_b += db;
        // 确保亮度在0~255范围内
        current_r = (current_r < 0) ? 0 : (current_r > 255 ? 255 : current_r);
        current_g = (current_g < 0) ? 0 : (current_g > 255 ? 255 : current_g);
        current_b = (current_b < 0) ? 0 : (current_b > 255 ? 255 : current_b);

        rgb_set_color(current_r, current_g, current_b);
        HAL_Delay(step_delay);
    }
    // 最终颜色确保与目标一致
    rgb_set_color(end_r, end_g, end_b);
}




3. 主函数调用(main.c)
#include "stm32f1xx_hal.h"
#include "rgb_led.h"

TIM_HandleTypeDef htim2;  // 定时器句柄(需与CubeMX配置一致)

// 定时器初始化函数(由CubeMX自动生成,此处简化)
void MX_TIM2_Init(void) {
    TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    TIM_MasterConfigTypeDef sMasterConfig = {0};
    TIM_OC_InitTypeDef sConfigOC = {0};

    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 71;  // 72MHz / (71+1) = 1MHz
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 999;    // 1MHz / (999+1) = 1kHz PWM
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
        Error_Handler();
    }
    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
        Error_Handler();
    }
    if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) {
        Error_Handler();
    }
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) {
        Error_Handler();
    }
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 0;  // 初始占空比0
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    // 配置3个通道
    if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) {Error_Handler();}
    if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) {Error_Handler();}
    if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK) {Error_Handler();}
    HAL_TIM_MspPostInit(&htim2);  // 初始化GPIO(由CubeMX生成)
}

int main(void) {
    HAL_Init();
    MX_TIM2_Init();  // 初始化定时器
    rgb_init();      // 初始化RGB灯

    while (1) {
        // 效果1:彩虹循环(每个颜色停留500ms)
        rgb_rainbow_cycle(500);

        // 效果2:红色呼吸灯(周期2秒)
        rgb_breath_effect(255, 0, 0, 2000);

        // 效果3:从蓝色渐变到粉色(持续3秒)
        rgb_fade_effect(0, 0, 255, 255, 105, 180, 3000);

        // 效果4:从绿色渐变到黄色(持续2秒)
        rgb_fade_effect(0, 255, 0, 255, 255, 0, 2000);
    }
}

// 错误处理函数(简化)
void Error_Handler(void) {
    while (1) {}
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line) {}
#endif



三、代码说明与使用要点
1. 配置前提
需通过STM32CubeMX配置TIM2的3个通道为PWM输出,参数如下:
预分频器(Prescaler)=71,自动重载值(Counter Period)=999(确保PWM频率1kHz);
通道模式为“PWM Mode 1”,极性为“High”(共阴极适用)。
引脚映射:TIM2_CH1→PA0(R)、TIM2_CH2→PA1(G)、TIM2_CH3→PA2(B)(可根据硬件修改)。
2. 核心函数解析
rgb_set_color():基础函数,通过PWM占空比控制R、G、B亮度;
rgb_rainbow_cycle():循环显示彩虹色,适合氛围灯;
rgb_breath_effect():指定颜色的亮度周期性渐变,模拟呼吸效果;
rgb_fade_effect():从起始色平滑过渡到目标色,适合色彩过渡场景。
3. 适配共阳极RGB灯
若使用共阳极灯,需修改rgb_set_color()中的占空比计算方式(反转逻辑):

// 共阳极:亮度越高,PWM占空比越低(低电平时间越长)
uint32_t pwm_r = PWM_MAX_VALUE - (r * PWM_MAX_VALUE) / RGB_MAX_BRIGHTNESS;
uint32_t pwm_g = PWM_MAX_VALUE - (g * PWM_MAX_VALUE) / RGB_MAX_BRIGHTNESS;
uint32_t pwm_b = PWM_MAX_VALUE - (b * PWM_MAX_VALUE) / RGB_MAX_BRIGHTNESS;


4. 优化建议
若需更平滑的渐变,可增加rgb_fade_effect()中的steps值(如200);
避免在中断中调用颜色控制函数,防止PWM时序紊乱;
多个效果切换时,可通过状态机实现,避免HAL_Delay()阻塞主程序。
通过以上代码,可实现丰富的RGB颜色变化效果,适用于指示灯、氛围灯、交互反馈等场景。
————————————————
版权声明:本文为CSDN博主「Shylock_Mister」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Shylock_Mister/article/details/153576353

您需要登录后才可以回帖 登录 | 注册

本版积分规则

188

主题

509

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0