查看:
9768
|
回复:
3
|
WS2812灯珠的使用说明
|
|
发表于2018-12-13 13:51:19
|
只看该作者
1#
电梯直达
前一段时间使用了WS2812灯珠,现在说明一下WS2812的使用方法以及驱动程序和遇到的问题以及解决方法 首先还是先看看数据手册 具体的也可以在某文库搜索在这里我附加一个我看的数据手册的链接:https://blog.csdn.net/tangxing1212/article/details/42964417,
我遇到的问题有1.时许不对,2.灯珠损坏, 1时许不对的原因是因为单片机的机械周期没有达到着灯珠驱动的要求时间,灯珠要求驱动时间做小的时间是0.4us,所以用到机械周期要达到ns的单片机,我用的是STC15f2k60s2,(下载程序的时候调频率22.1184MHZ,不是下载频率)它由两种模式:12T模式一个机械周期是1us,1T模式机械周期是1/12us刚好可以达到所要求的时间控制范围,如果使用89C系列的单片机此时晶振频率要达到24MHZ,这样的话才符合要求, 2.我当时用的灯珠有些问题,写好程序不能使用但是我的程序是可以用的,我之前有两条灯带(一分为二怕烧坏全部灯)但是灯就是不亮而且还不对颜色,使用万能表测量电压VCC和GND是否导通然后再测数据口的DX的电压,我的DX数据口没电压这就说明我的灯带的数据线DX可能断了于是我反向接入VCC和GND DX的引脚结果全部的灯亮了,说明我的灯带的开始的接口断了,我用排插引出来了IO口灯带的问题解决。 下面开始分析程序 #include <STC15F2K60S2.H> #include "intrins.h" sbit WS2812 = P1^7; //数据口 #define numLEDs 8 //灯的个数 unsigned char buf_R[numLEDs] = {0};//颜色缓存多少个灯 unsigned char buf_G[numLEDs] = {0}; unsigned char buf_B[numLEDs] = {0}; unsigned char i=0; void RGB_Set_Up(); //送0码 void RGB_Set_Down(); //送1码 void HAL_Delay(unsigned int t) //延时函数 { unsigned int x,y; for(x=114;x>0;x--) for(y=t;y>0;y--); } //复位延时 50us void Delay50us() //@22.1184MHz { unsigned char i, j; _nop_(); _nop_(); i = 2; j = 15; do { while (--j); } while (--i); } //1码,高电平850ns 低电平400ns 误差正负150ns 严格按照时许进行通信传输数据 void RGB_Set_Up() { WS2812 = 1; //经过逻辑分析仪调试的的延时请勿乱改 _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();_nop_(); WS2812 = 0; } //1码,高电平400ns 低电平850ns 误差正负150ns void RGB_Set_Down() { WS2812 = 1; //经过逻辑分析仪调试的的延时 _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); WS2812 = 0; } //发送24位数据 发送数据GRB,每个字节从高到低发送给数据 void Send_2811_24bits(unsigned char G8,unsigned char R8,unsigned char B8) { unsigned int n = 0; //发送G8位 for(n=0;n<8;n++) { G8<<=n; if(G8&0x80 == 0x80) { RGB_Set_Up(); } else { RGB_Set_Down(); } } //发送R8位 for(n=0;n<8;n++) { R8<<=n; if(R8&0x80 == 0x80) //判断数据是否发送高电平1反之为0共有八位数据 { RGB_Set_Up(); } else { RGB_Set_Down(); } } //发送B8位 for(n=0;n<8;n++) { B8<<=n; if(B8&0x80 == 0x80) { RGB_Set_Up(); } else { RGB_Set_Down(); } } } //复位码 void RGB_Rst() { WS2812 = 1; WS2812 = 0; //先拉高在拉低延时50us复位清除 Delay50us(); } //把24位数据GRB码转RGB存储每个灯的数据并且发送 void Set_Colour(unsigned char r,unsigned char g,unsigned char b) { unsigned char i; for(i=0;i<numLEDs;i++) //存储灯数据每个灯是8位字符0--255 { buf_R[i] = r; //缓冲存储 buf_G[i] = g; buf_B[i] = b; } for(i=0;i<numLEDs;i++) { Send_2811_24bits(buf_G[i],buf_R[i],buf_B[i]);//发送显示 } } //某一个点显示的颜色和点亮多个灯的原理是一样的 void SetPointColour(unsigned int num,unsigned char r,unsigned char g,unsigned char b) { unsigned char i; for(i=0;i<numLEDs;i++) { buf_R[num] = r;//缓冲 buf_G[num] = g; buf_B[num] = b; } for(i=0;i<numLEDs;i++) { Send_2811_24bits(buf_G[i],buf_R[i],buf_B[i]);//发送显示 } } //颜色交换24位不拆分发 当数据24位的时候此函数可以使用拆分数据24位变为3个8位字节的数据 两种数据发送的方法原理都是一样的 void SetPixelColor(unsigned char num,unsigned long c) { unsigned char i; for(i=0;i<numLEDs;i++) { buf_R[num] = (unsigned char)(c>>16); //解析一个24位数据 从高到地发送数据所以取数的时候也要注意 buf_G[num] = (unsigned char)(c>>8); //数据格式G0G1G2G3G4G5G6G7 R0R1R2R3R4R5R6R7 B0B1B2B3B4B5B6B7 buf_B[num] = (unsigned char)(c); // } for(i=0;i<numLEDs;i++) { Send_2811_24bits(buf_G[i],buf_R[i],buf_B[i]); //发送显示 } } //复位 清除所有的颜色 void PixelUpdate() { RGB_Rst(); } //颜色 合并颜色成为一个24位数据 unsigned long Color(unsigned char r, unsigned char g, unsigned char b) { return ((unsigned long)r << 16) | ((unsigned long)g << 8) | b; //8位数据组合成24位数据 } void main() { PixelUpdate(); while(1) { for(i=0; i<numLEDs;i++) { SetPixelColor(i,Color(255,0,255)); PixelUpdate(); } } } 就这样吧,感谢CSxx的某位博主的博客 链接https://blog.csdn.net/u014411165/article/details/78787709 |
|
发表于2018-12-13 13:52:29
|
只看该作者
2#
写的一般如有错误感谢指出修改
|
|
发表于2018-12-14 14:05:50
|
只看该作者
3#
机械周期——是机器周期,时许—时序 ,DX是数据传输的IO口,89C系列的单片机是STC89C5X系列的单片机
|
|
发表于2021-05-18 16:31:11
|
只看该作者
4#
做得太好了,讲解清晰明了,零基础的我能理解大部分,只有小部分还理不顺,多看几次就能理了,感谢UP主
|
|