相关链接
硬件部分
WS2812(软件部分)(PWM+DMA)
协议
WS2812是一种异步串行通信,它每一位数据时间是ns级别的
默认是高电平状态
0码:220-380ns高电平+580-1600ns低电平
1码:580-1600ns高电平+220-380ns低电平
复位码:>280us低电平
24Bit数据来代表GRB的亮度值
从高位到低位发送,分别按照G->R->B的顺序发送
先发送第一个灯的数据(离Dat输入直连的那个灯)
例子:
分别发送红绿蓝三色的数据给3个ws2812
软件
思路
用GPIO模拟时序进行发送,因为是ns级延迟,所以延迟需要较高要求
初始化
将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要求的
为了方便就不做修改,不使用直接操作寄存器的方式了
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();
}
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演示