[单片机框架] [app_led] [WS2812x] 利用软定时器实现WS2812x闪烁和呼吸等灯光模式_stm32

引脚编号 引脚名称 说明
1 DO 控制数据信号输出端
2 DI 控制数据信号输入端
3 VCC 控制电路电源正极
4 NC 空脚
5 VDD LED电源正极
6 VSS 电源负极

[单片机框架] [app_led] [WS2812x] 利用软定时器实现WS2812x闪烁和呼吸等灯光模式_stm32_02
数据时序图
0,1码的高低电平时间:

电平 描述 时间
T0H 0 码, 高电平时间 0.35us ±150ns
T0L 0 码, 低电平时间 0.8us ±150ns
T1H 1 码, 高电平时间 0.7us ±150ns
T1L 1 码, 低电平时间 0.6us ±150ns
RES 低电平时间 约 >50us
TH+TL=1.25μs±600ns
[单片机框架] [app_led] [WS2812x] 利用软定时器实现WS2812x闪烁和呼吸等灯光模式_单片机_03

[单片机框架] [onewire] 利用单线协议来点亮WS2812X 模拟IO 兼容带OS

/********************************************************************************
* @file    led_ws2812x.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-11-23
* @brief   LED灯光,OneWire控制
* @example
#include "business_function.h"
#include "app_led.h"
// 初始化APP_LED(创建软定时器)
app_led_init();
// 关闭灯光
app_led_indicate(LED_DRIVEN_WS2812, APP_LED_ID_0, LED_TYPE_OFF, 0, 0);
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#include "app_led.h"
#include "onewire.h"
#include "os_api.h"
#include "rgb_hsv.h"
/* Private Includes ----------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"

/* Private Define ------------------------------------------------------------*/
#define BYTE_0(n)   ((uint8_t)((n) & (uint8_t)0xFF))        /*!< Returns the low byte of the 32-bit value */
#define BYTE_1(n)   ((uint8_t)(BYTE_0((n) >> (uint8_t)8)))  /*!< Returns the second byte of the 32-bit value */
#define BYTE_2(n)   ((uint8_t)(BYTE_0((n) >> (uint8_t)16))) /*!< Returns the third byte of the 32-bit value */
#define BYTE_3(n)   ((uint8_t)(BYTE_0((n) >> (uint8_t)24)))
/* Private Macro -------------------------------------------------------------*/
#if BS_APP_LED_WS2812_DRIVEN_MODE
#if BS_WS2812_CH0_EN
static void timer_ws2812_0_light_control(void const *arg);
#endif
#if BS_WS2812_CH1_EN
static void timer_ws2812_1_light_control(void const *arg);
#endif
#if BS_WS2812_CH2_EN
static void timer_ws2812_2_light_control(void const *arg);
#endif
#if BS_WS2812_CH3_EN
static void timer_ws2812_3_light_control(void const *arg);
#endif
#endif
/* Private Typedef -----------------------------------------------------------*/
static bool g_app_led_init = false;
// 定义led灯光结构体类型
typedef struct
{
    app_led_id_t     led_id;               // 组号
    app_led_type_t   type;                 // 0--灭灯  1--常亮  2--呼吸  3--快闪
    bool             level_logic;          // 0--低电平亮  1--高电平亮
    char            *timer_id;             // 软定时器id
    uint32_t         period_max;           // 重装载值(最大值)                   --> 对WS2812来说,则是挂载了多少个灯
    uint16_t         cycle_time;           // 定时器轮询时间(灭灯和常亮只执行一次)
    uint32_t         period;               // 重装载值(控制值)                   --> 对WS2812来说,则是RGB值
    // 下面不用填写,仅用于临时计算
    uint8_t          temp_dir;             // 用于方向 0--up 1--keep 2--down
    uint16_t         temp_times;           // 用于计次
} app_led_t;

// 定义软定时器,用于实现灯光效果
#if BS_APP_LED_WS2812_DRIVEN_MODE
#if BS_WS2812_CH0_EN
os_timer_def(ws2812_0, timer_ws2812_0_light_control);
app_led_t app_led_ws2812_0 = {APP_LED_ID_0, LED_TYPE_OFF, 0, NULL, BS_WS2812_CH0_NUM, 0, 0, 1, 0};
#endif
#if BS_WS2812_CH1_EN
os_timer_def(ws2812_1, timer_ws2812_1_light_control);
app_led_t app_led_ws2812_1 = {APP_LED_ID_1, LED_TYPE_OFF, 0, NULL, BS_WS2812_CH1_NUM, 0, 0, 1, 0};
#endif
#if BS_WS2812_CH2_EN
os_timer_def(ws2812_2, timer_ws2812_2_light_control);
app_led_t app_led_ws2812_2 = {APP_LED_ID_2, LED_TYPE_OFF, 0, NULL, BS_WS2812_CH2_NUM, 0, 0, 1, 0};
#endif
#if BS_WS2812_CH3_EN
os_timer_def(ws2812_3, timer_ws2812_3_light_control);
app_led_t app_led_ws2812_3 = {APP_LED_ID_3, LED_TYPE_OFF, 0, NULL, BS_WS2812_CH3_NUM, 0, 0, 1, 0};
#endif
#endif
/* Private Function Prototypes ----------------------------------------------*/
/********************[灯光类型]对内接口函数*************************************/
/**
 * @brief  关闭灯光
 * @param  *app_led: led灯光结构体指针
 */
static void led_type_off(app_led_t *app_led)
{
    uint8_t temp[3] = {0, 0 ,0};
    onewire_send_data(app_led->led_id, temp, 3);
}
/**
 * @brief  灯光常亮
 * @param  *app_led: led灯光结构体指针
 */
static void led_type_light(app_led_t *app_led)
{
    uint8_t temp[3] = {BYTE_1(app_led->period), BYTE_2(app_led->period), BYTE_0(app_led->period)}; // GRB
    onewire_send_data(app_led->led_id, temp, 3);
}

///**
// * @brief  灯光由暗变亮
// * @note   渐变效果由cycle_time决定
// * @param  *app_led: led灯光结构体指针
// */
//static void led_type_rise_slowly(app_led_t *app_led)
//{
//    if (app_led->type != LED_TYPE_RISE_SLOWLY)
//    {
//        return;
//    }
//    app_led->temp_times++;
//    if (app_led->temp_times == 257)
//    {
//        return;
//    }
//    uint8_t temp[3]; // GRB
//    float h, s, v;
//    rgb2hsv(BYTE_2(app_led->period), BYTE_1(app_led->period), BYTE_0(app_led->period), &h, &s, &v);
//    v = (float)(app_led->temp_times) / 256;
//    hsv2rgb(h, s, v, &temp[1], &temp[0], &temp[2]);

//    bsp_onewire_send_data(temp, 3);
//    os_timer_start((os_timer_id)(app_led->timer_id), app_led->cycle_time);
//}

///**
// * @brief  灯光由亮变暗
// * @note   渐变效果由cycle_time决定
// * @param  *app_led: led灯光结构体指针
// */
//static void led_type_fall_slowly(app_led_t *app_led)
//{
//    if (app_led->type != LED_TYPE_RISE_SLOWLY)
//    {
//        return;
//    }
//    app_led->temp_times++;
//    if (app_led->temp_times == 257)
//    {
//        return;
//    }
//    uint8_t temp[3]; // GRB
//    float h, s, v;
//    rgb2hsv(BYTE_2(app_led->period), BYTE_1(app_led->period), BYTE_0(app_led->period), &h, &s, &v);
//    v = (float)(256 - app_led->temp_times) / 256;
//    hsv2rgb(h, s, v, &temp[1], &temp[0], &temp[2]);

//    bsp_onewire_send_data(temp, 3);
//    os_timer_start((os_timer_id)(app_led->timer_id), app_led->cycle_time);
//}

/**
 * @brief  灯光呼吸效果
 * @note   呼吸频率由cycle_time决定
 * @param  *app_led: led灯光结构体指针
 */
static void led_type_breath(app_led_t *app_led)
{
    if (app_led->type != LED_TYPE_BREATH)
    {
        return;
    }

    uint16_t time = 0;
    uint8_t temp[3]; // GRB
    float h, s, v;

    if (app_led->temp_dir == 0)
    {
        app_led->temp_times++;
    }
    else if (app_led->temp_dir == 1)
    {
        app_led->temp_dir = 2;
        time = 255;
        goto end;
    }
    else if (app_led->temp_dir == 2)
    {
        app_led->temp_times--;
    }

    if (app_led->temp_times == 257)
    {
        app_led->temp_dir = 1;
    }
    else if (app_led->temp_times == 0)
    {
        app_led->temp_dir = 0;
        time = 255;
        goto end;
    }
    time = app_led->cycle_time;
end:
    rgb2hsv(BYTE_2(app_led->period), BYTE_1(app_led->period), BYTE_0(app_led->period), &h, &s, &v);
    v = (float)(app_led->temp_times) / 256;
    hsv2rgb(h, s, v, &temp[1], &temp[0], &temp[2]);

    onewire_send_data(app_led->led_id, temp, 3);
    os_timer_start((os_timer_id)(app_led->timer_id), time);
}

/**
 * @brief  灯光闪烁
 * @note   闪烁频率由cycle_time决定
 * @param  *app_led: led灯光结构体指针
 */
static void led_type_twinkle(app_led_t *app_led)
{
    if (app_led->type != LED_TYPE_TWINKLE)
    {
        return;
    }

    if (app_led->temp_dir == 0)
    {
        led_type_light(app_led);
        app_led->temp_dir = 1;
    }
    else
    {
        led_type_off(app_led);
        app_led->temp_dir = 0;
    }
    os_timer_start((os_timer_id)(app_led->timer_id), app_led->cycle_time);
}

/**
 * @brief  灯光SOS灯效
 * @param  *app_led: led灯光结构体指针
 */
static void led_type_sos(app_led_t *app_led)
{
    if (app_led->type != LED_TYPE_SOS)
    {
        return;
    }

    uint16_t time = 0;
    if (app_led->temp_dir == 0)
    {
        app_led->temp_dir = 1;
        led_type_light(app_led);
        time = 100;
        goto end;
    }
    else if (app_led->temp_dir == 1)
    {
        app_led->temp_times++;
        app_led->temp_dir = 0;
        if (app_led->temp_times > 2)
        {
            app_led->temp_times = 0;
            app_led->temp_dir = 2;
        }
        led_type_off(app_led);
        time = 200;
        goto end;
    }
    else if (app_led->temp_dir == 2)
    {
        app_led->temp_dir = 3;
        led_type_light(app_led);
        time = 800;
        goto end;
    }
    else if (app_led->temp_dir == 3)
    {
        app_led->temp_times++;
        app_led->temp_dir = 2;
        if (app_led->temp_times > 2)
        {
            app_led->temp_times = 0;
            app_led->temp_dir   = 0;
        }
        led_type_off(app_led);
        time = 200;
        goto end;
    }
    else
    {
        app_led->temp_dir = 0;
    }
end:
    os_timer_start((os_timer_id)(app_led->timer_id), time);
}

/**
 * @brief  灯光红蓝交替闪烁
 * @param  *app_led: led灯光结构体指针
 */
static void led_type_red_blue_twinkle(app_led_t *app_led)
{
    if (app_led->type != LED_TYPE_RED_BLUE_TWINKLE)
    {
        return;
    }
    uint16_t time = 0;
    if (app_led->temp_dir == 0)
    {
        app_led->temp_dir = 1;
        app_led->period = COLOR_RED;
        led_type_light(app_led);
        time = 150;
        goto end;
    }
    else if (app_led->temp_dir == 1)
    {
        app_led->temp_times++;
        app_led->temp_dir = 0;
        if (app_led->temp_times > 2)
        {
            app_led->temp_times = 0;
            app_led->temp_dir = 2;
        }
        app_led->period = COLOR_BLUE;
        led_type_light(app_led);
        time = 150;
        goto end;
    }
    else if (app_led->temp_dir == 2)
    {
        app_led->temp_dir = 3;
        app_led->period = COLOR_RED;
        led_type_light(app_led);
        time = 500;
        goto end;
    }
    else if (app_led->temp_dir == 3)
    {
        app_led->temp_times++;
        app_led->temp_dir = 2;
        if (app_led->temp_times > 2)
        {
            app_led->temp_times = 0;
            app_led->temp_dir   = 0;
        }
        app_led->period = COLOR_BLUE;
        led_type_light(app_led);
        time = 500;
        goto end;
    }
    else
    {
        time = 1000;
        app_led->temp_dir = 0;
        app_led->temp_times = 0;
        led_type_off(app_led);
    }
end:
    os_timer_start((os_timer_id)(app_led->timer_id), time);
}
/************************************[软定时器][回调函数]灯光操作************************************/
#if BS_APP_LED_WS2812_DRIVEN_MODE
#if BS_WS2812_CH0_EN
/**
 * @brief  [软定时器回调函数][WS2812_CH0] 执行对应灯光效果
 * @note   采用定时器轮询实现灯效
 */
static void timer_ws2812_0_light_control(void const *arg)
{
    if (app_led_ws2812_0.type == LED_TYPE_OFF)
    {
        led_type_light(&app_led_ws2812_0);
    }
    else if (app_led_ws2812_0.type == LED_TYPE_LIGHT)
    {
        led_type_light(&app_led_ws2812_0);
    }
    else if (app_led_ws2812_0.type == LED_TYPE_BREATH)
    {
        led_type_breath(&app_led_ws2812_0);
    }
    else if (app_led_ws2812_0.type == LED_TYPE_TWINKLE)
    {
        led_type_twinkle(&app_led_ws2812_0);
    }
    else if (app_led_ws2812_0.type == LED_TYPE_SOS)
    {
        led_type_sos(&app_led_ws2812_0);
    }
//    else if (app_led_ws2812_0.type == LED_TYPE_RISE_SLOWLY)
//    {
//        led_type_rise_slowly(&app_led_ws2812_0);
//    }
//    else if (app_led_ws2812_0.type == LED_TYPE_FALL_SLOWLY)
//    {
//        led_type_fall_slowly(&app_led_ws2812_0);
//    }

    else if (app_led_ws2812_0.type == LED_TYPE_RED_BLUE_TWINKLE)
    {
        led_type_red_blue_twinkle(&app_led_ws2812_0);
    }
}
#endif

#if BS_WS2812_CH1_EN
/**
 * @brief  [软定时器回调函数][WS2812_CH1] 执行对应灯光效果
 * @note   采用定时器轮询实现灯效
 */
static void timer_ws2812_1_light_control(void const *arg)
{
    if (app_led_ws2812_1.type == LED_TYPE_OFF)
    {
        led_type_light(&app_led_ws2812_1);
    }
    else if (app_led_ws2812_1.type == LED_TYPE_LIGHT)
    {
        led_type_light(&app_led_ws2812_1);
    }
    else if (app_led_ws2812_1.type == LED_TYPE_BREATH)
    {
        led_type_breath(&app_led_ws2812_1);
    }
    else if (app_led_ws2812_1.type == LED_TYPE_TWINKLE)
    {
        led_type_twinkle(&app_led_ws2812_1);
    }
    else if (app_led_ws2812_1.type == LED_TYPE_SOS)
    {
        led_type_sos(&app_led_ws2812_1);
    }
    else if (app_led_ws2812_1.type == LED_TYPE_RISE_SLOWLY)
    {
        led_type_rise_slowly(&app_led_ws2812_1);
    }
    else if (app_led_ws2812_1.type == LED_TYPE_FALL_SLOWLY)
    {
        led_type_fall_slowly(&app_led_ws2812_1);
    }
}
#endif

#if BS_WS2812_CH2_EN
/**
 * @brief  [软定时器回调函数][WS2812_CH2] 执行对应灯光效果
 * @note   采用定时器轮询实现灯效
 */
static void timer_ws2812_2_light_control(void const *arg)
{
    if (app_led_ws2812_2.type == LED_TYPE_OFF)
    {
        led_type_light(&app_led_ws2812_2);
    }
    else if (app_led_ws2812_2.type == LED_TYPE_LIGHT)
    {
        led_type_light(&app_led_ws2812_2);
    }
    else if (app_led_ws2812_2.type == LED_TYPE_BREATH)
    {
        led_type_breath(&app_led_ws2812_2);
    }
    else if (app_led_ws2812_2.type == LED_TYPE_TWINKLE)
    {
        led_type_twinkle(&app_led_ws2812_2);
    }
    else if (app_led_ws2812_2.type == LED_TYPE_SOS)
    {
        led_type_sos(&app_led_ws2812_2);
    }
    else if (app_led_ws2812_2.type == LED_TYPE_RISE_SLOWLY)
    {
        led_type_rise_slowly(&app_led_ws2812_2);
    }
    else if (app_led_ws2812_2.type == LED_TYPE_FALL_SLOWLY)
    {
        led_type_fall_slowly(&app_led_ws2812_2);
    }
}
#endif

#if BS_WS2812_CH3_EN
/**
 * @brief  [软定时器回调函数][WS2812_CH3] 执行对应灯光效果
 * @note   采用定时器轮询实现灯效
 */
static void timer_ws2812_3_light_control(void const *arg)
{
    if (app_led_ws2812_3.type == LED_TYPE_OFF)
    {
        led_type_light(&app_led_ws2812_3);
    }
    else if (app_led_ws2812_3.type == LED_TYPE_LIGHT)
    {
        led_type_light(&app_led_ws2812_3);
    }
    else if (app_led_ws2812_3.type == LED_TYPE_BREATH)
    {
        led_type_breath(&app_led_ws2812_3);
    }
    else if (app_led_ws2812_3.type == LED_TYPE_TWINKLE)
    {
        led_type_twinkle(&app_led_ws2812_3);
    }
    else if (app_led_ws2812_3.type == LED_TYPE_SOS)
    {
        led_type_sos(&app_led_ws2812_3);
    }
    else if (app_led_ws2812_3.type == LED_TYPE_RISE_SLOWLY)
    {
        led_type_rise_slowly(&app_led_ws2812_3);
    }
    else if (app_led_ws2812_3.type == LED_TYPE_FALL_SLOWLY)
    {
        led_type_fall_slowly(&app_led_ws2812_3);
    }
}
#endif
#endif

/**
  * @brief  通过led_id获取结构体指针
  * @param  led_id 灯光id号
  * @return NULL--无效  其他则有效值
  */
static app_led_t *get_app_led(app_led_id_t led_id)
{
    if (led_id == APP_LED_ID_0)
    {
#if BS_APP_LED_WS2812_DRIVEN_MODE && BS_WS2812_CH0_EN
        return &app_led_ws2812_0;
#else
        return NULL;
#endif
    }
#if BS_APP_LED_WS2812_DRIVEN_MODE && BS_WS2812_CH1_EN
    else if (led_id == APP_LED_ID_1)
    {
        return &app_led_ws2812_1;
    }
#endif
#if BS_APP_LED_WS2812_DRIVEN_MODE && BS_WS2812_CH2_EN
    else if (led_id == APP_LED_ID_2)
    {
        return &app_led_ws2812_2;
    }
#endif
#if BS_APP_LED_WS2812_DRIVEN_MODE && BS_WS2812_CH3_EN
    else if (led_id == APP_LED_ID_3)
    {
        return &app_led_ws2812_3;
    }
#endif
    return NULL;
}

/* Public Function Prototypes -----------------------------------------------*/
/**
 * @brief  [app层][ws2812相关初始化] 定义软定时器和参数设置
 * @note   NULL
 * @retval None
 */
void led_ws2812_init(void)
{
    if (g_app_led_init)
    {
        return;
    }
    g_app_led_init = true;
    uint32_t timer_err_ret = 0;
#if BS_APP_LED_WS2812_DRIVEN_MODE
#if BS_WS2812_CH0_EN
    app_led_ws2812_0.timer_id    = (char *)os_timer_create(os_timer(ws2812_0), OS_TIMER_ONCE, &timer_err_ret);
#endif
#if BS_WS2812_CH1_EN
    app_led_ws2812_1.timer_id    = (char *)os_timer_create(os_timer(ws2812_1), OS_TIMER_ONCE, &timer_err_ret);
#endif
#if BS_WS2812_CH2_EN
    app_led_ws2812_2.timer_id    = (char *)os_timer_create(os_timer(ws2812_2), OS_TIMER_ONCE, &timer_err_ret);
#endif
#if BS_WS2812_CH3_EN
    app_led_ws2812_3.timer_id    = (char *)os_timer_create(os_timer(ws2812_3), OS_TIMER_ONCE, &timer_err_ret);
#endif
#endif
}

/**
 * @brief  得到当前组号的灯光值
 * @param  led_id: led组号
 * @retval 当前组号的PWM值
 */
uint16_t app_led_ws2812_get_current_period(app_led_id_t led_id)
{
    app_led_t *app_led = get_app_led(led_id);
    return app_led->period;
}

/**
 * @brief  得到当前组号的灯光模式
 * @param  led_id: led组号
 * @retval 当前组号的灯光模式
 */
app_led_type_t app_led_ws2812_get_current_type(app_led_id_t led_id)
{
    app_led_t *app_led = get_app_led(led_id);
    return app_led->type;
}

/**
  * @brief  LED操作
  * @param  led_id led组号
  * @param  type 灯光类型
  * @param  cycle_time 灯光周期(ms) 定时器轮询时间(灭灯和常亮只执行一次)
  * @param  period 重装载值(控制值)
  * @return 0--false 1--true
  */
bool app_led_ws2812_ioctl(app_led_id_t led_id, app_led_type_t type, uint16_t cycle_time, uint32_t period)
{
    app_led_t *led_info = NULL;

    led_info = get_app_led(led_id);
    if (led_info == NULL)
    {
        return false;
    }

    led_info->temp_dir    = 0;
    led_info->temp_times  = 0;
    led_info->cycle_time  = cycle_time;
    led_info->type        = type;
    if (type == LED_TYPE_OFF)
    {
        led_info->period  = 0;
    }
    else
    {
        led_info->period  = period;
    }

    os_timer_start((os_timer_id)(led_info->timer_id), 1);
    return true;
}