本文分享一下如何实现灯带 WS2812b/W2811的驱动代码
主控芯片:华大HC32F460
灯带驱动芯片:WS2812b/W2811
1.WS2812b/W2811芯片产品概述&引脚排序
![在这里插入图片描述](https://img-blog.csdnimg.cn/7c889ae7010c4b7ebe8c302b8cb943b9.png
时序波形&数据格式:
驱动方式:
1.发送reset信号;
2.将数据按24bit(8bit red,8bit green,8bit blue)每盏灯,依次发送,速度为800Kbps
主控芯片驱动WS2811/WS2812的接口有很多种,常见的有
1.普通IO
2.SPI
本文使用的是SPI方式,需要将SPI速度与WS2811/WS2812速度匹配(800Kbps
)
2.代码
#include <stdint.h>
#include <string.h>
#define zero 0b11000000
#define one 0b11111000
#define SPI_SCK_PORT (PortA)//grop1
#define SPI_SCK_PIN (Pin07)
#define SPI_SCK_FUNC (Func_Spi1_Sck)
/* SPI_NSS Port/Pin definition */
#define SPI_NSS_PORT (PortA)//grop1
#define SPI_NSS_PIN (Pin12)
#define SPI_NSS_FUNC (Func_Spi1_Nss0)
/* SPI_MOSI Port/Pin definition */
#define SPI_MOSI_PORT (PortA) //grop1
#define SPI_MOSI_PIN (Pin02)
#define SPI_MOSI_FUNC (Func_Spi1_Mosi)
/* SPI_MISO Port/Pin definition */
#define SPI_MISO_PORT (PortA)//grop1
#define SPI_MISO_PIN (Pin11)
#define SPI_MISO_FUNC (Func_Spi1_Miso)
typedef struct
{
uint8_t red;
uint8_t green;
uint8_t blue;
}ws2812b_color;
//传输一次WS2812灯带数据格式
typedef struct
{
uint8_t head[3]; //reset
uint8_t GRB[FRAME_BYTES];
uint8_t tail; //传输完后为低电平
} ws2812_stu;
ws2812_stu color_buff =
{
.head[0] = 0,
.head[1] = 0,
.head[2] = 0,
.tail = 0
};
void ws2812_spi1_Init(void)
{
stc_spi_init_t stcSpiInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcSpiInit);
/* Configuration peripheral clock */
PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_SPI1, Enable);
/* Configuration SPI pin */
PORT_SetFunc(SPI_SCK_PORT, SPI_SCK_PIN, SPI_SCK_FUNC, Disable);
PORT_SetFunc(SPI_NSS_PORT, SPI_NSS_PIN, SPI_NSS_FUNC, Disable);
PORT_SetFunc(SPI_MOSI_PORT, SPI_MOSI_PIN, SPI_MOSI_FUNC, Disable);
PORT_SetFunc(SPI_MISO_PORT, SPI_MISO_PIN, SPI_MISO_FUNC, Disable);
/* Configuration SPI structure */
stcSpiInit.enClkDiv = SpiClkDiv16; //16(16703IC对应是16分配,2811IC对应8分频)
stcSpiInit.enFrameNumber = SpiFrameNumber1;
stcSpiInit.enDataLength = SpiDataLengthBit8;
stcSpiInit.enFirstBitPosition = SpiFirstBitPositionMSB;
stcSpiInit.enSckPolarity = SpiSckIdleLevelLow;
stcSpiInit.enSckPhase = SpiSckOddSampleEvenChange;
stcSpiInit.enReadBufferObject = SpiReadReceiverBuffer;
stcSpiInit.enWorkMode = SpiWorkMode4Line;
stcSpiInit.enTransMode = SpiTransFullDuplex;
stcSpiInit.enCommAutoSuspendEn = Disable;
stcSpiInit.enModeFaultErrorDetectEn = Disable;
stcSpiInit.enParitySelfDetectEn = Disable;
stcSpiInit.enParityEn = Disable;
stcSpiInit.enParity = SpiParityEven;
stcSpiInit.enMasterSlaveMode = SpiModeMaster;
stcSpiInit.stcDelayConfig.enSsSetupDelayOption = SpiSsSetupDelayCustomValue;
stcSpiInit.stcDelayConfig.enSsSetupDelayTime = SpiSsSetupDelaySck1;
stcSpiInit.stcDelayConfig.enSsHoldDelayOption = SpiSsHoldDelayCustomValue;
stcSpiInit.stcDelayConfig.enSsHoldDelayTime = SpiSsHoldDelaySck1;
stcSpiInit.stcDelayConfig.enSsIntervalTimeOption = SpiSsIntervalCustomValue;
stcSpiInit.stcDelayConfig.enSsIntervalTime = SpiSsIntervalSck6PlusPck2;
stcSpiInit.stcSsConfig.enSsValidBit = SpiSsValidChannel0;
stcSpiInit.stcSsConfig.enSs0Polarity = SpiSsLowValid;
SPI_Init(M4_SPI1, &stcSpiInit);
}
void ws2812_spi_dma_config(void)
{
stc_dma_config_t stcDmaCfg;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcDmaCfg);
/* Configuration peripheral clock */
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_DMA1, Enable);
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);
/* Configure TX DMA */
stcDmaCfg.u16BlockSize = 1u;
stcDmaCfg.u16TransferCnt = FRAME_BYTES;
stcDmaCfg.u32SrcAddr = (uint32_t)color_buff.GRB;
stcDmaCfg.u32DesAddr = (uint32_t)(&M4_SPI1->DR);
stcDmaCfg.stcDmaChCfg.enSrcInc = AddressIncrease;
stcDmaCfg.stcDmaChCfg.enDesInc = AddressFix;
stcDmaCfg.stcDmaChCfg.enTrnWidth = Dma8Bit;
stcDmaCfg.stcDmaChCfg.enIntEn = Disable;
DMA_InitChannel(M4_DMA1, DmaCh1, &stcDmaCfg);
DMA_SetTriggerSrc(M4_DMA1, DmaCh1, EVT_SPI1_SPTI);
/* Enable DMA. */
DMA_Cmd(M4_DMA1, Enable);
}
void ws2812_spi_transmit_dma( ws2812b_color buffer[], uint16_t len) //提取spi发送
{
int transmit_len = 0;
for(i = 0; i < len; i++)
{
uint8_t j = 0;
//RED
for(int8_t k = 7; k >= 0; k--)
{
if(((uint8_t)(buffer[i].red) & (1 << k)) == 0)
color_buff.GRB[i * 24 + j] = zero;
else
color_buff.GRB[i * 24 + j] = one;
j++;
}
//BLUE
for(int8_t k = 7; k >= 0; k--)
{
if(((uint8_t)(buffer[i].blue) & (1 << k)) == 0)
color_buff.GRB[i * 24 + j] = zero;
else
color_buff.GRB[i * 24 + j] = one;
j++;
}
//GREEN
for(int8_t k = 7; k >= 0; k--)
{
if(((uint8_t)(buffer[i].green) & (1 << k)) == 0)
color_buff.GRB[i * 24 + j] = zero;
else
color_buff.GRB[i * 24 + j] = one;
j++;
}
}
transmit_len = len * 24 + 4;
DMA_SetSrcAddress(M4_DMA1, DmaCh1, (uint32_t)color_buff.GRB);
DMA_SetTransferCnt(M4_DMA1, DmaCh1, transmit_len);
DMA_ChannelCmd(M4_DMA1, DmaCh1, Enable);
SPI_Cmd(M4_SPI1, Enable);
while (Reset == DMA_GetIrqFlag(M4_DMA1, DmaCh1, TrnCpltIrq))
{
}
DMA_ClearIrqFlag(M4_DMA1, DmaCh1, TrnCpltIrq);
SPI_Cmd(M4_SPI1, Disable);
}