对于ws2812的控制方法网络上有很多资料,但对于不同厂家生产的ws2812可能时序有些许差异。
本文主要是添加了DMA的功能,节省了CPU资源
ws2812.h
#ifndef __WS2811_H__
#define __WS2811_H__
#define CODE_1 0XFc // 1111 1100
#define CODE_0 0XC0 // 1100 0000
#define LED_Number 30 //灯珠数量
extern uint8_t LED_Arry[];//缓存数组
typedef struct
{
uint8_t R;
uint8_t G;
uint8_t B;
}Color;
void WS2811_Init(void);
void SPI_SendByte(uint8_t Data);
void WS2811_SendBit(uint8_t Bit);
void WS2811_SendByte(uint8_t byte);
void WS2811_Reset(void);
void WS2811_UpdateArry(uint8_t G,uint8_t R,uint8_t B);
void WS2811_SetArry(void);
void WS2811_Stay_Bright(uint8_t G,uint8_t R,uint8_t B);
void WS2811_lightening(uint8_t G,uint8_t R,uint8_t B);
void WS2811_RunningLED(uint8_t G,uint8_t R,uint8_t B);
void WS2811_Change_Bright(void);
#endif
ws2812初始化
#include "stm32f10x.h" // Device header
#include "WS2811.h"
#include "Delay.h"
uint8_t LED_Arry[(LED_Number)*3],j=0;
uint8_t LED_RGBArry[(LED_Number)*24];
uint16_t LED_DMA;
Color Change_Color;
void WS2811_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
SPI_InitTypeDef SPI_InitStruct;
SPI_InitStruct.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_8;
SPI_InitStruct.SPI_CPHA=SPI_CPHA_2Edge;
SPI_InitStruct.SPI_CPOL=SPI_CPOL_Low;
SPI_InitStruct.SPI_CRCPolynomial=7;
SPI_InitStruct.SPI_DataSize=SPI_DataSize_8b;
SPI_InitStruct.SPI_Direction=SPI_Direction_1Line_Tx;
SPI_InitStruct.SPI_FirstBit=SPI_FirstBit_MSB;
SPI_InitStruct.SPI_Mode=SPI_Mode_Master;
SPI_InitStruct.SPI_NSS=SPI_NSS_Soft;
SPI_Init(SPI1, &SPI_InitStruct);
SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);
SPI_Cmd(SPI1,ENABLE);
DMA_DeInit(DMA1_Channel3);
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_BufferSize=LED_Number*24;
DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;
DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)LED_RGBArry;
DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;
DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)&SPI1->DR;
DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_Priority=DMA_Priority_High;
DMA_Init(DMA1_Channel3, &DMA_InitStruct);
DMA_Cmd(DMA1_Channel3,DISABLE);
WS2811_Reset();
Change_Color.R=255;
Change_Color.B=0;
Change_Color.G=0;//用于“变色”函数
}
控制函数
/**
*@brief:WS2812复位
*@param:
*@retval:
*/
void WS2811_Reset(void)
{
SPI_SendByte(0x00);
Delay_us(80);
}
void SPI_SendByte(uint8_t Data)
{
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);
SPI_I2S_SendData(SPI1,Data);
}
/**
*@brief:WS2811发送0码或1码
*@param:0/1
*@retval:
*/
void WS2811_SendBit(uint8_t Bit)
{
switch(Bit)
{
case 0: LED_RGBArry[LED_DMA]=CODE_0;break;
default: LED_RGBArry[LED_DMA]=CODE_1;break;
}LED_DMA++;
if(LED_DMA==(LED_Number*24))LED_DMA=0;
}
/**
*@brief:WS2811发送一个字节
*@param:byte
*@retval:
*/
void WS2811_SendByte(uint8_t byte)
{
for(int i=7;i>=0;i--)
{
WS2811_SendBit(byte&(0x01<<i));
}
}
/**
*@brief:WS2811更新缓冲数组
*@param:R,G,B
*@retval:
*/
void WS2811_UpdateArry(uint8_t G,uint8_t R,uint8_t B)
{
for(uint8_t i=0;i<LED_Number;i++)
{
LED_Arry[3*i] =G;
LED_Arry[3*i+1]=R;
LED_Arry[3*i+2]=B;
}
}
/**
*@brief:发送缓冲数组
*@param:ÎÞ
*@retval:ÎÞ
*/
void WS2811_SetArry(void)
{
for(uint8_t i=0;i<(LED_Number*3);i++)
{
WS2811_SendByte(LED_Arry[i]);
}
DMA_Cmd(DMA1_Channel3,DISABLE);
DMA_ClearFlag(DMA1_FLAG_TC1);
DMA_SetCurrDataCounter(DMA1_Channel3,LED_Number*24);
DMA_Cmd(DMA1_Channel3,ENABLE);//while(DMA_GetFlagStatus(DMA1_FLAG_TC1)!=RESET);
}
功能函数
/**
*@brief:常亮
*@param:G,R,B
*@retval:
*/
void WS2811_Stay_Bright(uint8_t G,uint8_t R,uint8_t B)
{
WS2811_UpdateArry(G,R,B);
WS2811_Reset();
WS2811_SetArry();
}
/**
*@brief:跑马灯
*@param:G,R,B
*@retval:
*/
void WS2811_lightening(uint8_t G,uint8_t R,uint8_t B)
{
for(uint16_t i=0;i<LED_Number;i++)
{
if(i<=j)
{
LED_Arry[3*i] =G;
LED_Arry[3*i+1]=R;
LED_Arry[3*i+2]=B;
}
else
{
LED_Arry[3*i] =0;
LED_Arry[3*i+1]=0;
LED_Arry[3*i+2]=0;
}
}
WS2811_Reset();
WS2811_SetArry();
j++;
if(j==LED_Number)j=0;
}
/**
*@brief:流水灯
*@param:G,R,B
*@retval:
*/
void WS2811_RunningLED(uint8_t G,uint8_t R,uint8_t B)
{
for(uint16_t i=0;i<LED_Number;i++)
{
if(i==j)
{
LED_Arry[3*i] =G;
LED_Arry[3*i+1]=R;
LED_Arry[3*i+2]=B;
}
else
{
LED_Arry[3*i] =0;
LED_Arry[3*i+1]=0;
LED_Arry[3*i+2]=0;
}
}
WS2811_Reset();
WS2811_SetArry();
j++;
if(j==LED_Number)j=0;
}
/**
*@brief:变换色彩
*@param:G,R,B
*@retval:
*/
void WS2811_Change_Bright(void)
{
if(Change_Color.R==255&&Change_Color.B<255&&Change_Color.G==0)
Change_Color.B++;
if(Change_Color.B==255&&Change_Color.R>0)
Change_Color.R--;
if(Change_Color.B==255&&Change_Color.R==0)
Change_Color.G++;
if(Change_Color.G==255&&Change_Color.B>0)
Change_Color.B--;
if(Change_Color.G==255&&Change_Color.R<255&&Change_Color.B==0)
Change_Color.R++;
if(Change_Color.R==255&&Change_Color.G>0)
Change_Color.G--;
WS2811_UpdateArry(Change_Color.G,Change_Color.R,Change_Color.B);
WS2811_Reset();
WS2811_SetArry();
}
欢迎批评改正,其余未尽代码可联系博主获取