stm32和ws2812B相对较好的方案。SPI和UART
最近看不少人玩ws2812b。我搜了一下找到个比较好的。这个程序是spi+dma的,我修改了下在F030F4上面跑着挺好。大概的意思是E表示1。8表示0。一个字节处理两位。
我想了一下UART+DMA,没有时间做。如果用UART,设置到2.4M,每个位400nS(spec.: 250-550),反转一下,每三位处理一个bit,高高低表示1(800+400),低低高表示0(800+400)。 这样start+76位,543,210,总共一个字节处理3个位,停止位因为反转了就是低电平,间隔时间不足50uS,应该没影响。
如此,每24/3=8个字节处理一个灯,比SPI的12个字节更少。个位有什么看法。 直接用IO,写得我要吐了。 uart还是比较复杂的吧,有校验位停止位什么的,还是PWM+DMA最直接明了。 SPI的方式不错,速度慢的单片机都可以做 谢谢楼主分享。 Eiman 发表于 2018-8-15 15:38
uart还是比较复杂的吧,有校验位停止位什么的,还是PWM+DMA最直接明了。
校验位可以没有的,电压反转后,开始位必须是高,和2812协议相同,停止位作为间隔可以忽略。
想问一下pwm占用多少RAM和CPU资源。是不是整个DMA发送完成才需要CPU参与一次,论坛那位貌似现在没搞定,不知卡在哪里。 gmyu 发表于 2018-8-15 16:00
校验位可以没有的,电压反转后,开始位必须是高,和2812协议相同,停止位作为间隔可以忽略。
想问一下pw ...
我的是PWM+DMA点亮60个WS2812B没问题啊。
占用空间如下:
8 808 bytes of readonlycode memory
352 bytes of readonlydata memory
5 554 bytes of readwrite data memory Eiman 发表于 2018-8-15 16:18
我的是PWM+DMA点亮60个WS2812B没问题啊。
占用空间如下:
8 808 bytes of readonlycode memory
我用F030F4,只有4K RAM, 你这个远远超出,假定100个灯,100*2*24就4.8k了,而用SPI就只需要100*12=1.2kbyte。 这个差距还是比较大的,毕竟还要做各种效果,加上buffer就更不敢用pwm了。 发送一个LED的数据所需要的时间是 1.25*24 = 32us
而CPU生成数据所需的时间远远小于32us
那么就有了使用双缓冲,乒乓操作的条件
两个缓冲区,每个缓冲区处理25个LED,总共占用RAM:SPI 25*12*2 = 600bytes; USART 25*24*2 = 1200bytes,而且扩展到更长的灯带时不需要增加缓冲区长度
DMA传输完成中断产生后,最后两个个字节(SPI是半字)数据一个在移位寄存器中发送,另一个在TDR寄存器中等待发送,中断函数里面等待TXE标志位置位,重新配置DMA 20061002838 发表于 2018-8-16 17:10
发送一个LED的数据所需要的时间是 1.25*24 = 32us
而CPU生成数据所需的时间远远小于32us
那么就有了使用双 ...
不用缓冲区,直接写DMA的buff会出现什么情况。基本上写buff很短时间,可以在刷新ws2812的时候做。或者就算正在发送spi,更新dma数据区会怎么样。
你已经用UART实现了,对么?貌似是一个bit对一个字节。 gmyu 发表于 2018-8-16 17:24
不用缓冲区,直接写DMA的buff会出现什么情况。基本上写buff很短时间,可以在刷新ws2812的时候做。或者就 ...
不用双缓冲,直接写DMA的buf,不就把正在发送的数据给破坏了吗
没玩过WS2812,UART是前两天给坛友设计的一个方案,很容易可以翻到,用USART,同步模式,外部用D触发器,通过时钟信号锁存数据
没验证过 20061002838 发表于 2018-8-16 17:39
不用双缓冲,直接写DMA的buf,不就把正在发送的数据给破坏了吗
没玩过WS2812,UART是前两天给坛友设计的 ...
我上面说了,TX反转电平,加开始位可以看作9个bit,这样可以处理3个LED位,不用外接器件,不过没有试过。
btw,上面的程序我运行有点问题,颜色编码通常是rgb,但是ws2812用的是gbr,他虽然做了处理,但是颜色不对。
改了一下这个函数,把循环也去掉,运行可能快点。
void Sw28_SetPixelsColor(SW28_HandleTypeDef *swObj, uint8_t pix, uint32_t color)
{
uint8_t g; //r,g,b;
uint8_t *pb = swObj->BuffPoint + pix*12;
g= (uint8_t)(color>>8);
*pb++ = LED2B; g >>= 2;
*pb++ = LED2B; g >>= 2;
*pb++ = LED2B; g >>= 2;
*pb = LED2B;
g= (uint8_t)(color>>16);
*pb++ = LED2B; g >>= 2;
*pb++ = LED2B; g >>= 2;
*pb++ = LED2B; g >>= 2;
*pb = LED2B;
g= (uint8_t)(color);
*pb++ = LED2B; g >>= 2;
*pb++ = LED2B; g >>= 2;
*pb++ = LED2B; g >>= 2;
*pb = LED2B;
} 本帖最后由 20061002838 于 2018-8-16 18:25 编辑
gmyu 发表于 2018-8-16 18:13
我上面说了,TX反转电平,加开始位可以看作9个bit,这样可以处理3个LED位,不用外接器件,不过没有试过。 ...
查表最快,没有之一
看错了,你这个就是查表 本帖最后由 gmyu 于 2018-8-16 18:43 编辑
20061002838 发表于 2018-8-16 18:20
查表最快,没有之一
看错了,你这个就是查表
请问,查表返回的一个32bit常量放到8位数组buffer里面,那种方法最快?谢谢! gmyu 发表于 2018-8-16 18:41
请问,查表返回的一个32bit常量放到8位数组buffer里面,那种方法最快?谢谢!...
指针,强制类型转换
void WS2812b_Display(void)
{
registerunsigned long i;
registerunsigned char temp = 0;
registerunsigned short const *pSrc;
registerunsigned short*pDrc;
register unsigned short b1, b2, b3;
pDrc = (unsigned short *)spi_SendBuf;
for (i = 0; i < 48; i++)//轮询像素缓存区
{
temp = ws2812b_PixBuf >> 4;
pSrc = (unsigned short const *)LUTbl;
b1 = *pSrc++;
b2 = *pSrc++;
b3 = *pSrc++;
*pDrc++ = b1;
*pDrc++ = b2;
*pDrc++ = b3;
temp = ws2812b_PixBuf & 0x0F;
pSrc = (unsigned short const *)LUTbl;
b1 = *pSrc++;
b2 = *pSrc++;
b3 = *pSrc++;
*pDrc++ = b1;
*pDrc++ = b2;
*pDrc++ = b3;
}
#if 0
DMA_Cmd(DMA1_Channel3, DISABLE);
DMA_ClearFlag(DMA1_FLAG_TC3);
DMA1_Channel3->CNDTR = SENDLENGTH;
DMA_Cmd(DMA1_Channel3, ENABLE);
#endif
} 20061002838 发表于 2018-8-16 18:47
指针,强制类型转换
对C++不熟悉,高手可以移植这个到stm32就好了,我在arduino下运行很炫,53种模式,可扩展性很强,如果用systick处理里面的step,延时也不消耗cpu资源了。 gmyu 发表于 2018-8-16 11:35
我用F030F4,只有4K RAM, 你这个远远超出,假定100个灯,100*2*24就4.8k了,而用SPI就只需要100*12=1.2k ...
100灯也就100*24就可以了,我用了5K多主要是我没省着用,还用了HSB颜色空间转换保存每一个灯的参数。 Eiman 发表于 2018-8-17 09:56
100灯也就100*24就可以了,我用了5K多主要是我没省着用,还用了HSB颜色空间转换保存每一个灯的参数。 ...
pwm dma data你用的是16位还是8位? gmyu 发表于 2018-8-17 10:36
pwm dma data你用的是16位还是8位?
是哦,一时没想起来。 stm32的io需要电平转换吗?ws2812是5V的,要3.5V才算高。我现在是把ws2812的vcc通过5V串1N4007后将为4.3V。你们是怎么做啊? 3.5才算高? 我直接连的。正常。 资料上写的是0.7倍的VCC才是高电平的啊吧? 学习中 谢谢 Eiman 发表于 2018-8-15 15:38
uart还是比较复杂的吧,有校验位停止位什么的,还是PWM+DMA最直接明了。
我用stc的PWM好像有点搞不定,好像30M情况下,37个周器,进中断再处理就超过了 weatt123456789 发表于 2018-10-30 03:53
我用stc的PWM好像有点搞不定,好像30M情况下,37个周器,进中断再处理就超过了 ...
所以用DMA处理就简单些 为什么不用PWM呢 楼主最后结果呢 UART没用,因为换207资源大大的有了。 gmyu 发表于 2018-11-3 19:15
UART没用,因为换207资源大大的有了。
莫名碰到WS2812该亮得时候不亮,不亮得时候瞎亮 gmyu 发表于 2018-11-3 19:15
UART没用,因为换207资源大大的有了。
不知道是不是0码和1码配置得问题。用的是SPI接口。 有没有人搞过w2812做成点阵显示酷炫特效的?
不知道能否实现,就是类似跳舞机那种 了解一下!! 20061002838 发表于 2018-8-16 18:47
指针,强制类型转换
STM32F103可以实现控制1024个灯珠? 你的SPI接哪呢?简易的电路图有吗?或者说明一下接法。 smilelinux 发表于 2019-4-24 23:54
你的SPI接哪呢?简易的电路图有吗?或者说明一下接法。
sdo到2812的data脚 mark一下,空了画个电路板试试 楼主,没看到你程序里面WS2812B的RESET信号怎么产生 花了一天在arm926上用UART dma实现了。每个UART发3个bits。24bits需要8个串口bytes。
下面是查表转颜色到UART数据。
UINT8 RGB2UART[] = {0xDB,0x9B,0xD3,0x93,0xDA,0x9A,0xD2,0x92};
void Send_24b_1LED(UINT8* Led_Arr, UINT32 u32color)
{UINT8 u8bit3,u8color;
for(UINT8 i = 0; i<8; i++){
u8color = (UINT8)(u32color >> (21-3*i));//先高后低G-R-B
u8bit3 = u8color & 0x7 ;
* (Led_Arr+i) = RGB2UART;
}
}
这个内存有64M,所以再不用考虑内存了,开两个buff采用乒乓的形式去刷新。 改了一下,把乘法那个去掉了。
void Send_24b_1LED(UINT8* Led_Arr, UINT32 u32color)
{UINT8 u8bit3,u8shift;
u8shift = 21;
for(UINT8 i = 0; i<8; i++){
u8bit3 = ((UINT8)(u32color >> u8shift)) & 0x7;//
u8shift -= 3;
* (Led_Arr+i) = RGB2UART;
}
} https://github.com/lamik/WS2812B_STM32_HAL
https://blog.csdn.net/Tkwer/article/details/104740550
别人的移植 gmyu 发表于 2022-10-15 11:58
https://github.com/lamik/WS2812B_STM32_HAL
https://blog.csdn.net/Tkwer/article/details/104740550
别 ...
(引用自40楼)
看网上视频有用8s003做的很炫的,不知道咋搞出来的,我 感觉我的45MHz频率都吃力
页:
[1]