STM32F407 HAL下使用PWM+DMA驱动WS2812,定时器与DMA完整配配置程序
时间: 2025-06-19 20:56:45 浏览: 21
### STM32F407 使用 HAL 库通过 PWM 和 DMA 驱动 WS2812 的完整配置
以下是基于 STM32F407 使用 HAL 库实现 PWM 和 DMA 驱动 WS2812 的完整代码示例。该代码包括定时器和 DMA 的配置,以及 WS2812 数据的生成与发送逻辑。
#### 定时器配置
使用 TIMx(例如 TIM2)作为 PWM 信号的来源,并设置其预分频器(PSC)和自动重装载值(ARR),以生成满足 WS2812B 要求的信号频率[^1]。
```c
// 定时器初始化函数
void MX_TIM2_Init(void)
{
TIM_HandleTypeDef htim2;
TIM_OC_InitTypeDef sConfigOC;
// 初始化定时器句柄
htim2.Instance = TIM2;
htim2.Init.Prescaler = 83; // 设置 PSC=83 (系统时钟为 84MHz, 分频后为 1MHz)
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 999; // 设置 ARR=999 (周期为 1ms)
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim2);
// 配置输出通道
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0; // 初始占空比为 0
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
// 启用定时器
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
}
```
#### DMA 配置
使用 DMA 将生成的数据传输到 TIMx 的捕获/比较寄存器(CCR),从而实现数据流的连续发送[^3]。
```c
// DMA 初始化函数
void MX_DMA_Init(void)
{
DMA_HandleTypeDef hdma_tim2_ch1;
// 初始化 DMA 句柄
hdma_tim2_ch1.Instance = DMA1_Stream5;
hdma_tim2_ch1.Init.Channel = DMA_CHANNEL_6;
hdma_tim2_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tim2_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim2_ch1.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim2_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_tim2_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_tim2_ch1.Init.Mode = DMA_CIRCULAR;
hdma_tim2_ch1.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_tim2_ch1);
// 配置 DMA 和定时器关联
__HAL_LINKDMA(&htim2, hdma[TIM_DMA_ID_CC1], hdma_tim2_ch1);
}
// 启用 DMA 传输
void Start_DMA_Transfer(uint32_t* data, uint16_t length)
{
HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, data, length);
}
```
#### WS2812 数据生成
WS2812B 的数据协议要求每个比特位由不同的高电平宽度表示:1 码为 700ns 高 + 300ns 低,0 码为 400ns 高 + 800ns 低。以下代码生成对应的数据数组。
```c
#define CODE_1 (58) // 1 码对应的计数次数
#define CODE_0 (25) // 0 码对应的计数次数
#define Pixel_NUM 1 // LED 数量
typedef struct {
uint8_t R;
uint8_t G;
uint8_t B;
} RGB_Color_TypeDef;
RGB_Color_TypeDef color = {255, 0, 0}; // 示例颜色:红色
uint32_t ws2812_data[Pixel_NUM * 24]; // 存储 WS2812 数据
void Generate_WS2812_Data(RGB_Color_TypeDef Color)
{
uint8_t rgb_data[3] = {Color.G, Color.R, Color.B}; // WS2812B 颜色顺序为 GRB
uint8_t bit_index, pixel_index;
uint32_t* data_ptr = ws2812_data;
for (pixel_index = 0; pixel_index < Pixel_NUM; pixel_index++) {
for (bit_index = 0; bit_index < 24; bit_index++) {
if ((rgb_data[bit_index / 8] >> (7 - (bit_index % 8))) & 0x01) {
*data_ptr++ = CODE_1; // 如果是 1 码
} else {
*data_ptr++ = CODE_0; // 如果是 0 码
}
}
}
}
```
#### 主程序
将上述功能整合到主程序中,完成 WS2812B 的驱动。
```c
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
MX_DMA_Init();
Generate_WS2812_Data(color); // 生成 WS2812 数据
Start_DMA_Transfer(ws2812_data, Pixel_NUM * 24); // 启动 DMA 传输
while (1) {
// 主循环可以用于其他任务
}
}
```
---
阅读全文
相关推荐


















