这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » 【STM32H755】驱动WS2812

共2条 1/1 1 跳转至

【STM32H755】驱动WS2812

工程师
2025-08-31 21:03:51     打赏

WS2812 是一款集成了控制电路和 RGB 发光芯片的智能全彩 LED 器件,属于 “像素级可编程 LED”。其核心特点如下:单颗集成:每个 LED 内部包含驱动芯片和 RGB 三色灯珠,支持独立控制颜色和亮度。串行通信:采用单线归零码(Single-Wire Non-Return-to-Zero, NRZ)通信协议,数据可通过一根线级联传输。

WS2812可以通过spi或者PWM方式来驱动。此次采集spi来驱动。

【工程配置】

我选择STM32H755的SPI2的MOSI来驱动,选择的IO为PC3

在STM32CubeMX中配置SPI2为单发送的方式。

其配置如下:

image.png

2、打开DMA,配置为字节传输,转输方向为从内存到外设:

image.png

3、打开DMA中断

image.png

最后生成工程。

【代码移植】

创建sk6812_spi2.c到项目中(注:本来我买的是sk6812,结果我用sk6812来驱动,发现有问题,后来改为ws2812驱动就OK了,我看这不良商家是不是给我发错货了。)

其内容如下:


#include "sk6812_spi2.h"
#include "string.h"


volatile uint8_t RGB_BIT_Buffer[RGB_BIT];
volatile uint8_t buffer[RGB_BIT*LED_NUMS];
volatile LEDType LED[LED_NUMS];
 
 
void WS2812_Update()
{
    HAL_SPI_Transmit_DMA(&hspi2,buffer,RGB_BIT*LED_NUMS);
}
 
/**
create 24 byte sent by SPI using RGB values.
*/
static void WS2812_CreatData(uint8_t R,uint8_t G,uint8_t B)
{
    uint8_t temp[RGB_BIT] = {0};
    for (uint8_t i=0;i<8;i++){
        temp[7-i] =  (G & 0x01) ? WS2812_1 : WS2812_0; 
        G = G >> 1;
    }
    for (uint8_t i=0;i<8;i++){
        temp[15-i] =  (R & 0x01) ? WS2812_1 : WS2812_0; 
        R = R >> 1;
    }
    for (uint8_t i=0;i<8;i++){
        temp[23-i] =  (B & 0x01) ? WS2812_1 : WS2812_0; 
        B = B >> 1;
    }
    memcpy(RGB_BIT_Buffer, temp, RGB_BIT);
}
 
/**
cook the whole buffer made by many(16 pieces) RGB_BIT_Buffers.
*/
static void WS2812_MakeBuffer()
{
    for(uint16_t i=0;i < LED_NUMS;i++)
    {
        WS2812_CreatData(LED[i].R,LED[i].G,LED[i].B);
        memcpy(buffer + i * RGB_BIT, RGB_BIT_Buffer, RGB_BIT);
    }
}
 
 
 
void WS2812_TurnOff()
{
    for(uint16_t i=0;i<LED_NUMS*24;i++)
    {
        buffer[i]=WS2812_0;
    }
}
 
 
/**
an led of position will bright with color value
pos is [0 , max-1]
*/
static void WS2812_Color_Pos(uint32_t color,uint16_t Pos)
{
    uint8_t R,G,B;
    uint16_t i;
   
    R=(color >> 16 ) & 0x00FF;
    G=(color >> 8  ) & 0x0000FF;
    B=(color       ) & 0x0000FF;
   
    WS2812_CreatData(R,G,B);
    if(Pos < LED_NUMS && Pos >=0)
    {
        memcpy(buffer + RGB_BIT * Pos, RGB_BIT_Buffer,RGB_BIT);
    }
    else
    {
        WS2812_TurnOff();
    }
}
 
 
 
void WS2812_Show_Wheel()
{
    static uint16_t i=0;
    i++;
    WS2812_Color_Pos(0xFF0000,(i)%16);
    WS2812_Color_Pos(0XFF7F00,(i+1)%16);
    WS2812_Color_Pos(0XFFFF00,(i+2)%16);
    WS2812_Color_Pos(0X7FFF00,(i+3)%16);
    WS2812_Color_Pos(0X00FF00,(i+4)%16);
    WS2812_Color_Pos(0X00FF7F,(i+5)%16);
    WS2812_Color_Pos(0X00FFFF,(i+6)%16);
    WS2812_Color_Pos(0X007FFF,(i+7)%16);
    WS2812_Color_Pos(0X0000FF,(i+8)%16);
    WS2812_Color_Pos(0X7F00FF,(i+9)%16);
    WS2812_Color_Pos(0XFF00FF,(i+10)%16);
    WS2812_Color_Pos(0XFF007F,(i+11)%16);
    WS2812_Color_Pos(0XFF0000,(i+12)%16);
    WS2812_Color_Pos(0XFF7F00,(i+13)%16);
    WS2812_Color_Pos(0XFFFF00,(i+14)%16);
    WS2812_Color_Pos(0X7FFF00,(i+15)%16);
    WS2812_Update();
}
 
// 流水灯灯效果参数定义
#define RUNNING_LIGHT_COLOR 0xFF0000  // 流水灯颜色(蓝绿色)
#define RUNNING_LIGHT_LENGTH 4       // 流水灯长度
#define RUNNING_LIGHT_SPEED 1        // 流水灯速度(数值越大越慢)

/**
 * 流水灯效果实现
 * 一个或多个连续的LED组成的光点沿着灯带移动
 * 传入参数:color - 流水灯颜色
 *           length - 流水灯长度
 *    
 */
void WS2812_Show_RunningLight(uint32_t color, uint16_t length)
{
    static uint16_t pos = 0;          // 当前流水灯位置
    static uint8_t speed_counter = 0; // 速度控制计数器
   
   
    // 先关闭所有LED
    WS2812_TurnOff();
    if(length > LED_NUMS) length = LED_NUMS;
    if(length == 0) length = 1;
   
    // 点亮当前位置及后续几个LED形成流水效果
    for(uint16_t i = 0; i < length; i++)
    {
        uint16_t current_pos = (pos + i) % LED_NUMS;
        WS2812_Color_Pos(color, current_pos);

    }
   
    // 更新位置,循环移动
    pos = (pos + 1) % LED_NUMS;
   
    // 发送数据更新显示
    WS2812_Update();
}

2、sk6812_spi2.h

#ifndef SK6812_SPI2_H
#define SK6812_SPI2_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
#include "spi.h"
 
#define WS2812_0        0xC0
#define WS2812_1        0xF0
#define WS2812_RST    0x00
#define LED_NUMS    60
#define RGB_BIT       24
 
typedef struct
{
    uint8_t R;
    uint8_t G;
    uint8_t B;
}LEDType;
 
 
/**
turn off all leds
*/
void WS2812_TurnOff();
void WS2812_Show_Wheel();
void WS2812_Update();
void WS2812_Show_RunningLight(uint32_t color, uint16_t length);

#ifdef __cplusplus
}
#endif

#endif // SK6812_SPI2_H

3、在freertos.c中添加测试代码,测试代码如下:

// 定义LED控制参数结构体
typedef struct {
    uint32_t color;
    uint32_t length;
    uint32_t delay;
} led_control_params_t;

// 默认参数
static led_control_params_t default_led_params = {0xFF0000, 4, 100};
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
	 
  for(;;)
  {
		WS2812_Show_RunningLight(default_led_params.color, default_led_params.length);
    osDelay(default_led_params.delay);
		osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
// 供外部调用的函数,用于更新LED参数
void UpdateLedParams(uint32_t color, uint32_t length, uint32_t delay)
{
    default_led_params.color = color;
    default_led_params.length = length;
    default_led_params.delay = delay;
}

// 单独更新颜色
void UpdateLedColor(uint32_t color)
{
    default_led_params.color = color;
}

// 单独更新长度
void UpdateLedLength(uint32_t length)
{
    default_led_params.length = length;
}

// 单独更新延迟时间
void UpdateLedDelay(uint32_t delay)
{
    if(delay > 0) {
        default_led_params.delay = delay;
    }
}

下载到开发板后,就可以实现动态点亮WS2812的的效果了。

bea32feacc6c06b2c5a57d30d989c020.jpg附视频:





关键词: STM32H755     WS2812     流水    

专家
2025-09-01 07:49:50     打赏
2楼

谢谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]