- 打卡等级:初来乍到
- 打卡总天数:5
- 最近打卡:2024-08-17 16:41:35
中级会员
- 积分
- 270
|
DMA_SPI, STC8H/STC32G, 驱动WS2812B全彩LED的简单应用
一位新人的工作之余琢磨的,供大家参考
芯片:STC8H4K64TLCD
功能:利用 DMA_SPI 驱动WS2812B(5颗)
限制:10颗以内,主频固定28Mhz
优点:无需反向器
硬件:第一颗WS2812B, DI接MOIS脚,(我接的是P3.4),
MOSI 接10K下拉电阻。
程序:
/*******我也不知道为什么丢这么多头文件*************/
#include<STC8H.H>
#include<absacc.h>
#include<stdio.h>
#include<math.h>
#include <intrins.h>
#include <string.h>
/**********WS2812B数据,0XF0对应1,0X00对应0************************/
unsigned char xdata GRB[96]={ 0xF0,0xF0,0xF0,0xF0, 0xF0,0xF0,0xF0,0xF0, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, // 绿色 对应WS2812数据:1111 1111 0000 0000 0000 0000
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0xF0,0xF0,0xF0,0xF0, 0xF0,0xF0,0xF0,0xF0, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, // 红色 对应WS2812数据: 0000 0000 1111 1111 0000 0000
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0xF0,0xF0,0xF0,0xF0, 0xF0,0xF0,0xF0,0xF0, //蓝色 对应WS2812数据:0000 0000 0000 0000 1111 1111
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,}; //全灭 对应WS2812数据:0000 0000 0000 0000 0000 0000
unsigned char xdata LED_DATA[120]={0xF0,0xF0,0xF0,0xF0, 0xF0,0xF0,0xF0,0xF0, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //0-23对应第一颗24bit数据,初始绿色
0xF0,0xF0,0xF0,0xF0, 0xF0,0xF0,0xF0,0xF0, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //24-47对应第二颗24bit数据,初始绿色
0xF0,0xF0,0xF0,0xF0, 0xF0,0xF0,0xF0,0xF0, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //48-71 对应第三颗24bit数据,初始绿色
0xF0,0xF0,0xF0,0xF0, 0xF0,0xF0,0xF0,0xF0, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //72-95 对应第四颗24bit数据,初始绿色
0xF0,0xF0,0xF0,0xF0, 0xF0,0xF0,0xF0,0xF0, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,}; //96-120 对应第五颗24bit数据,初始绿色
int xdata Di=0; //定义LED_DATA数据位,0 第一颗LED数据第一位,24第二颗数据第一位,依次按24倍数
int xdata Yrgb=0; //定义GRB数据位,0 绿色数据第一位 ,24红色数据第一位,48蓝色数据第一位,72关闭LED数据第一位
int xdata ENSPI=0; //DMA_SPI中断标志位
/**********延时 80us用于WS2812B置零,实际运用中可考虑其他方式 1000MS方便观察现象************/
void Delay80us() //@28MHz
{
unsigned char i, j;
_nop_();
i = 3;
j = 230;
do
{
while (--j);
} while (--i);
}
void Delay1000ms() //@28MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 143;
j = 12;
k = 64;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
/******SW2812B数据*****************/
void LEDRGB(Di,Yrgb)
{
memmove(LED_DATA+Di,GRB+Yrgb,24); //从GRB第Yrgb+1位复制到LED_DATA的Di+1位,一共复制24个字符
}
/**********DMA_SPI**************************/
void SPI()
{
ENSPI=DMA_SPI_CR; //读DMA_SPI控制寄存器
ENSPI&=0xC0; //取第7.6位
if(ENSPI==0) //0,说明DMA_SPI未使用,
{
P34=0; //MOSI低电平
Delay80us(); //延时WS2812B置零,开始接收数据,
DMA_SPI_AMT=119; //传输120字节。24*5=120字节
DMA_SPI_TXA=LED_DATA; //数据起始位。
SPCTL=0xD3; //1101 0011 6.使能SPI 5主机模式,4空闲时钟线低电平,3前沿写 2后沿读 1:0主时钟2分频 14Mhz”
DMA_SPI_CR=0xC0; //11000000 开始DMA_SPI
}
}
//DM_SPI中断
void DMA_SPI_Routine(void) interrupt 49
{
SPCTL=0x00;
P34=0; //WS2812B数据空闲低电平
DMA_SPI_CR=0x00; //关闭DMA_SPI
DMA_SPI_STA=0x00; //中断标志位清零
}
void main()
{
CLKSEL=0; //内部高速时钟 下载设置25.6MHZ
EA=1; //打开总中断
//------------------I/O设置,MOIS设置为推挽输出,设置为准双向口时,实测高电平为一斜线----------
P0M0 = 0x00; P0M1 = 0x00;
P1M0 = 0x00; P1M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x7f;
P3M0 = 0x10; P3M1 = 0x00;
P34=0;
P4M0 = 0x00; P4M1 = 0x00;
P5M0 = 0x00; P5M1 = 0x00;
//---------------------SPI设置-----------------------------------------
P_SW2|=128; //1000 0000 允许访问片内SFR 0FA00H~0FFFFH FB50-FB6F 触摸阈值寄存器
P_SW1=12; //00-- **0- MOSI输出设置P3.4 **=11
AUXR=0; //允许访问内部扩展RAM
DMA_SPI_CFG2=4; //00000100 不使用SS脚 SS脚P1.2”
DMA_SPI_CFG=0xCF; //1100 1111,允许DMA_SPI中断,允许发送禁止接收数据,中断优先最高 访问级最大
while(1)
{
//-----------全部显示绿色-----------
Delay1000ms();
LEDRGB(0,0); //从GRB第1个字符开始,依次复制24个字符复制到LED_DATA的第1-24字符,第一颗LED数据
LEDRGB(24,0); //从GRB第1个字符开始,依次复制24个字符复制到LED_DATA的第25-48字符,第二颗LED数据
LEDRGB(48,0); //从GRB第1个字符开始,依次复制24个字符复制到LED_DATA的第49-72字符,第三颗LED数据
LEDRGB(72,0); //从GRB第1个字符开始,依次复制24个字符复制到LED_DATA的第73-96字符,第三颗LED数据
LEDRGB(96,0); //从GRB第1个字符开始,依次复制24个字符复制到LED_DATA的第97-120字符,第三颗LED数据
SPI();
//-----------全部显示红色-----------
Delay1000ms();
LEDRGB(0,24);
LEDRGB(24,24);
LEDRGB(48,24);
LEDRGB(72,24);
LEDRGB(96,24);
SPI();
//-----------全部显示蓝色-----------
Delay1000ms();
LEDRGB(0,48);
LEDRGB(24,48);
LEDRGB(48,48);
LEDRGB(72,48);
LEDRGB(96,48);
SPI();
//-----------全部关闭-----------
Delay1000ms();
LEDRGB(0,72);
LEDRGB(24,72);
LEDRGB(48,72);
LEDRGB(72,72);
LEDRGB(96,72);
SPI();
}
}
思路:
DMA_SPI在进行数据传输时,2个字符直接有间隙,间隙期间MOSI为高电平,
而WS2812B判断1与0是依据高电平时间,间隙时长与主频有关,40Mhz时候,
间隙时长约280nS,28Mhz间隙时长约400nS.
如果增加反相器,可以无需考虑这段时长,因为我的PCB已经成型不方便增加反相器,
所以利用2个字符的间隙高电平时间,让WS2812B判断为0,通过字符高位设1延长
高电平时间让WS2812B判断为1。
最后,强烈建议使用DMA_SPI驱动WS2812B时候,MOSI脚增加反相器。
小白一枚,如果有什么错误,欢迎指出,谢谢
DMA_SPI 字符 间隙
主频28MHz MOSI 波形
|
1
喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
-
+2
楼主威武~
|