晓飛飛 发表于 2026-1-16 16:20:56

点个幻彩灯 何必单恋WS2812可以看看APA102@2线制,标准SPI

说到幻彩灯,大家似乎只有WS2812一种选择,其实不然
今天说说APA102,兼容型号为SK9822,一款同步二线驱动的幻彩LED,
先说它的缺点:

[*]比WS2812多占一条口线
[*]成本略高

再说它的优点:

[*]双线同步传输,非异步操作,不挑单片机IO速度,代码不必严格时序,不必担心中断影响时序,稳如老狗,完全没有单总线的硬伤
[*]CLK时钟速度高达20MHz,远超WS2812的800kHz,刷新速率30帧/秒时,级联数超过25600,远超WS2812的1024点
[*]原生支持硬件SPI和SPI DMA,,单个LED对应32bit数据,正好4字节,单片机资源占用超小,速度快到飞起
[*]5位全局亮度,高频PWM调光,物理不闪,WS2812只能缩放RGB调光
[*]支持增加缓冲门用作远传中继,


测试电路如下:

1012

晓飛飛 发表于 2026-1-16 16:29:41

#include "def.h"
#include <intrins.h>
#include "AI8G.h"

#define SCL_H P54 = 1//APA102C的时钟输入SCK
#define SCL_L P54 = 0
#define DIN_H P55 = 1//APA102C的串口数据输入DI
#define DIN_L P55 = 0

#define NUM_LEDS 1                //灯串的规模
#define BRIGHTNESS 10//0~31

struct CRGB {
      u8 r,g,b;
};

bit flag;

struct CRGB leds;//显存

void APA_send(u8 dat)//IO模拟方式
{
      u8 i;
      for(i=0;i<8;i++){
                if(dat & 0x80)DIN_H;
                else               DIN_L;
                //NOP1();      //实测主频35MHz时都不需要NOP,
                SCL_H;
                //NOP1();          //实测主频35MHz时都不需要NOP,
                SCL_L;
                dat <<= 1;
      }
}


void APA_send(u8 dat)//硬件SPI方式
{
      SPDAT = dat;                           //发送测试数据
      while (!(SPSTAT & 0x80));               //查询完成标志
      SPSTAT = 0xc0;                        //清中断标志
}

void set_color(u16 index,u8 r,u8 g,u8 b){                //设置灯串中第index个灯的颜色
      if(index >= 0 && index <NUM_LEDS){
                leds.r = r;
                leds.g = g;
                leds.b = b;
      }
}

void show_led(void){
      u8 i,ctrl;
      for(i=0;i<4;i++)APA_send(0x00);//发送32bit前导 否则首灯不亮
      for(i=0;i<NUM_LEDS;i++){
                ctrl = 0xE0 | (BRIGHTNESS & 0x1F);
                APA_send(ctrl);                        //填充亮度
                APA_send(leds.b);      //填充蓝色
                APA_send(leds.g);      //填充绿色
                APA_send(leds.r);      //填充红色
      }
      APA_send(0xFF);                //填充结束帧
      APA_send(0xFF);                //填充结束帧
}


void Timer0_Isr(void) interrupt 1
{
      static u8 i,j;
      switch (i)
      {
                case 0:
                        set_color(0,j,0,0);//红色渐变
                        if(j++ > 250)      {j = 0;      i++;}
                        break;
                case 1:
                        set_color(0,0,j,0);//绿色渐变
                        if(j++ > 250)      {j = 0;      i++;}
                        break;                        
                case 2:
                        set_color(0,0,0,j);//蓝色渐变
                        if(j++ > 250)      {j = 0;      i++;}
                        break;
                case 3:
                        set_color(0,j,j,0);//黄色渐变
                        if(j++ > 250)      {j = 0;      i++;}
                        break;
                case 4:
                        set_color(0,0,j,j);//靛色渐变
                        if(j++ > 250)      {j = 0;      i++;}
                        break;                        
                case 5:
                        set_color(0,j,0,j);//紫色渐变
                        if(j++ > 250)      {j = 0;      i++;}
                        break;
                case 6:
                        set_color(0,j,j,j);//白色渐变
                        if(j++ > 250)      {j = 0;      i = 0;}
                        break;
                default:
                        break;      
      }
      show_led();      //刷新显示
}

void Timer0_Init(void)                //10毫秒@12.000MHz
{
      AUXR &= 0x7F;                        //定时器时钟12T模式
      TMOD &= 0xF0;                        //设置定时器模式
      TL0 = 0xF0;                              //设置定时初始值
      TH0 = 0xD8;                              //设置定时初始值
      TF0 = 0;                              //清除TF0标志
      TR0 = 1;                              //定时器0开始计时
      ET0 = 1;                              //使能定时器0中断
}

void main()
{
    P_SW2 = 0x80;
    P3M0 = 0x00; P3M1 = 0x00;
    P5M0 = 0x30; P5M1 = 0x00; //CLK & DI PP_OUT
    SPCTL = 0x50;         //SPI Master CLK = SYS/4
    SPSTAT = 0xc0;          //Clear Flag
   Timer0_Init();   
   EA = 1;
   while(1);               
}


liuxingyu 发表于 2026-1-29 19:12:56

点赞
页: [1]
查看完整版本: 点个幻彩灯 何必单恋WS2812可以看看APA102@2线制,标准SPI