板子是野火指南者(其他stm32也适用)

使用的库是标准库(标准库太麻烦,我要转战hal)

具体的思路是tim输出pwm波+dma内存到外设

注意:tim的dma是需要对着表选的,tim输出的pwm口也是需要看着表选的。我在这里选了tim3的ch1(A6),以及其对应的dma1通道5

4f90f35c37d34efa94c206f48ce0e1be.png

 9d8cbc9656fe4b929a5d17305d0210e2.png

我们通过查询可以得知ws2812B灯带的频率是800khz,stm32的晶振频率是72mhz,所以我们72/90等于0.8,我们对定时器进行一个分频。

我购买的1m灯带是有60个灯,所以我们创建一个数组,每个灯有三种颜色grb,每种颜色需要8位来进行控制其亮灭。

宏定义:

#define WS2812B_LED_NUM 60
#define WS2812B_RESET_LEN 42
#define WS2812B_DMA_BUF_LEN (WS2812B_LED_NUM * 24 + WS2812B_RESET_LEN)

uint16_t WS2812B_DMA_Buffer[WS2812B_DMA_BUF_LEN];

#define CODE_1 54 // 高电平时间:0.9 μs (54/72 MHz)
#define CODE_0 18 // 高电平时间:0.35 μs (18/72 MHz)
RGB_Color_TypeDef clear={0,0,0};
RGB_Color_TypeDef table[16] = 
{
	
   {254,67,101}, 
   {76,0,10},
   {249,15,173},
   {128,0,32},
   {158,46,36},
   {184,206,142},
   {227,23,13},
   {178,34,34},
   {255,99,71},
   {99,38,18},
   {255,97,0},
   {21,161,201},
   {56,94,15},
   {50,205,50},
   {160,32,240},
   {218,60,90}
};

定时器处理+dma代码:

void TIM3_DMA_Init(void)
{
    // 启用时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  // 启用 TIM3 时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);    // 启用 DMA1 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 启用 GPIOA 时钟

    // 配置 GPIOA6 为复用功能输出 (TIM3 CH1)
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      // 复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    // 50 MHz
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置 TIM3
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_TimeBaseStructure.TIM_Period = 89;         // 1.25us (72 MHz / 800 kHz - 1)
    TIM_TimeBaseStructure.TIM_Prescaler = 0;       // 不分频
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    // 配置 TIM3 通道 1 为 PWM 输出
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 50;             // 初始占空比为 0
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);

    // 启用 TIM3 的 PWM
    TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
    TIM_ARRPreloadConfig(TIM3, ENABLE);
    TIM_Cmd(TIM3, ENABLE);

    // 配置 DMA
    DMA_InitTypeDef DMA_InitStructure;
    DMA_DeInit(DMA1_Channel6); // TIM3_CH1 对应 DMA1 通道 6
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM3->CCR1; // 外设地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)WS2812B_DMA_Buffer; // 内存地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  // 搬运方向:内存到外设
    DMA_InitStructure.DMA_BufferSize = WS2812B_DMA_BUF_LEN; // 缓冲区大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不自增
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址自增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 外设数据大小 16 位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 内存数据大小 16 位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 优先级高
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 禁用存储器到存储器模式
    DMA_Init(DMA1_Channel6, &DMA_InitStructure);

    // 启用 TIM3 的 DMA 请求
    TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);
}

灯带代码:

void WS2812B_SetPixel(uint16_t index, RGB_Color_TypeDef color)
{
    if (index >= WS2812B_LED_NUM) return;

    uint16_t i, offset = index * 24;

    for (i = 0; i < 8; i++)
    {
        WS2812B_DMA_Buffer[offset + i]   = (color.G & (1 << (7 - i))) ? CODE_1 : CODE_0;
        WS2812B_DMA_Buffer[offset + 8 + i] = (color.R & (1 << (7 - i))) ? CODE_1 : CODE_0;
        WS2812B_DMA_Buffer[offset + 16 + i] = (color.B & (1 << (7 - i))) ? CODE_1 : CODE_0;
    }
}
void WS2812B_SetAll(RGB_Color_TypeDef color)
{
    uint16_t i;
    for (i = 0; i < WS2812B_LED_NUM; i++)
    {
        WS2812B_SetPixel(i, color);
    }
}

void WS2812B_Clear(void)
{
    uint16_t i;
    for (i = 0; i < WS2812B_DMA_BUF_LEN; i++)
    {
        WS2812B_DMA_Buffer[i] = 0;
    }
		WS2812B_TurnOnAll(clear);
}

void WS2812B_Show(void)
{
    uint32_t timeout = 1000000; // 超时计数

    DMA_Cmd(DMA1_Channel6, ENABLE);  // 启用 DMA
    TIM_Cmd(TIM3, ENABLE);           // 启动 TIM3

    // 检查 TIM3 和 DMA 状态
    if (!(TIM3->CR1 & TIM_CR1_CEN))
    {
        printf("TIM3 is not running!\n");
        return;
    }

    if (!(TIM3->DIER & TIM_DIER_CC1DE))
    {
        printf("TIM3 DMA request not enabled!\n");
        return;
    }

    // 等待 DMA 传输完成或超时
    while (!DMA_GetFlagStatus(DMA1_FLAG_TC6) && --timeout);

    if (timeout == 0)
    {
        printf("DMA transfer timeout!\n");
        return;
    }

    // 清除 DMA 标志位
    DMA_ClearFlag(DMA1_FLAG_TC6);

    // 禁用 DMA 和 TIM3
    DMA_Cmd(DMA1_Channel6, DISABLE);
    TIM_Cmd(TIM3, DISABLE);
}

void WS2812B_RunningLight(void)
{
    static uint8_t position = 0;

    WS2812B_Clear();
    //WS2812B_SetPixel(position, 0, 255, 0); // 设置当前 LED 为绿色

    position = (position + 1) % WS2812B_LED_NUM;

    WS2812B_Show();
}

void WS2812B_TurnOnAll(RGB_Color_TypeDef color)
{
    WS2812B_SetAll(color);
    WS2812B_Show();
}
void WS2812B_TurnONE(int num,RGB_Color_TypeDef color)//前num个灯亮color
{
	WS2812B_Clear();
	WS2812B_Show();
	for(int i=0;i<num;i++)
		WS2812B_SetPixel(i,color);
	WS2812B_Show();
}

灯带.h

typedef struct RGB_Color
{
	int R;
	int G;
	int B;
}RGB_Color_TypeDef;

extern RGB_Color_TypeDef table[16];
extern RGB_Color_TypeDef bian;

void TIM3_DMA_Init(void);          // 初始化 TIM3 和 DMA
void TIM5_1ms_Init(void);
void WS2812B_Clear(void);          // 清空灯带
void WS2812B_Show(void);           // 显示复位信号
void WS2812B_RunningLight(void);
void WS2812B_TurnOnAll(RGB_Color_TypeDef color);
void WS2812B_TurnONE(int num,RGB_Color_TypeDef color);
void liushui(int num,RGB_Color_TypeDef color);
void DelayMs(__IO uint32_t hwMill);

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐