本帖最后由 lilijin1995 于 2023-8-13 21:09 编辑  
 
引言:       其实个人觉得本贴子也没啥创新的地方,只是做了一些移植工作,关于一些经验分享,如果无兴趣阅读,请直接跳过,勿网暴! 
 
背景: 
这次使用的是某品牌的51单片机,系统时钟频率12Mhz,SPI最高可以系统的2分频,得到6Mhz的SPI时钟频率;基本能满足WS2812的时序要求; 
- void InitSPI(void)
 
 - {
 
 -         FCTR &= ~ SPIFTR;                
 
 -         SPICFG |= 0x50;
 
 -         SPICTL = 0x00;
 
 -         // f SCK= SYSCLK / 2*( SPICKR +1 ) SPI ʱÖÓ 12M/2*(0+1)=6Mhz
 
 -         SPISCR = 0;
 
 -         SPI_EN();
 
 - }
 
  正文接下来我们看一个WS2812彩虹轮盘的实现代码: 
- void ws281x_rainbowCycle(void) {
 
  
-    u16 i, j;
 
  
-   for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
 
 -     for(i=0; i< PIXEL_NUM; i++) {
 
 -       ws281x_setPixelColor(i,ws281x_wheel(((i * 256 / PIXEL_NUM) + j) & 255));                        
 
 -     }
 
 -      ws281x_show();                        
 
 -      DelayMS(10);
 
 -   }
 
 - }
 
  大家应该发现了,基本不变,还是同样的配方,同样的味道 
- void ws281x_setPixelColor(u16 n ,u32 GRBcolor)
 
  
- {
 
 -   u8 i;
 
 -   if(n < PIXEL_NUM)
 
 -   {
 
 -     for(i = 0; i < 24; ++i)
 
  
-     {
 
 -       pixelBuffer[n][i] = (((GRBcolor << i) & 0X800000) ? WS_HIGH : WS_LOW);
 
 -     }
 
 -   }
 
 - }
 
  另外的ws281x_wheel就是渐变算法的实现; 
- unsigned long ws281x_color(u8 red, u8 green, u8 blue)
 
 - {
 
 -     return ((unsigned long)green << 16) | ((unsigned long)red << 8) | blue;
 
 - }
 
  
 
- // Input a value 0 to 255 to get a color value.
 
  
- // The colours are a transition r - g - b - back to r.
 
 - u32 ws281x_wheel(u8 wheelPos) {
 
  
-   wheelPos = 255 - wheelPos;
 
  
-   if(wheelPos < 85) {
 
  
-     return ws281x_color(255 - wheelPos * 3, 0, wheelPos * 3);
 
  
-   }
 
  
-   if(wheelPos < 170) {
 
  
-     wheelPos -= 85;
 
  
-     return ws281x_color(0, wheelPos * 3, 255 - wheelPos * 3);
 
  
-   }
 
  
-   wheelPos -= 170;
 
  
-   return ws281x_color(wheelPos * 3, 255 - wheelPos * 3, 0);
 
  
- }
 
  这里需要注意以下,ws281x_color,这里面一定要强制转换先;一开始我是这样写的,如下: 
- uint32_t WS281x_Color(uint8_t red, uint8_t green, uint8_t blue) { return green << 16 | red<< 8 | blue; }
 
 
  但是C51里面不行,这样的效果是只有红蓝色,丢失了绿色; 
在这里我直接chatGPT,直接问了C51怎么实现uint32_t WS281x_Color(uint8_t red, uint8_t green, uint8_t blue) { return green << 16 | red<< 8 | blue; }这个代码,最后采得到 
((unsigned long)green << 16) | ((unsigned long)red << 8) | blue; 
下载验证与预期效果一致; 
在这里还需要注意一些时序问题,其实WS2812只要高电平的时序满足了,基本可以实现驱动点亮RGB了,因为我的时序是这样设置的,如下: 
- #define PIXEL_NUM 16
 
 - #define WS_HIGH 0XF8
 
 - #define WS_LOW  0XC0
 
 - u8 xdata pixelBuffer[PIXEL_NUM][24] ;
 
  正常的话,我应该是 
#define WS_HIGH 0XF0 
#define WS_LOW  0XC0 
 
但我用逻辑分析仪抓到的高电平时间并不满足要求,所以这里设置成了0xF8;毕竟没有DMA,而我们的低电平时间更加不满足了; 
大家可以看我的数据刷新代码:ws281x_show 
- void ws281x_show(void)
 
 - {
 
 -         u8 n,i;
 
 -         for(n = 0; n < PIXEL_NUM; n++)
 
 -   {
 
  
-     for(i = 0; i < 24; ++i)
 
  
-     {
 
 -                         SPIDAT = pixelBuffer[n][i]; 
 
 -                         //SPIDAT=WS_LOW;
 
 -             while (!SPIF);
 
 -                         
 
 -                                 SPIF = 0;        
 
 -                 }                        
 
 -   }                        
 
  
-                 
 
 - }
 
  因为51单片机主频很低的,加上等待SPI发送完成,以及一次循环的完成时间,故而低电平时间肯定比预期长又长的,但是感觉WS2812就是只判定高电平时序而已; 
结尾: 
 
 
 
 
 
 
 
 
 
 
  |