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

本文介绍了WS2812这种智能集成LED光源,其特点包括内置控制电路、级联方案、高亮度级别和丰富的颜色表现。通过单线协议与单片机配合,实现多LED控制,简化接口设计。文章还详细阐述了WS2812的工作电压、数据时序以及芯片的工作原理,并提供了基于OneWire的LED控制代码示例,支持不同灯光效果如常亮、呼吸、闪烁等。
摘要由CSDN通过智能技术生成

一、器件介绍

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

在这里插入图片描述
数据时序图
0,1码的高低电平时间:

电平描述时间
T0H0 码, 高电平时间0.35us ±150ns
T0L0 码, 低电平时间0.8us ±150ns
T1H1 码, 高电平时间0.7us ±150ns
T1L1 码, 低电平时间0.6us ±150ns
RES低电平时间约 >50us
TH+TL=1.25μs±600ns

在这里插入图片描述

二、另一篇

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

三、简介

智能集成LED光源 WS2812 通过简单的外部接口、特有的级联方案便于利用MCU完成多个LED控制,极大简化了LED控制接口。相比于传统的 单片机LED IO口复用控制方案 ,使用WS2812则更加的简介。

1. 芯片简介

(1) 特点与优势

在5050封装内集成有控制电路和RGB芯片,形成完整像素点控制;
内置扫执行好整形电路,传递到级联下一节点时,不会产生信号失真累积效应;
内置复位电路与掉电复位电路;
每个RGB灯都有256亮度级别,可以形成2 24 = 16777216 2^{24} = 167772162
24
=16777216中颜色,刷新频率不低于400Hz;
通过信号线完成端口级联;
传输距离在5米之内,无需增加额外电路;
在刷新频率30帧/秒中,低速模式下可以控制不少于512颗灯,高速模式下则超过1024颗灯;
数据传输速率为800kbps;
颜色一致性强,价格低;

1. 工作原理

(1) 工作电压
  根据 WS2812 数据手册,它的工作电压范围在KaTeX parse error: Can’t use function ‘~’ in math mode at position 6: + 3.5\̲~̲ + 5.3V,输入信号电压在工作电压VDD±0.5V范围内。三路LED的参数:

【表2-1-1 RGB 参数】
Emitting color Wavelength(nm) Luminous intensity(mcd) Current(mA) Voltage(V)
Red 620-630 550-700 16 1.8-2.2
Green 515-530 1100-1400 16 2.8~3.1
Blue 465-475 200-400 16 3.0-3.4

/********************************************************************************
* @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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jianqiang.xue

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值