STM32HAL库+SPI+DMA驱动SW2812

1、CubeMx配置,时钟部分设置72M  硬件SPI配置为32分频,一个时钟脉冲0.444us,至于其他配置选项随意选 都无所谓 配置DMA传输

根据SW2812的通讯0:高0.4us+低0.85us 1:高0.8us+0.45us 还有150ns允许误差可以理解为:

高0.4us+数据0.4us+低0.45us

SW2812的1bit位对应SPI的3个时钟脉冲,高位在前

发0:数据设置为100 

发1:数据设置为110

这样通讯总线直接连接到SPI的MOSI引脚上就行了

对应复位脉冲有的数据手册写的大于50us 有的是大于80us 还有280us 的 我都晕了

实现方法也很简单就是在发送完数据后,SPI再连续发送 复位脉冲**us/0.444us的bit位0数据就行了,因为总线空闲状态为低电平,最一个刷新周期后SPI最后传输的数据位要为0

这样RGB的数据共24位需要缓冲区24bit*3=72bit=9byte  

SW2812_RGB_to_buff();这个函数就是将24位颜色按1bit对应3个数据bit写入DMA缓冲区,注意是高位优先传送但是DMA传输是配置的按字节,做好对应关系

下面列出其中的R数据对应关系

SW2812_RGB.RGB_R 7 6 5 4 3 2 1
19
20
0
SW2812_SPI_buff 1 * 0 1 * 0 1 * 0 1 * 0 1 * 0 1 * 0 1 * 0 1 * 0
SW2812_SPI_buff 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
初始化值 0X24 0X49 0X92

DMA配置循环传输 程序中只需要启动一次就行了 可以选择normal模式 手动启动传输

.h文件代码

#ifndef __SW2812_H
#define __SW2812_H

#include "main.h"
#define SW2812_NUM 16 //配置SW2812的个数
//配置复位脉冲时间长度=1秒/ 2.25Mbits/s * 80byte *8bit=284.44us 
//根据数据手册复位脉冲时间可以更改此数据实测最小15运行正常 看来复位脉冲最小是50us
#define RST_Byte 80 

//定义颜色RGB结构体
typedef struct
{
	uint8_t RGB_R;
	uint8_t RGB_G;
	uint8_t RGB_B;
}type_color;

void SW2812_Send_Start(void);//启动DMA传输

void SW2812_RGB_to_buff(void);//将RGB数据转换为DMA缓冲区1byte颜色对应3byte数据
void SW2812_Set_color(uint16_t number,uint8_t RGB_R,uint8_t  RGB_G,uint8_t RGB_B);//设置颜
void SW2812_Set_TypeDef(uint16_t number ,const type_color * color);//按结构体设置颜色
void SW2812_Display(uint8_t choice);//主函数调用 形参为模式选择

.C 文件代码

#include "main.h"
#include "SPI.h"
#include "RGB_Normal.h"
#include "sw2812.h"
uint8_t SW2812_RGB[SW2812_NUM*3];
uint8_t SW2812_SPI_buff[SW2812_NUM*3*3+RST_Byte];
void SW2812_Send_Start(void)
{
//空闲状态是低电平 
HAL_SPI_Transmit_DMA  ( &hspi1 ,SW2812_SPI_buff,  SW2812_NUM*3*3+RST_Byte);
}

void SW2812_RGB_to_buff(void)
{
	uint16_t i;
	for(i=0;i<SW2812_NUM*3;i++)
	{
		SW2812_SPI_buff[i*3]	=0x92;//默认SPI输出为0
		SW2812_SPI_buff[i*3+1]	=0x49;//默认SPI输出为0
		SW2812_SPI_buff[i*3+2]	=0x24;//默认SPI输出为0
        //接下来根据颜色值置位对应缓冲区对应位
		if(	SW2812_RGB[i]&&0x01==0x01)		//第0位
			SW2812_SPI_buff[i*3+2]|=0x02;
		if(	SW2812_RGB[i]&&0x02==0x02)		//第1位
			SW2812_SPI_buff[i*3+2]|=0x10;
		if(	SW2812_RGB[i]&&0x04==0x04)		//第2位
			{SW2812_SPI_buff[i*3+2]|=0x80;}
		if(	SW2812_RGB[i]&&0x08==0x08)		//第3位
			{SW2812_SPI_buff[i*3+1]|=0x04;}
		if(	SW2812_RGB[i]&&0x10==0x10)		//第4位
			{SW2812_SPI_buff[i*3+1]|=0x20;}
		if(	SW2812_RGB[i]&&0x20==0x20)		//第5位
			{SW2812_SPI_buff[i*3]|=0x01;}
		if(	SW2812_RGB[i]&&0x40==0x40)		//第6位
			{SW2812_SPI_buff[i*3]|=0x08;}	
		if(	SW2812_RGB[i]&&0x80==0x80)		//第7位
			{SW2812_SPI_buff[i*3]|=0x40;}			
	}
}
void SW2812_Set_color(uint16_t number,uint8_t RGB_R,uint8_t  RGB_G,uint8_t RGB_B)
{
	SW2812_RGB[number*3+0]=RGB_R;
	SW2812_RGB[number*3+1]=RGB_G;
	SW2812_RGB[number*3+2]=RGB_B;
}
void SW2812_Set_TypeDef(uint16_t number ,const type_color * color)
{
	SW2812_RGB[number*3+0]=color->RGB_R;
	SW2812_RGB[number*3+1]=color->RGB_G;
	SW2812_RGB[number*3+2]=color->RGB_B;
}
void SW2812_Display(uint8_t choice)
{
	switch(choice)
	{
		case 0:{
			uint8_t i;
			static uint8_t j;
			j++;
			for(i=0;i<16;i++)
			SW2812_Set_TypeDef(i,&RGB_normal[(i+j)%SW2812_NUM]);
		}break;
		case 1:{
			uint8_t i;
			static uint8_t j;
			j++;
			for(i=0;i<16;i++)
			SW2812_Set_TypeDef(i,&RGB_NO_light[(i+j)%SW2812_NUM]);
		}break;
	}
SW2812_RGB_to_buff();//更新到SPI——DMA的缓冲区
}

 RGB颜色定义结构体常亮.h文件

#ifndef __RGB_Normal_H
#define __RGB_Normal_H

#include "SW2812.h"
const type_color RGB_normal[]={
{255,0,0},				//0     red,
{255,255,0},      //1     yellow,
{0,255,0},        //2     green,
{0,255,255},      //3     cyan,
{0,0,255},        //4     blue,
{255,0,255},      //5     Brilliant_purple,
{128,0,0},        //6     maroon,
{128,128,0},      //7     olive,
{0,128,0},        //8     Dark_green,
{0,128,128},      //9     turquoise,
{0,0,128},        //10    Dark_blue,
{128,0,128},      //11    purple,
{255,255,255},    //12    white,
{192,192,192},    //13    silver,
{128,128,128},    //14    gray,
{000,128,255},    //16
{000,255,128},    //17
{128,000,255},    //18
{128,128,000},    //19
{0,0,0},          //15    black,
 };
const type_color RGB_NO_light[]={
{1,0,0}, 
{0,1,0}, 
{1,1,0}, 
{0,0,1}, 
{1,0,1}, 
{0,1,1},
{1,1,1}, 
{1,0,0}, 
{0,1,0}, 
{1,1,0}, 
{0,0,1}, 
{1,0,1}, 
{0,1,1},
{1,1,1},
{1,0,0}, 
{0,1,0}, 
{1,1,0}, 
{0,0,1}, 
};
#endif

最后一个效果图