时序很简单,每一位或0或1,根据占空比来区分。
一个全彩的点 是3种颜色不同的占比来组成。 一种颜色用8位,一个字节来表示深浅,256个等级。
三种颜色,绿,红,蓝。 一共需要24位。
控制一个灯需要发送24位,控制N个灯 就发送24*N 位。
难点在于T0H,T1L 的时间是0.3US, 这个速度用低档单片机很难实现。
我也曾尝试用汇编来实现,在少量级联的情况还行,灯一多,控制就很不理想了。
其实我测试的灯也就150来个。在灯比较多的时候,时序稍一偏差 ,就会超出变化的范围内。
STM32的SPI 硬件来实现。 要用DMA SPI 数据。STM32 很奇怪 ,可能是我不习惯,在参考手册看功能。 在数据手册具体哪个芯片的对应的管脚,具体的外设。
SPI 2 用一线发送。因此 只需要MOSI 和 SCK 2根线 。SPI2 MOSI==PB15; SCK == PB13;要用到DMA; 查参考手册,需要DMA2. 遗憾 DMA2 只有在大容量和互联型的IC中。 STM32F103C8 没有DMA2.
只能用DMA1 的通道3 和 SPI1 了。 SPI1 MOSI == PA7; DMA在参考手册看,SPI1的TX 在DMA1的通道3 。
数据结构体如下:
typedef union _BYTE_VAL
{
BYTE Val;
BYTE byte;
struct
{
unsigned char b0:1;
unsigned char b1:1;
unsigned char b2:1;
unsigned char b3:1;
unsigned char b4:1;
unsigned char b5:1;
unsigned char b6:1;
unsigned char b7:1;
} bits;
} BYTE_VAL;
typedef union _RGB_VAL // 一个LED 的结构体
{
DWORD Val;
struct
{
BYTE blue; //xt1511;
BYTE red;
BYTE green;
BYTE c3; //no use
} byte;
} RGB_VAL;
#define LedCount 150 //150个灯珠。
RGB_VAL displayGRB_buf[ LedCount ]; // 所有灯珠的颜色 ,一个灯珠需要24位,最少3个字节。
unsigned char Ws2811DisBuf[LedCount *24]; // 所有灯珠颜色的每一位用一个字节,用做SPI发送数据。
/*!< Specifies the memory base address for DMAy Channelx. */
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Ws2811DisBuf;
//把要显示的颜色 全部转换成SPI 要发出的时序数据,放到Ws2811DisBuf中。
for (ii = 0; ii < LedCount;ii ++) //显示的数组
{
iiii.Val = displayGRB_buf[ii].Val ;
i = 0 ;
do //根据24位 的1/0 把 01111100 01110000 放入BUF中 。
{
Ws2811DisBuf[BufCount ++] = iiii.bits.b0 ? 0x7c:0x70;
iiii.Val = iiii.Val >> 1; //
i++;
}while(i < 24);
}
// SPI的发送 必须用DMA来完成。 如果用MCU来发送,Ws2811DisBuf 需要5MS 左右,严重影响AD的采集。
DMA_Cmd(DMA1_Channel3, DISABLE); //NO 使能DMA通道
DMA_ClearFlag (DMA1_FLAG_TC3);
SPI1_Send( Ws2811DisBuf, LedCountAll );
喔 这个程序也使用与WS2811的驱动。 WS2811 时序的最小间隔是0.5US, 比XT1511 慢点。
作者: esad0, 来源:面包板社区
链接: https://mbb.eet-china.com/blog/uid-me-1039027.html
版权声明:本文为博主原创,未经本人允许,禁止转载!
curton 2019-4-25 08:13