灯带型号
淘宝购买此灯带,5V-2.7MM-60灯每米,1米:


灯带引出三根线,红线是电源正极(5V),白线是电源负极(GND,与单片机共地),绿线是PWM信号线(STM32 GPIO引出)。
硬件配置
使用STM32F405的PB0引脚做PWM,推挽输出无上拉:
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspPostInit 0 */
/* USER CODE END TIM3_MspPostInit 0 */
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM3 GPIO Configuration
PB0 ------> TIM3_CH3
*/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
else if(timHandle->Instance==TIM4)
{
/* USER CODE BEGIN TIM4_MspPostInit 0 */
/* USER CODE END TIM4_MspPostInit 0 */
/* USER CODE BEGIN TIM4_MspPostInit 1 */
/* USER CODE END TIM4_MspPostInit 1 */
}
}
未经验证的驱动能力增强硬件接法:硬件用一5V正极接上4.7kΩ电阻连接PB0(FT),并开漏配置“GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;”,“ GPIO_InitStruct.Pull = GPIO_NOPULL;”。
根据数据手册
https://docs.keysking.com/assets/files/WS2812数据手册-c2fb4796e75b0ce7d513045045c06b2a.pdf
时序特性:

打开定时器3并配置DMA
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspInit 0 */
/* USER CODE END TIM3_MspInit 0 */
/* TIM3 clock enable */
__HAL_RCC_TIM3_CLK_ENABLE();
/* TIM3 DMA Init */
/* TIM3_CH3 Init */
hdma_tim3_ch3.Instance = DMA1_Stream7;
hdma_tim3_ch3.Init.Channel = DMA_CHANNEL_5;
hdma_tim3_ch3.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tim3_ch3.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim3_ch3.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim3_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_tim3_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_tim3_ch3.Init.Mode = DMA_CIRCULAR;
hdma_tim3_ch3.Init.Priority = DMA_PRIORITY_LOW;
hdma_tim3_ch3.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_tim3_ch3) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(tim_baseHandle,hdma[TIM_DMA_ID_CC3],hdma_tim3_ch3);
/* USER CODE BEGIN TIM3_MspInit 1 */
/* USER CODE END TIM3_MspInit 1 */
}
配置定时器3频率为800kHz:
/* TIM3 init function */
void MX_TIM3_Init(void)
{
/* USER CODE BEGIN TIM3_Init 0 */
/* USER CODE END TIM3_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM3_Init 1 */
/* USER CODE END TIM3_Init 1 */
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 209; // 168MHz/210 = 800KHz,符合WS2812标准
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM3_Init 2 */
/* USER CODE END TIM3_Init 2 */
HAL_TIM_MspPostInit(&htim3);
}
软件驱动模块
再根据数据手册:

rgb_drive.h
#ifndef __RGBDRIVE_H
#define __RGBDRIVE_H
#include "stm32f4xx_hal.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define WS2812_LED_NUM 60U
void WS2812_Init(void);
void WS2812_Set(uint16_t index, uint8_t r, uint8_t g, uint8_t b);
void WS2812_Clear(void);
void WS2812_Show(void);
#ifdef __cplusplus
}
#endif
#endif
rgb_drive.c
#include "rgb_drive.h"
#include <string.h>
extern TIM_HandleTypeDef htim3;
#define WS2812_BITS_PER_LED 24U
#define WS2812_RESET_SLOTS 120U
#define WS2812_BUF_LEN (WS2812_LED_NUM * WS2812_BITS_PER_LED + WS2812_RESET_SLOTS)
/* TIM3: 168MHz / 210 = 800kHz, 1 bit = 1.25us */
#define WS2812_PERIOD_TICKS 209U
/* 约 0.4us 和 0.85us, 适配 800kHz 周期 */
#define WS2812_T0H_TICKS 67U
#define WS2812_T1H_TICKS 143U
static uint8_t s_led_rgb[WS2812_LED_NUM][3]; /* [R, G, B] */
static uint32_t s_pwm_buf[WS2812_BUF_LEN];
static void WS2812_BuildBuffer(void)
{
uint32_t idx = 0;
for (uint16_t led = 0; led < WS2812_LED_NUM; led++)
{
uint8_t r = s_led_rgb[led][0];
uint8_t g = s_led_rgb[led][1];
uint8_t b = s_led_rgb[led][2];
/* WS2812 默认 GRB 顺序 */
for (int8_t bit = 7; bit >= 0; bit--)
{
s_pwm_buf[idx++] = (g & (1U << bit)) ? WS2812_T1H_TICKS : WS2812_T0H_TICKS;
}
for (int8_t bit = 7; bit >= 0; bit--)
{
s_pwm_buf[idx++] = (r & (1U << bit)) ? WS2812_T1H_TICKS : WS2812_T0H_TICKS;
}
for (int8_t bit = 7; bit >= 0; bit--)
{
s_pwm_buf[idx++] = (b & (1U << bit)) ? WS2812_T1H_TICKS : WS2812_T0H_TICKS;
}
}
/* 末尾补足低电平, 满足 reset 时间 */
for (; idx < WS2812_BUF_LEN; idx++)
{
s_pwm_buf[idx] = 0;
}
}
//void WS2812_Init(void)
//{
// memset(s_led_rgb, 0, sizeof(s_led_rgb));
// memset(s_pwm_buf, 0, sizeof(s_pwm_buf));
// HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_3);
// __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0);
//}
void WS2812_Init(void)
{
/* 上电全暖橘色: R=255, G=100, B=0 */
for (uint16_t i = 0; i < WS2812_LED_NUM; i++)
{
s_led_rgb[i][0] = 255; /* R */
s_led_rgb[i][1] = 100; /* G */
s_led_rgb[i][2] = 0; /* B */
}
memset(s_pwm_buf, 0, sizeof(s_pwm_buf));
HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_3);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0);
WS2812_Show(); /* 立即显示暖橘色 */
}
void WS2812_Set(uint16_t index, uint8_t r, uint8_t g, uint8_t b)
{
if (index >= WS2812_LED_NUM)
{
return;
}
s_led_rgb[index][0] = r;
s_led_rgb[index][1] = g;
s_led_rgb[index][2] = b;
}
void WS2812_Clear(void)
{
memset(s_led_rgb, 0, sizeof(s_led_rgb));
}
void WS2812_Show(void)
{
WS2812_BuildBuffer();
HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_3);
if (HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_3, s_pwm_buf, WS2812_BUF_LEN) != HAL_OK)
{
return;
}
/* 有 DMA 就等 DMA 完成, 没有就按总时长等一小段时间 */
if (htim3.hdma[TIM_DMA_ID_CC3] != NULL)
{
while (HAL_DMA_GetState(htim3.hdma[TIM_DMA_ID_CC3]) != HAL_DMA_STATE_READY)
{
}
}
else
{
HAL_Delay(2);
}
HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_3);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0);
}
浙公网安备 33010602011771号