[单片机芯片] 一款51单片机SPI驱动WS2812的经验分享

[复制链接]
4323|8
 楼主| lilijin1995 发表于 2023-7-31 10:41 | 显示全部楼层 |阅读模式
本帖最后由 lilijin1995 于 2023-8-13 21:09 编辑

引言:       其实个人觉得本贴子也没啥创新的地方,只是做了一些移植工作,关于一些经验分享,如果无兴趣阅读,请直接跳过,勿网暴!

背景:
这次使用的是某品牌的51单片机,系统时钟频率12Mhz,SPI最高可以系统的2分频,得到6Mhz的SPI时钟频率;基本能满足WS2812的时序要求;
  1. void InitSPI(void)
  2. {
  3.         FCTR &= ~ SPIFTR;               
  4.         SPICFG |= 0x50;
  5.         SPICTL = 0x00;
  6.         // f SCK= SYSCLK / 2*( SPICKR +1 ) SPI ʱÖÓ 12M/2*(0+1)=6Mhz
  7.         SPISCR = 0;
  8.         SPI_EN();
  9. }
正文接下来我们看一个WS2812彩虹轮盘的实现代码:
  1. void ws281x_rainbowCycle(void) {

  2.    u16 i, j;

  3.   for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
  4.     for(i=0; i< PIXEL_NUM; i++) {
  5.       ws281x_setPixelColor(i,ws281x_wheel(((i * 256 / PIXEL_NUM) + j) & 255));                        
  6.     }
  7.      ws281x_show();                        
  8.      DelayMS(10);
  9.   }
  10. }
大家应该发现了,基本不变,还是同样的配方,同样的味道
  1. void ws281x_setPixelColor(u16 n ,u32 GRBcolor)

  2. {
  3.   u8 i;
  4.   if(n < PIXEL_NUM)
  5.   {
  6.     for(i = 0; i < 24; ++i)

  7.     {
  8.       pixelBuffer[n][i] = (((GRBcolor << i) & 0X800000) ? WS_HIGH : WS_LOW);
  9.     }
  10.   }
  11. }
另外的ws281x_wheel就是渐变算法的实现;
  1. unsigned long ws281x_color(u8 red, u8 green, u8 blue)
  2. {
  3.     return ((unsigned long)green << 16) | ((unsigned long)red << 8) | blue;
  4. }


  5. // Input a value 0 to 255 to get a color value.

  6. // The colours are a transition r - g - b - back to r.
  7. u32 ws281x_wheel(u8 wheelPos) {

  8.   wheelPos = 255 - wheelPos;

  9.   if(wheelPos < 85) {

  10.     return ws281x_color(255 - wheelPos * 3, 0, wheelPos * 3);

  11.   }

  12.   if(wheelPos < 170) {

  13.     wheelPos -= 85;

  14.     return ws281x_color(0, wheelPos * 3, 255 - wheelPos * 3);

  15.   }

  16.   wheelPos -= 170;

  17.   return ws281x_color(wheelPos * 3, 255 - wheelPos * 3, 0);

  18. }
这里需要注意以下,ws281x_color,这里面一定要强制转换先;一开始我是这样写的,如下:
  1. 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了,因为我的时序是这样设置的,如下:
  1. #define PIXEL_NUM 16
  2. #define WS_HIGH 0XF8
  3. #define WS_LOW  0XC0
  4. u8 xdata pixelBuffer[PIXEL_NUM][24] ;
正常的话,我应该是
#define WS_HIGH 0XF0
#define WS_LOW  0XC0

但我用逻辑分析仪抓到的高电平时间并不满足要求,所以这里设置成了0xF8;毕竟没有DMA,而我们的低电平时间更加不满足了;
大家可以看我的数据刷新代码:ws281x_show
  1. void ws281x_show(void)
  2. {
  3.         u8 n,i;
  4.         for(n = 0; n < PIXEL_NUM; n++)
  5.   {

  6.     for(i = 0; i < 24; ++i)

  7.     {
  8.                         SPIDAT = pixelBuffer[n][i];
  9.                         //SPIDAT=WS_LOW;
  10.             while (!SPIF);
  11.                         
  12.                                 SPIF = 0;        
  13.                 }                        
  14.   }                        

  15.                
  16. }
因为51单片机主频很低的,加上等待SPI发送完成,以及一次循环的完成时间,故而低电平时间肯定比预期长又长的,但是感觉WS2812就是只判定高电平时序而已;
结尾:




tpgf 发表于 2023-8-10 17:17 | 显示全部楼层
WS2812能接收的最快的时序是多少呢
八层楼 发表于 2023-8-10 17:26 | 显示全部楼层
现在我们所说的51单片机 是说内核是51的是吗
观海 发表于 2023-8-10 17:49 | 显示全部楼层
是不是使用了51内核的单片机性能普遍都比较低呢
guanjiaer 发表于 2023-8-10 18:06 | 显示全部楼层
这个是不是不需要程序进行实时的响应呢
heimaojingzhang 发表于 2023-8-10 18:18 | 显示全部楼层
51内核单片机的spi通讯方式的速度上限是多少呢
田舍郎 发表于 2023-8-10 23:08 来自手机 | 显示全部楼层
能移植成功就是好经验
keaibukelian 发表于 2023-8-11 09:12 | 显示全部楼层
在单片机的c语言中如何做到数据类型强制转换呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

56

主题

165

帖子

8

粉丝
快速回复 在线客服 返回列表 返回顶部