STM32F103C8T6硬件SPI+DMA控制ws2812(库函数)

对于ws2812的控制方法网络上有很多资料,但对于不同厂家生产的ws2812可能时序有些许差异。

关于ws2812的控制思路请移步:

关于使用SPI控制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();
}

欢迎批评改正,其余未尽代码可联系博主获取 

 

STM32F103C8T6控制器通过HAL库或CubeMX生成的驱动程序可以控制WS2812B灯珠。WS2812B是一种串行通信的RGB LED灯条,通常每3个LED作为一个像素,通过数据线逐位发送颜色信息。 以下是使用HAL库的基本步骤: 1. 包含头文件:在C文件中包含`stm32f1xx_hal_led.h`和相关的驱动头文件,如`led_stm32f1xx.h`。 ```c #include "stm32f1xx_hal.h" #include "led_stm32f1xx.h" ``` 2. 初始化GPIO和SPI:如果WS2812B连接到SPI,需要初始化相应的GPIO和SPI外设。 ```c HAL_GPIO_Init(GPIOA, &Pin_InitStruct); HAL_SPI_Init(&hspi1); ``` 3. 配置WS2812B驱动:创建并配置WS2812B灯带结构体,设置像素数、LED密度等。 ```c led WS2812B Led = { .Instance = SPI1, .Pin = LED_PIN, .Speed = SPI_SPEED, .PixelNumber = NUM_PIXELS, }; ``` 4. 发送数据:使用`LedControl`函数发送RGB值给WS2812B。 ```c void SendData(uint8_t* data) { HAL_GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PIN, GPIO_PIN_RESET); HAL_Delay(DELAY_TIME); // 等待上一帧关闭 HAL_SPI_Transmit(&hspi1, data, LED_PIXEL_SIZE * NUM_PIXELS, HAL_MAX_DELAY); HAL_GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PIN, GPIO_PIN_SET); } ``` 5. 更新灯珠状态:在循环中更新想要显示的颜色数组,并调用`SendData`函数。 ```c for (uint8_t i = 0; i < NUM_PIXELS; i++) { // 计算并填充RGB值 uint8_t color[3] = { red, green, blue }; data[i * LED_PIXEL_SIZE] = color[0]; data[i * LED_PIXEL_SIZE + 1] = color[1]; data[i * LED_PIXEL_SIZE + 2] = color[2]; } SendData(data); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值