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配置:
在上一篇文章可以看到控制一个码的周期在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; extern tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT]; 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就可改变灯条的颜色。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!