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

21 篇文章 11 订阅
20 篇文章 33 订阅
本文详细介绍了如何使用STM32通过软件模拟时序来驱动WS2812 RGB灯带。内容包括WS2812的通信协议、代码实现、复位码要求以及注意事项。通过内联函数和NOP指令精确控制高电平和低电平的时间,确保满足WS2812的纳秒级时序要求。
摘要由CSDN通过智能技术生成

相关链接

​​​​​​​​​​​​​​硬件部分​​​​​​​

WS2812(软件部分)(PWM+DMA) ​​​​​​​

协议

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

软件

思路

用GPIO模拟时序进行发送,因为是ns级延迟,所以延迟需要较高要求

初始化

7caa60975de3419aba99620cb77957d4.png

 将GPIO设为开漏浮空输出,最高规格输出

使用的是84MHz的系统频率

0码

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

这里选用400ns高+850ns低

因为84MHz的系统频率每一条指令执行是12ns左右,而调用函数需要一定时间,且不是一条指令就能解决的(要存起来原来的地址,跳转到新地址等等)综合测下来需要几百ns

因此使用内联函数

inline void WS2812_Code_0(void)
{
    HAL_GPIO_WritePin(WS2812_GPIO_Group, WS2812_GPIO_Pin, GPIO_PIN_SET);
    for (int i = 0; i < 6; i++)
        __nop();
    HAL_GPIO_WritePin(WS2812_GPIO_Group, WS2812_GPIO_Pin, GPIO_PIN_RESET);
    for (int i = 0; i < 11; i++)
        __nop();
}

有些人说HAL库的GPIO库函数时间较长不能满足要求

这里实测是可以满足ws2812的ns要求的

为了方便就不做修改,不使用直接操作寄存器的方式了

a49a71793c314f518cfbc9e820f52822.png

 0码的波形和时间

1码

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

这里选用850ns高+400ns低

inline void WS2812_Code_1(void)
{
    HAL_GPIO_WritePin(WS2812_GPIO_Group, WS2812_GPIO_Pin, GPIO_PIN_SET);
    for (int i = 0; i < 12; i++)
        __nop();
    HAL_GPIO_WritePin(WS2812_GPIO_Group, WS2812_GPIO_Pin, GPIO_PIN_RESET);
    for (int i = 0; i < 4; i++)
        __nop();
}

beacad6cb3b949178e167521cd005159.png

1码的波形和时间

复位码

复位码:>280us低电平

void WS2812_Code_Reast(void)
{
    HAL_GPIO_WritePin(WS2812_GPIO_Group, WS2812_GPIO_Pin, GPIO_PIN_RESET);
    HAL_Delay(1);
}

这里让低电平为1ms

解码

发送1Bety数据

从高位到低位发送

inline void WS2812_Send_Byte(uint8_t Dat)
{
    for (int i = 0; i < 8; i++)
    {
        if (Dat & 0x80)
        {
            WS2812_Code_1();
        }
        else
        {
            WS2812_Code_0();
        }
        Dat <<= 1;
    }
}

RGB解码和发送

因为没有24位的数据,平常使用的灯的数量较少,顶天100个,所以这边使用32位数据来保存(也可以建立个结构体)

32位数据按RGB保存(通用),然后ws2812解码程序按照GRB发送

void WS2812_Color_Decode(uint32_t Color)
{
    WS2812_Send_Byte((Color & 0x00ff00) >> 8);
    WS2812_Send_Byte((Color & 0xff0000) >> 16);
    WS2812_Send_Byte((Color & 0x0000ff) >> 0);
}

其他

我建立一个数数组来保存RGB颜色信息,需要改变颜色时直接更改这个数组的对于值即可

uint32_t WS2812_Data[WS2812_Num] = {0};

这个函数将数组中的所有数据发送给灯

//动作函数,发送编码给灯
void WS2812_Send(void)
{
    for (int i = 0; i < 2; i++)
    {
        WS2812_Code_Reast();
        for (int i = 0; i < WS2812_Num; i++)
        {
            WS2812_Color_Decode(WS2812_Data[i]);
        }
        HAL_GPIO_WritePin(WS2812_GPIO_Group, WS2812_GPIO_Pin, GPIO_PIN_SET);
    }
}

注意

1.上电时需要执行一次复位函数

2.发送完数据之后ws2812会自动按照最后一次设置的数据显示

3.上述的0码和1码是F4系列在84MHz的系统主频下的数值,其他请配合逻辑分析仪自行测试 

成品

stm32驱动ws2812演示

百度网盘

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值