stm32驱动ws2812
时间: 2023-07-30 14:12:14 浏览: 199
要驱动WS2812 LED灯条,需要使用STM32的定时器和DMA功能。以下是一个简单的示例代码:
```
#include "stm32f10x.h"
#define LED_NUM 8
uint8_t led_data[LED_NUM * 3];
void WS2812_Init(void)
{
// 配置定时器
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_TIM1, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 89;
TIM_TimeBaseInitStruct.TIM_Prescaler = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OC1Init(TIM1, &TIM_OCInitStruct);
TIM_Cmd(TIM1, ENABLE);
// 配置DMA
DMA_InitTypeDef DMA_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel2);
DMA_InitStruct.DMA_BufferSize = LED_NUM * 24;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)led_data;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&TIM1->CCR1;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel2, &DMA_InitStruct);
// 发送复位信号
uint8_t reset_data[4] = {0x00, 0x00, 0x00, 0x00};
DMA_Cmd(DMA1_Channel2, ENABLE);
DMA_SetCurrDataCounter(DMA1_Channel2, 4);
DMA_MemoryTargetConfig(DMA1_Channel2, (uint32_t)reset_data, DMA_Memory_0);
while (DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC2);
}
void WS2812_SendData(void)
{
DMA_Cmd(DMA1_Channel2, ENABLE);
DMA_SetCurrDataCounter(DMA1_Channel2, LED_NUM * 24);
DMA_MemoryTargetConfig(DMA1_Channel2, (uint32_t)led_data, DMA_Memory_0);
while (DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC2);
}
void WS2812_SetColor(uint8_t index, uint8_t r, uint8_t g, uint8_t b)
{
uint32_t color = ((uint32_t)g << 16) | ((uint32_t)r << 8) | (uint32_t)b;
uint32_t mask = 0x800000;
for (int i = 0; i < 24; i++) {
if (color & mask) {
led_data[index * 24 + i] = 18;
} else {
led_data[index * 24 + i] = 9;
}
mask >>= 1;
}
}
int main(void)
{
WS2812_Init();
while (1) {
for (int i = 0; i < LED_NUM; i++) {
WS2812_SetColor(i, 255, 0, 0);
}
WS2812_SendData();
delay_ms(500);
for (int i = 0; i < LED_NUM; i++) {
WS2812_SetColor(i, 0, 255, 0);
}
WS2812_SendData();
delay_ms(500);
for (int i = 0; i < LED_NUM; i++) {
WS2812_SetColor(i, 0, 0, 255);
}
WS2812_SendData();
delay_ms(500);
}
}
```
在这个例子中,我们使用了定时器1的通道1来控制WS2812的数据线。通过配置定时器的周期和占空比,可以产生0和1的高电平时间。然后,我们使用DMA将数据发送到定时器的CCR1寄存器,以控制高电平时间的长度。
在WS2812_SendData函数中,我们启动DMA传输,将led_data数组中的数据发送到WS2812灯条。在WS2812_SetColor函数中,我们将颜色值转换为对应的高电平时间,存储在led_data数组中。
需要注意的是,在初始化之前,需要使用GPIO_ResetBits将数据线拉低一段时间,以产生复位信号。在发送数据之后,需要等待一段时间,以确保数据已经全部发送完毕。
阅读全文