> 技术文档 > WS2812B_RGB灯介绍以及驱动方法(STM32)_ws2812b驱动方法

WS2812B_RGB灯介绍以及驱动方法(STM32)_ws2812b驱动方法


一、硬件介绍

WS2812B控制IC下常见的相关模块(方形 / 圆形LED灯)
WS2812B_RGB灯介绍以及驱动方法(STM32)_ws2812b驱动方法
WS2812B_RGB灯介绍以及驱动方法(STM32)_ws2812b驱动方法

主要特点:

● IC控制电路与LED点光源共用一个电源。
● 控制电路与RGB芯片集成在一个5050封装的元器件中, 构成一个完整的外控像素点。
● 内置信号整形电路, 任何一个像素点收到信号后经过波形整形再输出, 保证线路波形畸变不会累加。
● 内置上电复位和掉电复位电路。
● 每个像素点的三基色颜色可实现256级亮度显示, 完成16777216种颜色的全真色彩显示。
● 端口扫描频率2KHz/s。
● 串行级联接口, 能通过一根信号线完成数据的接收与解码。
● 任意两点传输距离在不超过5米时无需增加任何电路。
● 当刷新速率30帧/秒时, 级联数不小于1024点。
数据发送速度可达800Kbps。
● 光的颜色高度一致, 性价比高

产品概述:

WS2812B是一个集控制电路与发光电路于一体的智能外控LED光源其外型与一个5050LED灯珠相同, 每个元件即为一个像素点。像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路, 还包含有高精度的内部振荡器和可编程定电流控制部分, 有效保证了像素点光的颜色高度一致。

数据协议采用单线归零码的通讯方式, 像素点在上电复位以后, DIN端接受从控制器传输过来的数据。

首先送过来的24bit数据被第一个像素点提取后, 送到像素点内部的数据锁存器, 剩余的数据经过内部整形处理电路整形放大后通过DO端口开始转发输出给下一个级联的像素点, 每经过一个像素点的传输, 信号减少24bit。

像素点采用自动整形转发技术, 使得该像素点的级联个数不受信号传送的限制, 仅受限信号传输速度要求。高达 2KHz 的端口扫描频率, 在高清摄像头的捕捉下都不会出现闪烁现象, 非常适合高速移动产品的使用。280μs以上的RESET时间, 出现中断也不会引起误复位, 可以支持更低频率、 价格便宜的MCU。LED具有低电压驱动、 环保节能、 亮度高、 散射角度大、 一致性好超、 低功率及超长寿命等优点。 将控制电路集成于LED上面, 电路变得更加简单, 体积小, 安装更加简便。

WS2812B_RGB灯介绍以及驱动方法(STM32)_ws2812b驱动方法WS2812B_RGB灯介绍以及驱动方法(STM32)_ws2812b驱动方法
WS2812B_RGB灯介绍以及驱动方法(STM32)_ws2812b驱动方法

二、硬件引脚连接

硬件引脚连接:

VCC -> 5V

GND -> GND

IN -> PA15 ( 定时器2 PWM_CH1 )

OUT -> IN ( 若要构成级联,连接到下一个模块的IN端 )

每个灯珠全亮的功率:0.3W

每个灯珠全亮的电流:0.6mA

三、程序代码

以STM32F103C8T6_HAL库代码为例,驱动WS2812B_RGB模块。

1. WS2812B的通信协议要求

WS2812B使用一种特殊的单线通信协议,通过高低电平的持续时间来区分数据位(0和1)。

具体时序要求如下:

  • 逻辑0:高电平持续时间约为0.25µs,低电平持续时间约为1µs。
  • 逻辑1:高电平持续时间约为1µs,低电平持续时间约为0.25µs。
  • 复位信号:低电平持续时间至少为280µs。

这些时序要求非常严格,误差不能超过±150ns,否则WS2812B无法正确解析数据。

2.使用PWM控制电平时间

PWM(脉宽调制)是一种通过调节信号的占空比(高电平时间与周期的比例)来模拟特定波形的方法。

对于WS2812B:

  • PWM可以精确控制高电平和低电平的持续时间。
  • 通过调整PWM的占空比,可以生成符合WS2812B要求的逻辑0和逻辑1信号。

例如:

  • 使用800kHz的PWM频率(周期为1.25µs):
    • 逻辑0:高电平占空比为20%(0.25µs高电平,1µs低电平)。
    • 逻辑1:高电平占空比为80%(1µs高电平,0.25µs低电平)。

通过PWM,可以轻松生成符合WS2812B要求的信号。

3.使用DMA传输数据

DMA(直接内存访问)是一种硬件功能,允许外设直接访问内存,而不需要CPU的干预。

使用DMA的好处包括:

  • 减少CPU负担:CPU不需要参与每个PWM周期的数据传输,可以执行其他任务。
  • 高精度:DMA可以确保数据传输的精确性和实时性,避免因CPU中断或任务切换导致的时序误差。
  • 高效传输:DMA可以一次性传输大量数据(如多个LED的颜色数据),而不需要CPU逐字节处理。

在驱动WS2812B时:

  • 每个LED需要24个PWM周期(每个颜色位一个周期)。

  • 多个LED的数据需要连续传输,且不能中断。

  • DMA可以将所有LED的数据一次性传输到定时器的PWM寄存器中,确保信号的连续性和精确性。

4、HAL库相关配置

时钟树配置:主频为72Mhz,不分频

1、TIM2定时器配置

需要配置定时器生成800kHz的PWM信号。(WS2812B的通信频率为800kHz,详见硬件介绍章节)

  • 定时器预分频器(Prescaler)设置为0(不分频)。
  • 定时器周期(Period)设置为89 (90 - 1),以生成800kHz的PWM信号。

PWM频率 = 系统时钟 / (Prescaler + 1) / (Period + 1)
800kHz = 72MHz / 1 / (89 + 1)

WS2812B_RGB灯介绍以及驱动方法(STM32)_ws2812b驱动方法

2、DMA配置

TIM的CCR为16位(Half Word)

WS2812B_RGB灯介绍以及驱动方法(STM32)_ws2812b驱动方法

5、相关代码

WS2812B.c:

WS2812B.c: #include \"ws2812b.h\" extern TIM_HandleTypeDef htim2;extern DMA_HandleTypeDef hdma_tim2_ch1;//每一行24个bit代表一个RGB数据volatile uint16_t RGB_Buf[ LED_COUNT + 1 ][ RGB_COUNT ]; // 最后一组数据为低电平,复位数据。/*功能:GRB -> RGB颜色转换WS2812B的发送顺序为 GRB顺序(高位在前),需转换将要发送的 RGB(常用) [ 255,255,255 ] -> GRBBrightness:亮度设置(0~1f)*/static void RGB_Color(uint8_t LED_Num,RGB_Color_TypeDef Color,float Brightness){ Brightness = (Brightness > 1.0f) ? 1.0f : Brightness; Brightness = (Brightness < 0.0f) ? 0.0f : Brightness; // Gamma校正 + 亮度调整 float gamma = 2.2f; uint8_t g_out = (uint8_t)(powf(Color.G / 255.0f, gamma) * Brightness * 255.0f + 0.5f); uint8_t r_out = (uint8_t)(powf(Color.R / 255.0f, gamma) * Brightness * 255.0f + 0.5f); uint8_t b_out = (uint8_t)(powf(Color.B / 255.0f, gamma) * Brightness * 255.0f + 0.5f); //颜色转换  for(uint8_t i=0;i<24;i++){ if(i<8) RGB_Buf[LED_Num][i] = ( g_out ) & (1 << (7 -i)) ? HIGH : LOW;else if(i<16) RGB_Buf[LED_Num][i] = ( r_out ) & (1 << (15 -i)) ? HIGH : LOW; else  RGB_Buf[LED_Num][i] = ( b_out ) & (1 << (23 -i)) ? HIGH : LOW; }}/*功能:所有LED关闭(清屏)*/static void RGB_BLACK_All(void){ for(uint8_t Led =0;Led<LED_COUNT;Led++) RGB_Color(Led,BLACK,0);}/*功能:设置多个LED (固定颜色)Led_Arr:要设置的LED (每行所在的位置)Color:颜色RGB {255,255,255}Brightness:亮度设置(0~1f)*/void Led_Single_Color(uint8_t Led_Arr[],RGB_Color_TypeDef Color,float Brightness){  for (uint8_t y = 0; y < LED_HEIGHT; y++) { // 8 * 8 for (uint8_t x = 0; x < LED_WIDTH; x++) { uint8_t led_index = y * LED_WIDTH + x; // 0~63 if (Led_Arr[y] & (1 << (7-x))) { RGB_Color(led_index, Color,Brightness); }else{  RGB_Color(led_index, BLACK,0); } } } /* 传输设置好的颜色数据 功能:发送数组RGB_Buf内的所有数据,包含Reset数据 发送8位数据,需要1.25us;发送LED_COUNT个数据需要:LED_COUNT * 24 * 1.25us + Reset Reset: 24 * 1.25us = 30us; 30us足够。 */ HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, (uint32_t *)RGB_Buf,(LED_COUNT + 1)*24); }/*功能:设置多个LED (自定义颜色)Led_Arr:要设置的LED (每行所在的位置)Color[]:颜色RGB数组 {255,255,255}...Brightness:亮度设置(0~1f)*/void Led_Multiple_Colors(uint8_t Led_Arr[],RGB_Color_TypeDef Color[],float Brightness){ uint8_t RGB_Num = 0; for (uint8_t y = 0; y < LED_HEIGHT; y++) { for (uint8_t x = 0; x < LED_WIDTH; x++) { uint8_t led_index = y * LED_WIDTH + x; if (Led_Arr[y] & (1 << (7-x))) {  RGB_Color(led_index, Color[RGB_Num++],Brightness); }else{  RGB_Color(led_index, BLACK,0); } } } HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, (uint32_t *)RGB_Buf,(LED_COUNT + 1)*24); }//清除所有LED颜色(清屏)void RGB_Off(void){ RGB_BLACK_All(); HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, (uint32_t *)RGB_Buf,(LED_COUNT + 1)*24);}// PWM DMA 完成回调函数 停止void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim){if(htim == &htim2){HAL_TIM_PWM_Stop_DMA(&htim2, TIM_CHANNEL_1); }}

WS2812B.h:

WS2812B.h: #ifndef __WS2812B_H__#define __WS2812B_H__#include \"main.h\"#include \"Stdbool.h\"#include #include #define LED_WIDTH 8#define LED_HEIGHT 8#define LED_COUNT (LED_WIDTH * LED_HEIGHT) // 总的LED的数量#define RGB_COUNT 24 //每个LED所需的RGB 24位#define HIGH 72// PWM占空比表示高电平,逻辑1: [ 高电平时间 = x / 90 × 1.25μs = 1μs ] => x = 72#define LOW 18 // PWM占空比表示低电平,逻辑0: [ 高电平时间 = x / 90 × 1.25μs = 0.25μs ] => x = 18#define WHITE (RGB_Color_TypeDef){255, 255, 255} //全白 #255#define BLACK (RGB_Color_TypeDef){0, 0, 0} //全黑 #0#define RED (RGB_Color_TypeDef){255, 0, 0} #define GREEN (RGB_Color_TypeDef){0, 255, 0} #define BLUE (RGB_Color_TypeDef){0, 0, 255} //单个LED的颜色控制结构体typedef struct{uint8_t R;uint8_t G;uint8_t B;}RGB_Color_TypeDef; void Led_Single_Color(uint8_t Led_Arr[],RGB_Color_TypeDef Color,float Brightness);void Led_Multiple_Colors(uint8_t Led_Arr[],RGB_Color_TypeDef Color[],float Brightness);void RGB_Off(void);#endif

main.c

... /* Private includes ----------------------------------------------------------*//* USER CODE BEGIN Includes */#include \"ws2812b.h\" /* USER CODE END Includes */int main(void){ const uint8_t Num_0[] = {0x00,0x1C,0x22, 0x22,0x22,0x1C,0x00,0x00}; // 0 const uint8_t Num_1[] = {0x00,0x10,0x10,0x10,0x1C,0x10,0x00,0x00}; // 1 const uint8_t Num_2[] = {0x00,0x3E,0x0C,0x10,0x22,0x3C,0x00,0x00}; // 2 const uint8_t Num_3[] = {0x00,0x1E,0x20,0x1C,0x20,0x3E,0x00,0x00}; // 3 const uint8_t Num_4[] = {0x00,0x20,0x7E,0x24,0x28,0x30,0x00,0x00}; // 4 const uint8_t Num_5[] = {0x00,0x1E,0x20,0x1E,0x02,0x3E,0x00,0x00}; // 5 const uint8_t Num_6[] = {0x00,0x1C,0x22,0x3E, 0x06,0x1C,0x00,0x00}; // 6 const uint8_t Num_7[] = {0x00,0x08,0x08,0x10,0x20,0x7E,0x00,0x00};// 7 const uint8_t Num_8[] = {0x00,0x1C,0x22,0x1C,0x22,0x3E,0x00,0x00};// 8 const uint8_t Num_9[] = {0x00,0x1E,0x30,0x3C,0x22,0x1C,0x00,0x00};// 9 uint8_t *ptr[] = {Num_0, Num_1, Num_2, Num_3, Num_4, Num_5, Num_6, Num_7, Num_8, Num_9}; uint8_t i = 0; float light = 0.01; /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE BEGIN 3 */ if (i >= 10) i = 0; if (light > 1.0) light = 0.01; Led_Single_Color(ptr[i++], BLUE, light += 0.02); HAL_Delay(500); } /* USER CODE END 3 */}

四、演示效果

0~9数字(500ms / 亮度逐渐增加)

在这里插入图片描述