STM32CubeMX WS2812B灯驱动

简介: STM32CubeMX WS2812B灯驱动

一、WS2812B

数据发送速度可达800Kbps。


数据协议采用单线归零码的通讯方式,像素点在上电复位以后,DIN端接受从控制器传输过来的数据,首先送过来的24bit数据被第一个像素点提取后,送到像素点内部的数据锁存器,剩余的数据经过内部整形处理电路整形放大后通过DO端口开始转发输出给下一个级联的像素点,每经过一个像素点的传输,信号减少24bit。像素点采用自动整形转发技术,使得该像素点的级联个数不受信号传送的限制,仅受限信号传输速度要求。


280μs以上的RESET时间,出现中断也不会引起误复位,可以支持更低频率、价格便宜的MCU。LED具有低电压驱动、环保节能、亮度高、散射角度大、一致性好超、低功率及超长寿命等优点。将控制电路集成于LED上面,电路变得更加简单,体积小,安装更加简便






二、CubeMX配置

我这里使用的是stm32f030f4p6,留了一个485接口

1.打开调试 选择滴答时钟




2.RCC配置



3.时钟树配置



4.配置PWW输出


设置周期为60个时钟周期(48MHz / 60 = 800kHz, 1.25us周期)


dma配置



5.串口配置




生成工程


三、KEIL代码

目标PWM信号

WS2812 LED的时序要求非常严格。一般来说,WS2812的高电平和低电平的持续时间如下:

  • 高电平时间约为0.7µs(亮位)
  • 低电平时间约为0.35µs(暗位)


总信号周期约为1.25µs。

设置

  • 系统时钟频率:48 MHz
  • 目标PWM周期:1.25µs


计算

  1. 计算计数器周期值(ARR)
    我们需要让一个PWM周期为1.25µs,即:




给定系统时钟频率为48 MHz,时钟周期为:

因此,计数器周期值为:


2.设置高电平和低电平持续时间

  • 高电平时间约为0.7µs
  • 低电平时间约为0.35µs


对应的计数器值:



WS2812B.c

#include "WS2812B.h"
#include "tim.h"
 
#define MAX_LED 6    // 灯的数量
#define USE_BRIGHTNESS 1    // 启用亮度控制
 
uint8_t LED_Data[MAX_LED][4];
uint8_t LED_Mod[MAX_LED][4];  // 用于亮度控制
 
void Set_LED(int LEDnum, int Red, int Green, int Blue) {
    if (LEDnum < 0 || LEDnum >= MAX_LED) return;
 
    Red = (Red < 0) ? 0 : (Red > 255) ? 255 : Red;
    Green = (Green < 0) ? 0 : (Green > 255) ? 255 : Green;
    Blue = (Blue < 0) ? 0 : (Blue > 255) ? 255 : Blue;
 
    LED_Data[LEDnum][0] = LEDnum;
    LED_Data[LEDnum][1] = Green;
    LED_Data[LEDnum][2] = Red;
    LED_Data[LEDnum][3] = Blue;
}
 
void Set_LED_HEX(int LEDnum, uint32_t colorValue) {
    if (LEDnum < 0 || LEDnum >= MAX_LED) return;
 
    int Red = (colorValue >> 16) & 0xFF;
    int Green = (colorValue >> 8) & 0xFF;
    int Blue = colorValue & 0xFF;
 
    LED_Data[LEDnum][0] = LEDnum;
    LED_Data[LEDnum][1] = Green;
    LED_Data[LEDnum][2] = Red;
    LED_Data[LEDnum][3] = Blue;
}
 
void Set_Brightness(int brightness) {
#if USE_BRIGHTNESS
    brightness = (brightness > 100) ? 100 : (brightness < 0) ? 0 : brightness;
 
    for (int i = 0; i < MAX_LED; i++) {
        LED_Mod[i][0] = LED_Data[i][0];
        for (int j = 1; j < 4; j++) {
            LED_Mod[i][j] = (LED_Data[i][j] * brightness) / 100;
        }
    }
#endif
}
 
uint16_t pwmData[(24 * MAX_LED) + 50];
 
// 发送数据
void WS2812_Send(void) {
    uint32_t indx = 0;
    uint32_t color;
 
    for (int i = 0; i < MAX_LED; i++) {
#if USE_BRIGHTNESS
        color = ((LED_Mod[i][1] << 16) | (LED_Mod[i][2] << 8) | (LED_Mod[i][3]));
#else
        color = ((LED_Data[i][1] << 16) | (LED_Data[i][2] << 8) | (LED_Data[i][3]));
#endif
        for (int j = 23; j >= 0; j--) {
            if (color & (1 << j)) {
                pwmData[indx] = 43;  // T1H,高电平持续时间
            } else {
                pwmData[indx] = 17;  // T0H,低电平持续时间
            }
            indx++;
        }
    }
 
    for (int i = 0; i < 50; i++) {
        pwmData[indx++] = 0;        //T1L,T0L持续时间
    }
 
    HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_1, (uint32_t *)pwmData, indx);
}


WS2812B.h

#ifndef __WS2812B_H
 
 
#define __WS2812B_H
#include "main.h"
 
void Set_LED (int LEDnum, int Red, int Green, int Blue);//RGB
 
void Set_LED_HEX(int LEDnum, uint32_t colorValue);//十六进制
 
void Set_Brightness (int brightness);  // 0-100
void WS2812_Send (void);
 
 
#endif
 


主函数

导入头文件和定义接收数组

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "WS2812B.h"
/* USER CODE END Includes */
 
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
//接收数据解析 FD 亮度 小灯1 2 3 4 5 6 FF
uint8_t rx1data[15]={0};
uint8_t data[15];
uint8_t rx1flag=0;
uint8_t light=80;
/* USER CODE END PTD */


空闲中断接收数据和关闭DMA

/* USER CODE BEGIN 0 */
//空闲中断回调函数,参数Size为串口实际接收到数据字节数
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
  if(huart->Instance==USART1)
  {
    for(int i=0;i<15;i++){
      data[i]=rx1data[i];
    }
    rx1flag=1;
    //再次开启空闲中断接收,不然只会接收一次数据
    HAL_UARTEx_ReceiveToIdle_IT(&huart1,rx1data,Size);
  }
}
 
//  DMA 传输完成回调函数
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
    HAL_TIM_PWM_Stop_DMA(&htim3,TIM_CHANNEL_1);
}
 
/* USER CODE END 0 */


main函数 接收一帧数据并且控制小灯RGB

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_TIM3_Init();
 
  HAL_UARTEx_ReceiveToIdle_IT(&huart1,rx1data,sizeof(rx1data));
  HAL_TIM_PWM_Stop_DMA(&htim3,TIM_CHANNEL_1);
 
  while (1)
  {
    if(rx1flag==1){
      
      if(data[0]==0xFD){
        Set_LED(0,data[2],data[3]>>4,data[3]&0x0f);
        Set_LED(1,data[4],data[5]>>4,data[5]&0x0f);
        Set_LED(2,data[6],data[7]>>4,data[7]&0x0f);
        Set_LED(3,data[8],data[9]>>4,data[9]&0x0f);
        Set_LED(4,data[10],data[11]>>4,data[11]&0x0f);
        Set_LED(5,data[12],data[13]>>4,data[13]&0x0f);
        if(data[1]>0){
        light=data[1];}
        Set_Brightness(light);
        WS2812_Send();
        rx1flag=0;
      }
    }
 
  }
}


帧解析

FD F0 0F 00 0F F0 00 F0 00 0F 00 FF 0F 0F FF

帧头帧尾    FD- FF


第一个字节数据 是调节RGB亮度       F0

第二第三个字节 控制第一个RGB 显示红色   0F 00

第四第五个字节 控制第二个RGB 显示黄色   0F F0

第六第七个字节 控制第三个RGB 显示绿色   00 F0

第八第九个字节 控制第四个RGB 显示蓝色   00 0F

第十第十一个字节 控制第五个RGB 显示靛蓝 00 FF

第十二第十三个字节 控制第6个RGB显示紫色  0F 0F


效果




嘉立创


https://oshwhub.com/chem4111/ledboad

链接:https://pan.baidu.com/s/1LIP_g_fawxpjzqoWyoT4GQ?pwd=nc54

提取码:nc54

目录
相关文章
小巴陪你搞技术-STM32驱动1602时钟
小巴陪你搞技术-STM32驱动1602时钟
|
3月前
|
传感器
手把手在STM32F103C8T6上构建可扩展可移植的DHT11驱动
【8月更文挑战第29天】本文详细介绍在STM32F103C8T6上构建可扩展且可移植的DHT11温湿度传感器驱动的步骤,包括硬件与软件准备、硬件连接、驱动代码编写及测试。通过这些步骤,可根据实际项目需求优化和扩展代码。
104 0
|
4月前
STM32Cubemx PWM驱动加湿器模拟火山喷发效果
STM32Cubemx PWM驱动加湿器模拟火山喷发效果
69 14
|
4月前
STM32Cubemx PWM驱动SG90舵机
STM32Cubemx PWM驱动SG90舵机
164 13
|
4月前
STM32CubeMX mpu6050驱动
STM32CubeMX mpu6050驱动
72 10
|
4月前
STM32CubeMX EC11旋转编码器驱动
STM32CubeMX EC11旋转编码器驱动
222 10
|
4月前
STM32CubeMX OLED驱动
STM32CubeMX OLED驱动
65 10
|
4月前
|
芯片
STM32CubeMX TM1637驱动数码管
STM32CubeMX TM1637驱动数码管
110 6
|
4月前
STM32CubeMX ULN2003步进电机驱动
STM32CubeMX ULN2003步进电机驱动
62 0