| 
				打卡等级:初来乍到打卡总天数: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楼主威武~
 |