通过SPI+DMA控制WS2812
一、STM32CubeMX配置
1、在Clion 中新建项目并,并给其项目命名,然后选中STM32CubeMX,最后点击Create
2、打开STM32CuMX搜索其对应的芯片型号
3、选择HSE使用外部晶振
4、打开SYS选择SW
5、打开Clock Configuration进行配置
6、给工程命名,(注使用Clion的朋友们,这个工程名一定要和最开始在Clion中创建的要一致,并且在Toolchain/IDE中选择STM32CubeIDE,最后要注意工程位置),而使用KEIL的朋友在Toolchain/IDE中选择MDK-ARM即可
7、在Code Generator勾上第一个,这样使得各个部分的初始化生成在对于的.c和.h文件,否则会将其初始化全部生成在main.c文件中
8、配置SPI,具体如图,频率选择看SPI频率选择
9、配置DMA,具体如图
10、最后点击GENERATE COOD
二、SPI频率选择
0码和1码
T0H | 0码,高电平时间 | 0.40us 加减150ns |
T1H | 1码,高电平时间 | 0.85us 加减150ns |
T0L | 0码,低电平时间 | 0.85us 加减150ns |
T1L | 1码,低电平时间 | 0.40us 加减150ns |
RES | 帧单位,低电平时间 | 50us以上 |
不管是 0 码 还是 1 码 ,其时间都约等于1.25u(0.40us.+0.85=1.25us),我们选择SPI发生8位,则1.25u / 8=0.15625us,即每一位等于0.15625us
频率=1/周期
频率=1/0.15625us=6.4M
即SPI频率设置为6.4M,
但是0.4us和0.85us都可以加减0.15us
故频率可以在1/[(1.25-0.3)/8]=8.4M,1/[(1.25+0.3)/8]=5.2M之间都可以,当然越接近6.4越好
因此我们在时钟树选择48MHz,得到SPI发送频率为6M,比较接近6.4M
三、程序设计
1、c文件代码如下
#include "ws2812.h"
#define LED_NUMS 56//灯的数量
#define CODE1 0xf0//1码
#define CODE0 0xc0//0码
uint8_t BLACK[3] = { 0,0,0};
uint8_t RED[3] = {30,0,0};
uint8_t GREEN[3] = {0,30,0};
uint8_t BLUE[3] = {0,0,30};
uint8_t LED_BUFFER[24*LED_NUMS + 10];
extern SPI_HandleTypeDef hspi1;
//单个LED颜色设置,即将单个灯的颜色转换成对应的0码和1码
void RGB_Set_Color(uint8_t ID,uint8_t color[3])
{
int i=0;
for (i = 0; i < 8; i++) { //green
LED_BUFFER[ID*24+i] = ((color[1] << i) & 0x80) ? CODE1 : CODE0;
}
for (i = 0; i < 8; i++) { //red
LED_BUFFER[ID*24+8+i] = ((color[0] << i) & 0x80) ? CODE1 : CODE0;
}
for (i = 0; i < 8; i++) { //blue
LED_BUFFER[ID*24+16+i] = ((color[2] << i) & 0x80) ? CODE1 : CODE0;
}
}
//SPI_DMA发送
void RGB_Reflash(uint8_t reflash_num)
{
HAL_SPI_Transmit_DMA(&hspi1, LED_BUFFER, 24*reflash_num);
}
//全部黑色,可用于初始化将其所有灯熄灭
void RGB_BLACK(uint8_t RGB_LEN)
{
for(int i=0;i<RGB_LEN;i++)
{
RGB_Set_Color(i,BLACK);
RGB_Reflash(RGB_LEN);
}
}
//全部红色
void RGB_RED(uint8_t RGB_LEN)
{
for(int i=0;i<RGB_LEN;i++)
{
RGB_Set_Color(i,RED);
RGB_Reflash(RGB_LEN);
}
}
//全部绿色
void RGB_GREEN(uint8_t RGB_LEN)
{
for(int i=0;i<RGB_LEN;i++)
{
RGB_Set_Color(i,GREEN);
RGB_Reflash(RGB_LEN);
}
}
//全部蓝色
void RGB_BLUE(uint8_t RGB_LEN)
{
for(int i=0;i<RGB_LEN;i++)
{
RGB_Set_Color(i,BLUE);
RGB_Reflash(RGB_LEN);
}
}
//渐变
void ws2812_1(uint16_t RGB_LEN,int speed,float light)
{
if(light==0)
light=1;
for(int j=0;j<12;j++)//A
{
uint8_t My_color[3]={32/light ,3*j/light , 0};
RGB_Set_Color(j,My_color);
}
for(int j=12;j<20;j++)//B
{
uint8_t My_color[3]={(32-4*(j-12))/light ,32/light , 0};
RGB_Set_Color(j,My_color);
}
for(int j=20;j<28;j++)//C
{
uint8_t My_color[3]={0 ,32/light , 4*(j-20)/light};
RGB_Set_Color(j,My_color);
}
for(int j=28;j<36;j++)//D
{
uint8_t My_color[3]={0 ,(32-4*(j-28))/light , 32/light};
RGB_Set_Color(j,My_color);
}
for(int j=36;j<46;j++)//E
{
uint8_t My_color[3]={3*(j-36)/light ,0 , 30/light};
RGB_Set_Color(j,My_color);
}
for(int j=46;j<56;j++)//F
{
uint8_t My_color[3]={30/light ,0 , 30-3*(j-46)/light};
RGB_Set_Color(j,My_color);
}
uint8_t My_color[3]={ 0 ,30/light , 0 };
RGB_Set_Color(LED_NUMS,My_color);
RGB_Reflash(RGB_LEN);
HAL_Delay (speed);
}
2、h文件代码如下
#ifndef __WS2812_H__
#define __WS2812_H__
#include "spi.h"
#ifdef __cplusplus
extern "C" {
#endif
//单个LED颜色设置,即将单个灯的颜色转换成对应的0码和1码
void RGB_Set_Color(uint8_t ID,uint8_t color[3]);
void RGB_Reflash(uint8_t reflash_num);//SPI_DMA发送
void RGB_BLACK(uint8_t RGB_LEN);//全部黑色,可用于初始化将其全部熄灭
void RGB_RED(uint8_t RGB_LEN); //全部红色
void RGB_GREEN(uint8_t RGB_LEN);//全部绿色
void RGB_BLUE(uint8_t RGB_LEN); //全部蓝色
//渐变light=[0.12,8] light通过比例来调节亮度
void ws2812_1(uint16_t RGB_LEN, int speed,float light);
3、在main中调用函数 ws2812_1(56,100,1);
即可,最终效果如图