点个幻彩灯 何必单恋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
#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);
}
点赞
页:
[1]