【SPI操纵WS2812】基于擎天柱的RGB驱动方案,纯走硬件,杜绝软件延时卡顿占用空间
/****************************************************************本次实验的SPI分组为P14P15P16P17
SSMOSI MISOSCK
请将RGB的DIN引脚接到AI8051U的P15引脚进行实验
重头戏在时钟配置函数(Sys.c中)将SPI转到高速SPI达到了刚好的3.2MHZ,
因为高速SPI(HSPI)通过PLL锁相环时钟,输出96MHZ给高速IO时钟,然后高速
SPI的时钟源是高速IO时钟,然后经过15分频后,在SPI配置中又进行了2分频,
所以最后的SPI工作频率是15分频和2分频叠加成了30MHZ,然后就有了SPI时钟
频率为:96/15/2=3.2MHZ,这个是非常合适的时钟频率,接下来就是考虑RGB的
1个时序该多久了,WS2812的时序是800K码率,也就是1个时序需要1250ns的时
间,那么0码是1/4的高电平和3/4的低电平;1码是3/4高电平和1/4低电平.那么
就是总共是1250ns,1/4时长是312.5ns,3/4时长是937.5ns,那我是不是SPI写
1个位就是(1000000/3.2MHZ)=312.5ns,刚好是1/4的占空比,那么我SPI写3个
位就是937.5ns了,通过这个原理,我们就可以通过SPI写4个位来实现0码/1码,
那么SPI一次性写8个位(1个字节)就是可以写2个0码/1码了
那么我们将G、R、B分别提取出来,8位的数据我们1次SPI的操作就可以判断2
位该写0还是写1,这样子1次SPI操作就可以写掉2位的RGB值了,1个颜色用4次
SPI操作来写,那么SPI的字节数总共就是4*3=12了
至于高速SPI,需要将SPI的输出口(MOSI和SCK)引脚设置为高速模式,在本次实
验中,需要将P14 P15 P17加内部上拉电阻,P16加内部下拉电阻,并且设置P15
和P17为推挽输出,P16为高阻输入+下拉电阻,这样MOSI输出完成后才会是低
电平
至此,龙场悟道!!!!
****************************************************************/
#include <AI8051U.H>
#include <intrins.h>
#include <absacc.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#define FOSC 40000000UL //主时钟
unsigned char Poi;
//void delay_ms(unsigned char ms)
//{
// unsigned int i;
// do
// {
// i=FOSC/6000;
// while(--i); //6T per loop
// }
// while(--ms);
//}
void SPI_T(unsigned char x)
{
unsigned char temp;
temp=(SBUF<<(x*2))&0xC0;
SPDAT=((temp&0x80)?0xE0:0x80)|((temp&0x40)?0x0E:0x08);
}
void Init(void)
{
WTST=0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR=1; //扩展寄存器(XFR)访问打开
CKCON=0; //提高访问XRAM速度
IAP_TPS=40;
IRCDB=128;
P0M1=0x00; P0M0=0x00; //设置为准双向口
P1M1=0x00; P1M0=0x00; //设置为准双向口
P2M1=0x00; P2M0=0x00; //设置为准双向口
P3M1=0x00; P3M0=0x00; //设置为准双向口
P4M1=0x00; P4M0=0x00; //设置为准双向口
P5M1=0x00; P5M0=0x00; //设置为准双向口
P6M1=0x00; P6M0=0x00; //设置为准双向口
P7M1=0x00; P7M0=0x00; //设置为准双向口
S1_S1=0; //UART1_2
S1_S0=1; //UART1_2
S1BRT=0; //选择TMR1作为UART1波特率发生器
T1x12=1; //设置TMR1为1T模式
TH1=0xFF; //设置UART1波特率(250Kbps@40MHz)
TL1=0xD8; //设置UART1波特率(250Kbps@40MHz)
SMOD0=1; //打开帧错误检测
SM1=1; //设置UART1模式为9位数据可变波特率
REN=1; //允许UART1接收数据
TR1=1; //打开定时器1
ES=1; //打开UART1中断
SPI_S1=1; //SPI_3
SPI_S0=0; //SPI_3
SPI_CLKDIV=3; //SPI时钟3分频
SPR1=1; //SPI输入时钟/2
SPR0=1; //SPI输入时钟/2
SSIG=1; //忽略SS引脚功能,使用MSTR确定器件是主机还是从机
DORD=0; //先发送/接收数据的高位(MSB)
MSTR=1; //设置主机模式
CPOL=0; //SCLK空闲时为低电平,SCLK的前时钟沿为上升沿,后时钟沿为下降沿
CPHA=1; //数据在SCLK的前时钟沿驱动,后时钟沿采样
SPSTAT=0xC0; //清除SPI中断标志、清除SPI写冲突标志
SPEN=1; //打开SPI功能
ESPI=1; //打开SPI中断
EA=1;
}
void main(void)
{
Init();
while(1)
{
}
}
void UART1_Isr(void) interrupt UART1_VECTOR
{
bit sync;
if(RI)
{
RI=0;
if(SM0)
{
SM0=0;
sync=1;
}
else
{
if(sync)
{
sync=0;
}
else
{
Poi=0;
SPI_T(Poi);
}
}
}
if(TI)
{
TI=0;
}
}
void SPI_Isr(void) interrupt SPI_VECTOR
{
SPSTAT|=0x80;
if(Poi<3)
{
SPI_T(++Poi);
}
}
DebugLab 发表于 2025-1-13 10:05
我直接用40M分频
40/12=3.3333333 DebugLab 发表于 2025-1-13 08:07
我直接用40M分频
40/12=3.3333333
欧欧欧大佬还是牛,我不确定是不是SPI_CLKDIV可以控制普通SPI,因为那里写的是高速SPI分频,所以我还得启用高速SPI DebugLab 发表于 2025-1-13 08:07
我直接用40M分频
40/12=3.3333333
就是这玩意吧挺严格的,分频不好分,要不就是直接,48/15=3.2MHZ DebugLab 发表于 2025-1-13 08:07
我直接用40M分频
40/12=3.3333333
但是主频无法跟STC32F比,那个主频比较低,这个分频也是不好分,STC单片机也没有倍频器,所以很难搞 陈家乐 发表于 2025-1-13 13:51
就是这玩意吧挺严格的,分频不好分,要不就是直接,48/15=3.2MHZ
8051U跑不了48M 陈家乐 发表于 2025-1-13 13:50
欧欧欧大佬还是牛,我不确定是不是SPI_CLKDIV可以控制普通SPI,因为那里写的是高速SPI分频,所以我还得启 ...
DebugLab 发表于 2025-1-13 12:13
8051U跑不了48M
最高42MHZ,有时候限制了发挥,还是得高主频才不用掉头发 DebugLab 发表于 2025-1-13 12:15
以前的SPI我拿来就用,现在折腾了这个时钟,理解更深刻了
页:
[1]
2