打印
[单片机芯片]

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

[复制链接]
1127|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lilijin1995|  楼主 | 2023-7-31 10:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 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就是只判定高电平时序而已;
结尾:




使用特权

评论回复
沙发
tpgf| | 2023-8-10 17:17 | 只看该作者
WS2812能接收的最快的时序是多少呢

使用特权

评论回复
板凳
八层楼| | 2023-8-10 17:26 | 只看该作者
现在我们所说的51单片机 是说内核是51的是吗

使用特权

评论回复
地板
观海| | 2023-8-10 17:49 | 只看该作者
是不是使用了51内核的单片机性能普遍都比较低呢

使用特权

评论回复
5
guanjiaer| | 2023-8-10 18:06 | 只看该作者
这个是不是不需要程序进行实时的响应呢

使用特权

评论回复
6
heimaojingzhang| | 2023-8-10 18:18 | 只看该作者
51内核单片机的spi通讯方式的速度上限是多少呢

使用特权

评论回复
7
田舍郎| | 2023-8-10 23:08 | 只看该作者
能移植成功就是好经验

使用特权

评论回复
8
keaibukelian| | 2023-8-11 09:12 | 只看该作者
在单片机的c语言中如何做到数据类型强制转换呢

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

54

主题

162

帖子

4

粉丝