STM32F103C8T6使用SPI接口驱动WS2812b灯条

之前一篇文章写了使用IO控制WS2812b操作原理,但是由于IO的输出比较慢,所以现在改用了硬件SPI控制WS2812b灯条

把SPI的mosi线接到ws2812b的数据线,SPI的速率可达十几Mbit/s,如此高的传输速率,我们可以使用一个(uint8_t)类型的数据代表一个码1或者码0;

也就是说,本来控制一个灯珠的数据由3个Byte(24位)变成了24Byte,每个bit转换成一个Byte;

具体看时钟如何配置的。

SPI配置:

STM32F103C8T6使用SPI接口驱动WS2812b灯条

在上一篇文章可以看到控制一个码的周期在1.25us±300ns之间,现在把时钟配成9Mbit/s,这个的话每个码的周期大概就在889ns,和LED的周期略有误差;

从规格书上可以看到码1和码0的占空比是大致分配一下1个byte的8个bit;

我这里分配的是

码1:0xF8;

码0:0xE0;

STM32F103C8T6使用SPI接口驱动WS2812b灯条

可以根据自己的具体情况取修改码0和码1的分配

ws2812b.h[[]()]()

#ifndef __WS2812B_H__
#define __WS2812B_H__ #include <stdint.h> // 编码 0 : 11100000
#define CODE_0 0xE0
// 编码 1 : 11111000
#define CODE_1 0xF8
/*ws2812b灯珠数量*/
#define WS2812B_AMOUNT 8 typedef struct
{
uint8_t R;
uint8_t G;
uint8_t B;
} tWs2812bCache_TypeDef; void WS2812b_Set(uint16_t Ws2b812b_NUM, uint8_t r,uint8_t g,uint8_t b);
void WS2812B_Task(void); #endif

ws2812b.c

#include "ws2812b.h"
#include "spi.h" //灯条显存SPI数据缓存
uint8_t gWs2812bDat_SPI[WS2812B_AMOUNT * 24] = {0};
//灯条显存
tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT] = {
//R G B
0X0F, 0X0F, 0X0F, //0
0X0F, 0X0F, 0X0F, //1
0X0F, 0X0F, 0X0F, //2
0X0F, 0X0F, 0X0F, //3
0X0F, 0X0F, 0X0F, //4
0X0F, 0X0F, 0X0F, //5
0X0F, 0X0F, 0X0F, //6
0X0F, 0X0F, 0X0F, //7
}; void WS2812b_Set(uint16_t Ws2b812b_NUM, uint8_t r,uint8_t g,uint8_t b)
{
uint8_t *pR = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24 + 8];
uint8_t *pG = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24];
uint8_t *pB = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24 + 16]; for(uint8_t i = 0; i < 8; i++) {
if(g & 0x80) {
*pG = CODE_1;
}
else {
*pG = CODE_0;
}
if(r & 0x80) {
*pR = CODE_1;
}
else {
*pR = CODE_0;
}
if(b & 0x80) {
*pB = CODE_1;
}
else {
*pB = CODE_0;
}
r <<= 1;
g <<= 1;
b <<= 1;
pR++;
pG++;
pB++;
}
}
void WS2812B_Task(void)
{
uint8_t dat = 0; //将gWs2812bDat数据解析成SPI数据
for(uint8_t iLED = 0; iLED < WS2812B_AMOUNT; iLED++)
{
WS2812b_Set(iLED, gWs2812bDat[iLED].R, gWs2812bDat[iLED].G, gWs2812bDat[iLED].B);
}
//总线输出数据
HAL_SPI_Transmit(&hspi1, gWs2812bDat_SPI, sizeof(gWs2812bDat_SPI), 100);
//使总线输出低电平
HAL_SPI_Transmit(&hspi1, &dat, 1, 100);
//帧信号:一个大于50us的低电平
HAL_Delay(1);
}

直接在main()里面调用WS2812B_Task()就可以驱动灯条,另外直接修改数组gWs2812bDat就可改变灯条的颜色。

上一篇:geotrellis使用(十一)实现空间数据库栅格化以及根据属性字段进行赋值


下一篇:S3C6410裸奔之旅——RVDS2.2编译、仿真、调试过程 LED流水灯---转的