【STM32F4系列】【HAL库】【自制库】WS2812(软件部分)(PWM+DMA)

相关链接

硬件介绍(PCB设计方案)

模拟时序发送

协议

WS2812是一种异步串行通信,它每一位数据时间是ns级别的

72301f6812644a2aaa7167d2188dc4b8.png

46761d63e33b40719d96461b60932f4a.png

默认是高电平状态

0码:220-380ns高电平+580-1600ns低电平

1码:580-1600ns高电平+220-380ns低电平

复位码:>280us低电平

9297e86fb9164a3c8c06b7a92fd22660.png

4644eb5c9652453eb89b74160c85f56e.png

24Bit数据来代表GRB的亮度值

从高位到低位发送,分别按照G->R->B的顺序发送

先发送第一个灯的数据(离Dat输入直连的那个灯)

例子:
分别发送红绿蓝三色的数据给3个ws2812

f21bfd2a9e8f49abaa1610fa77a84007.png

外设设置

硬件PWM

分析

STM32F4系列的系统频率为84MHz

定时器的最高频率(不改动时钟设置的情况下)为84MHz,也就是11ns左右,

完全可足以驱动WS2812(几百ns级的)

设系统频率为 f 单位是MHz

则0码.1码的高电平占空比 n0 n1(0码高电平取370ns左右,1码高电平取850ns左右)

重载值 n 分别为

n 0 = 0.37 f , n 1 = 0.85 f , n = 1.25 f n_{0}=0.37f,n_{1}=0.85f,n=1.25f n0=0.37f,n1=0.85f,n=1.25f

四舍五入一下,取n=105,n0=32,n1=71

HAL设置

在这里插入图片描述

PWM输出,不分频,重载值设为105

其他不需要改动

在这里插入图片描述

PWM的输出GPIO设置为开漏浮空输出(外接5V上拉)

DMA

分析

DMA是外设直接访问内存的一个手段,可以快速的传递数据

我们在这个例子里用到的是

将内存里的关于占空比的数据发送给定时器的比较值

让其发送具有编码含义的脉冲

PWM+DMA的一些问题:

使用HAL库DMA给定时器发送比较值时,会一次性发送多个(数组地址和长度)

定时器每当发送一个脉冲后,更改为下一个比较值,直到数组被发送完成,触发一次DMA中断

这样我们就可以利用这个特点发送WS2812的数据

HAL设置

在这里插入图片描述

设置PWM的输出通道为响应通道

从内存到外设模式(Direction的设置)

普通模式(Mode)

数据宽度(Data Width)为字(32bit)

方案设计

设置两个缓冲区,每个长度为25个uint32(其中前24个是发送的数据码,第25个是保持占空比为0)

缓冲区的第25个数据为0是确保DMA中断响应时是低电平(码字的低电平时间稍长,3-4us无所谓,但是不能出现而外的高电平)

发送复位码时则使用单独划分好的,在Flash里的静态数组

在DMA中断响应时,计算下次发送的数据给到缓冲区
这样只需要3个变量数组(2个缓冲区,1个存放灯带颜色数据),1个常量数组(复位码)

操作流程:

  1. 更改颜色信息给颜色数组
  2. 发送复位码,开启PWM+DMA
  3. 解码第一位颜色数据给到缓冲区0
  4. (DMA中断)发送缓冲区0给定时器
  5. (DMA中断)计算第二位颜色数据给缓冲区1
  6. (下一个)(DMA中断)发送缓冲区1给定时器
  7. (DMA中断)计算第三位颜色数据给缓冲区0

以此类推,直到发送完成

在这里插入图片描述

代码实现

解码函数

/**
 * @brief 将uint32转为发送的数据
 * @param Data:颜色数据
 * @param Ret:解码后的数据(PWM占空比)
 * @return
 * @author HZ12138
 * @date 2022-10-03 18:03:17
 */
void WS2812_uint32ToData(uint32_t Data, uint32_t *Ret)
{
    uint32_t zj = Data;
    uint8_t *p = (uint8_t *)&zj;
    uint8_t R = 0, G = 0, B = 0;
    B = *(p);     // B
    G = *(p + 1); // G
    R = *(p + 2); // R
    zj = (G << 16) | (R << 8) | B;
    for (int i = 0; i < 24; i++)
    {
        if (zj & (1 << 23))
            Ret[i] = WS2812_Code_1;
        else
            Ret[i] = WS2812_Code_0;
        zj <<= 1;
    }
    Ret[24] = 0;
}

用一个指针p,将数据中的RGB数据解码出来

然后使用一个循环,将数据存入缓冲区中

开始发送和复位

const uint32_t WS2812_Rst[240] = {0}; //复位码缓冲区
/**
 * @brief 开始发送颜色数据
 * @param 无
 * @return 无
 * @author HZ12138
 * @date 2022-10-03 18:05:13
 */
void WS2812_Start(void)
{
    HAL_TIM_PWM_Start_DMA(&WS2812_TIM, WS2812_TIM_Channel, (uint32_t *)WS2812_Rst, 240);
    WS2812_uint32ToData(WS2812_Data[0], WS2812_SendBuf0);
    WS2812_En = 1;
}
/**
 * @brief 发送复位码
 * @param 无
 * @return 无
 * @author HZ12138
 * @date 2022-10-03 18:05:33
 */
void WS2812_Code_Reast(void)
{
    HAL_TIM_PWM_Start_DMA(&WS2812_TIM, WS2812_TIM_Channel, (uint32_t *)WS2812_Rst, 240);
    WS2812_En = 0;
}

复位码缓冲区是常量数组,开始发送和单独复位码的区别WS2812_En的标志

WS2812_En为1时才执行交替发送缓冲区0和1

发送函数

/**
 * @brief 发送函数(DMA中断调用)
 * @param 无
 * @return 无
 * @author HZ12138
 * @date 2022-10-03 18:04:50
 */
void WS2812_Send(void)
{
    static uint32_t j = 0;
    static uint32_t ins = 0;
    if (WS2812_En == 1)
    {
        if (j == WS2812_Num)
        {
            j = 0;
            HAL_TIM_PWM_Stop_DMA(&WS2812_TIM, WS2812_TIM_Channel);
            WS2812_En = 0;
            return;
        }
        j++;
        if (ins == 0)
        {
            HAL_TIM_PWM_Start_DMA(&WS2812_TIM, WS2812_TIM_Channel, WS2812_SendBuf0, 25);
            WS2812_uint32ToData(WS2812_Data[j], WS2812_SendBuf1);
            ins = 1;
        }
        else
        {
            HAL_TIM_PWM_Start_DMA(&WS2812_TIM, WS2812_TIM_Channel, WS2812_SendBuf1, 25);
            WS2812_uint32ToData(WS2812_Data[j], WS2812_SendBuf0);
            ins = 0;
        }
    }
}

这个函数是在DMA中断中调用

思路如同前面所说

波形

在这里插入图片描述

整个波形全貌↑

在这里插入图片描述

两次发送的间隔(DMA中断中导致的)↑

在这里插入图片描述

1码↑

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sibTtygx-1664810051668)(D:\桌面文件\博客\WS2812\8.png)]

0码↑

成品

GitHub

百度网盘

  • 12
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
ws2812b是一种智能彩灯,在STM32上使用HAL库进行编程时,可以利用PWMDMA控制来控制彩灯的颜色和亮度。 PWM(脉宽调制)是一种常用的控制电子设备亮度的方法,通过改变PWM信号的占空比即高电平时间和低电平时间的比例,可以控制灯光的亮度。对于ws2812b彩灯,它需要接收到一串特定的脉冲信号来控制灯光的颜色和亮度,因此我们可以利用PWM信号来模拟这个特定的脉冲信号。 在使用HAL库进行编程时,可以利用定时器和PWM功能来生成脉冲信号。首先,我们需要初始化定时器和PWM通道,然后设置定时器的计数周期和预分频值,以确定脉冲信号的频率。接下来,我们可以通过改变PWM通道的CCR寄存器的值来改变脉冲信号的占空比,从而控制灯光的亮度。通过反复改变CCR寄存器的值,即可实现灯光的渐变效果。 为了实现更高效的控制,可以结合使用DMA(直接存储器访问)功能。DMA可以在处理器和外设之间直接传输数据,减轻CPU的负担。对于控制彩灯来说,我们可以把存储颜色和亮度信息的数组存放在内存中,然后通过DMA传输到PWM寄存器中,从而控制彩灯。通过配置DMA通道和中断,可以实现定时更新彩灯的效果。 总之,通过利用STM32HAL库,结合PWMDMA控制,我们可以方便地对ws2812b彩灯进行编程,实现灯光的颜色和亮度控制,使其呈现出丰富多彩的效果。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值