一、器件介绍
引脚编号 | 引脚名称 | 说明 |
---|---|---|
1 | DO | 控制数据信号输出端 |
2 | DI | 控制数据信号输入端 |
3 | VCC | 控制电路电源正极 |
4 | NC | 空脚 |
5 | VDD | LED电源正极 |
6 | VSS | 电源负极 |
数据时序图
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 |
二、另一篇
[单片机框架] [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;
}