STM32F103C8T6使用SPI接口驅動WS2812b燈條

曾經夢想少年 2021-09-19 09:40:57 阅读数:758

stm32f103c8t6 stm 使用 spi 接口

之前一篇文章寫了使用IO控制WS2812b操作原理,但是由於IO的輸出比較慢,所以現在改用了硬件SPI控制WS2812b燈條
把SPI的mosi線接到ws2812b的數據線,SPI的速率可達十幾Mbit/s,如此高的傳輸速率,我們可以使用一個(uint8_t)類型的數據代錶一個碼1或者碼0;
也就是說,本來控制一個燈珠的數據由3個Byte(24比特)變成了24Byte,每個bit轉換成一個Byte;
具體看時鐘如何配置的。
SPI配置:

在上一篇文章可以看到控制一個碼的周期在1.25us±300ns之間,現在把時鐘配成9Mbit/s,這個的話每個碼的周期大概就在889ns,和LED的周期略有誤差;
從規格書上可以看到碼1和碼0的占空比是大致分配一下1個byte的8個bit;
我這裏分配的是
碼1:0xF8;
碼0:0xE0;

可以根據自己的具體情况取修改碼0和碼1的分配,下面是驅動ws2812b的代碼:

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就可改變燈條的顏色。

版权声明:本文为[曾經夢想少年]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210919094056904O.html