硬件连接
WS2812B是一款全彩LED控制IC,单总线控制,可以级联。
单个灯珠连接将DIN脚连接至某一个IO口并接上电源即可 多个灯珠串联将第一个灯珠的DOUT脚连接至下一个灯珠的DIN脚
驱动原理
1.时序图
如图,由高低电平持续的不同时间代表0或者1,用一段长时间拉低表示reset,下图为对应的不同时长。
2.数据传输方式
如图,MCU将串联的GRB码传输进第一个灯珠,每个灯接收的是24bit数据(GRB颜色值),D1灯在收到24bit数据后,会把数据保存,如果还收到数据,会通过DO脚传给D2。
重点:高低电平的时间一定要控制在规格书的要求范围内
驱动代码
代码部分参考_祥子@这位老哥的文章
WS2812.h
typedef struct color{
uint8_t R;
uint8_t G;
uint8_t B;
}Color_TypeDef;
#define LED_NUM 12
#define WS2812B_High() HAL_GPIO_WritePin(RGB_GPIO_Port,RGB_Pin,GPIO_PIN_SET);
#define WS2812B_Low() HAL_GPIO_WritePin(RGB_GPIO_Port,RGB_Pin,GPIO_PIN_RESET);
void delay_320ns(void);
void delay_1000ns(void);
void MY_delay_us(uint16_t num);
void WS2812B_Reset(void);
void WS2812B_WriteByte(uint8_t dat);
void WS2812B_WriteColor(Color_TypeDef *pColor);
void Copy_Color(Color_TypeDef *pDst,Color_TypeDef *pScr);
void WS2812B_Refresh(void);
void WS2812B_Fillcolor(uint16_t start,uint16_t end,Color_TypeDef *pColor);
void WS2812B_Move(uint8_t dir);
WS2812.c
1.先写出发送0码1码的函数,使用了__nop();函数,一个__nop()对应一个机器周期,具体时长需要测量
void delay_320ns(void)
{
uint8_t i;
for(i=0;i<5;i++)
{
__nop();
}
}
void delay_1000ns(void)
{
uint8_t i;
for(i=0;i<25;i++)
{
__nop();
}
}
void MY_delay_us(uint16_t num)
{
uint8_t i;
while(num)
{
for(i=0;i<25;i++)
{
__nop();
}
num--;
}
}
测量延时时长的方法&函数 在main函数中调用这个函数,然后开启debug,轮流测试两个函数延时时长,不断更改循环次数直到时长满足时序要求。
void WS2812B_Test2(void)
{
WS2812B_Hi();
delay_320ns();
WS2812B_Low();
}
debug测试方法 在测试函数前后加上断点放在while内,进入debug后看右下角 如果是t0就右击选择t2或者t1。 在测试函数前的断点停下时再右键把数值清零,到结束的断点停下时显示的值就是延时函数实际的时间
2.写数据发送函数
void WS2812B_Reset(void)
{
WS2812B_Low();
int i=60;
while(i--)
{
delay_1000ns();
}
}
void WS2812B_WriteByte(uint8_t dat)
{
uint8_t i;
for (i=0;i<8;i++)
{
if (dat & 0x80)
{
WS2812B_High();
delay_1000ns();
WS2812B_Low();
delay_320ns();
}
else
{
WS2812B_High();
delay_320ns();
WS2812B_Low();
delay_1000ns();
}
dat<<=1;
}
}
void WS2812B_WriteColor(Color_TypeDef *pColor)
{
WS2812B_WriteByte(pColor->G);
WS2812B_WriteByte(pColor->R);
WS2812B_WriteByte(pColor->B);
}
void WS2812B_Refresh(void)
{
uint8_t i;
for(i=0;i<LED_NUM;i++)
{
WS2812B_WriteColor(&WS2812B_Buf[i]);
}
}
3.灯珠颜色处理 (实现跑马灯/彩虹渐变)
void Copy_Color(Color_TypeDef *pDst,Color_TypeDef *pScr)
{
pDst->R = pScr->R;
pDst->G = pScr->G;
pDst->B = pScr->B;
}
void WS2812B_Fillcolor(uint16_t start,uint16_t end,Color_TypeDef *pColor)
{
if(start>end)
{
uint16_t temp;
temp=start;
start=end;
end=temp;
}
if (start>=LED_NUM)return;
if(end>=LED_NUM)end=LED_NUM-1;
while(start<=end)
{
Copy_Color(&WS2812B_Buf[start],pColor);
start++;
}
}
void WS2812B_Move(uint8_t dir)
{
Color_TypeDef temp;
uint8_t i;
if(dir)
{
Copy_Color(&temp,&WS2812B_Buf[LED_NUM-1]);
i = LED_NUM-1;
while(i)
{
Copy_Color(&WS2812B_Buf[i],&WS2812B_Buf[i-1]);
i--;
}
Copy_Color(&WS2812B_Buf[0],&temp);
}
else
{
Copy_Color(&temp,&WS2812B_Buf[0]);
i = 0;
while(i<(LED_NUM-1))
{
Copy_Color(&WS2812B_Buf[i],&WS2812B_Buf[i+1]);
i++;
}
Copy_Color(&WS2812B_Buf[LED_NUM-1],&temp);
}
}
main.c
定义
Color_TypeDef WS2812B_Buf[LED_NUM];
初始化
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
uint8_t i;
for(i=0;i<8;i++)
{
WS2812B_Buf[i].R=63-7*i;
WS2812B_Buf[i].G=7*i;
WS2812B_Buf[i].B=0;
HAL_Delay(1);
}
for(i=8;i<12;i++)
{
WS2812B_Buf[i].R=0;
WS2812B_Buf[i].G=127-7*i;
WS2812B_Buf[i].B=7*i-56;
HAL_Delay(1);
}
WS2812B_Refresh();
循环
while(1)
{
HAL_Delay(40);
WS2812B_Move(5);
WS2812B_Refresh();
}
效果展示
初始化完的灯效 (加上一块均光板或者喷过漆的亚克力板可以让光更均匀) (随便捡了一块废板喷的漆)
|