一、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
计算
-
计算计数器周期值(ARR):
我们需要让一个PWM周期为1.25µs,即:
给定系统时钟频率为48 MHz,时钟周期为:
因此,计数器周期值为:
-
设置高电平和低电平持续时间:
- 高电平时间约为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) {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) {LED_Data[LEDnum][0] = LEDnum;LED_Data[LEDnum][2] = (colorValue >> 16) & 0xFF; // RLED_Data[LEDnum][1] = (colorValue >> 8) & 0xFF; // GLED_Data[LEDnum][3] = colorValue & 0xFF; // B
}void Set_Brightness(int brightness) {if (brightness > 90) brightness = 90; // 最大亮度值为100if (brightness < 10) brightness = 10; // 最小亮度值为0for (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;}}
}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_BRIGHTNESScolor = ((LED_Mod[i][1] << 16) | (LED_Mod[i][2] << 8) | (LED_Mod[i][3]));
#elsecolor = ((LED_Data[i][1] << 16) | (LED_Data[i][2] << 8) | (LED_Data[i][3]));
#endiffor (int j = 23; j >= 0; j--) {if (color & (1 << j)) {pwmData[indx] = 34; // 高电平持续时间} else {pwmData[indx] = 17; // 低电平持续时间}indx++;}}for (int i = 0; i < 50; i++) {pwmData[indx] = 0;indx++;}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);//RGBvoid 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;
/* USER CODE END PTD */
空闲中断接收数据
/* 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);}
}
/* 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));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);Set_Brightness(data[1]);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/1WSJNQzQiiU7Vc3ed04pNPw?pwd=1cjy
提取码:1cjy