使用Stm32F103C8t6的定时器2通道1PWM+DMA驱动W2812B代码
时间: 2024-06-08 11:08:32 浏览: 153
hal库 定时器 PWM模式 DMA方式 控制WS2812B显示
以下是使用Stm32F103C8t6的定时器2通道1PWM+DMA驱动W2812B的代码,可以参考:
```c
#include "stm32f10x.h"
#define LED_NUM 8 // 定义LED数量
#define LED_BUF_SIZE (LED_NUM * 24) // 定义LED数据缓存大小
// 定义W2812B的高电平和低电平的时间
#define T0H 14
#define T1H 52
#define TL 52
// 定义W2812B的数据格式
typedef struct {
uint8_t g;
uint8_t r;
uint8_t b;
} color_t;
// 定义LED数据缓存
color_t led_buf[LED_NUM];
// 定义DMA传输完成标志位
volatile uint8_t dma_tx_complete = 0;
void delay_us(uint32_t us) {
SysTick->LOAD = 72 * us;
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk;
while(!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
SysTick->CTRL = 0;
}
void init_pwm(void) {
// 使能定时器2和GPIOA的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 初始化GPIOA的PA0引脚为复用推挽输出模式
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 初始化定时器2的PWM模式
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 89; // PWM周期为90个时钟周期
TIM_TimeBaseStructure.TIM_Prescaler = 0; // 不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
// 启用定时器2的PWM输出
TIM_Cmd(TIM2, ENABLE);
}
void init_dma(void) {
// 使能DMA1时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Channel7);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM2->CCR1; // 定时器2的通道1
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)led_buf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = LED_BUF_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel7, &DMA_InitStructure);
// 配置DMA1通道7传输完成中断
DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 启用DMA1通道7
DMA_Cmd(DMA1_Channel7, ENABLE);
}
void dma_tx_complete_irqhandler(void) {
// 清除传输完成标志位
DMA_ClearITPendingBit(DMA1_IT_TC7);
dma_tx_complete = 1;
}
void send_led_data(void) {
uint16_t i, j;
uint8_t data;
// 填充LED数据缓存
for(i = 0; i < LED_NUM; i++) {
for(j = 0; j < 8; j++) {
data = (led_buf[i].g << j) & 0x80 ? T1H : T0H;
*(&led_buf[i].g + 1) <<= 1;
led_buf[i].g |= data > TL;
data = (led_buf[i].r << j) & 0x80 ? T1H : T0H;
*(&led_buf[i].r + 1) <<= 1;
led_buf[i].r |= data > TL;
data = (led_buf[i].b << j) & 0x80 ? T1H : T0H;
*(&led_buf[i].b + 1) <<= 1;
led_buf[i].b |= data > TL;
}
}
// 等待上一次传输完成
while(!dma_tx_complete);
// 清除传输完成标志位
dma_tx_complete = 0;
// 启动DMA传输
DMA_Cmd(DMA1_Channel7, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel7, LED_BUF_SIZE);
DMA_Cmd(DMA1_Channel7, ENABLE);
}
int main(void) {
// 初始化SysTick定时器,用于延时
SysTick_Config(SystemCoreClock / 1000000);
// 初始化PWM输出
init_pwm();
// 初始化DMA传输
init_dma();
// 填充LED数据缓存
int i;
for(i = 0; i < LED_NUM; i++) {
led_buf[i].r = 0x00;
led_buf[i].g = 0x00;
led_buf[i].b = 0x00;
}
// 发送LED数据
while(1) {
send_led_data();
delay_us(500); // 500us的刷新周期
}
}
```
需要注意的是,该代码在 PA0 引脚上输出 PWM 波形,因此需要将 W2812B 的 DI 引脚连接到 PA0 引脚上。另外,W2812B 的数据格式为 G-R-B(即绿色在前,红色在中间,蓝色在最后),因此在填充 LED 数据缓存时需要按照该格式填充。
阅读全文