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

一、硬件介绍

WS2812B控制IC下常见的相关模块(方形 / 圆形LED灯)
在这里插入图片描述
在这里插入图片描述

主要特点:

● 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上面, 电路变得更加简单, 体积小, 安装更加简便。

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

二、硬件引脚连接

硬件引脚连接:

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)

2、DMA配置

TIM的CCR为16位(Half Word)

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 ] -> GRB
Brightness:亮度设置(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 <string.h>
#include <math.h>


#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 / 亮度逐渐增加)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值