Bootstrap

STM32+PWM+DMA驱动WS2812彩灯模块(附源码)

STM32+PWM+DMA驱动WS2812彩灯模块

WS2812模块介绍

WS2812是一颗数字LED灯珠,采用单总线通讯,每颗灯珠支持24bit的颜色控制,也即RGB888,信号线通过DIN输入,经过一颗灯珠之后,信号线上前24bit数据会被该灯珠锁存,之后将剩下的数据信号整形之后通过DOUT输出
引脚功能图

经典电路

电路图
C1为VDD的滤波电容,一般大小为100NF。

实物展示

在这里插入图片描述

点亮灯光

// An highlighted block
void controlMultipleLEDs() {
    // 控制LED 0
    colors[0][0] = 255; // 设置为红色
    colors[0][1] = 0;
    colors[0][2] = 0;

    // 控制LED 1
    colors[1][0] = 0;   // 设置为绿色
    colors[1][1] = 255;
    colors[1][2] = 0;
	    // 控制LED 2
    colors[2][0] = 0;   // 设置为蓝色
    colors[2][1] = 255;
    colors[2][2] = 0;
		    // 控制LED 3
    colors[3][0] = 100;   
    colors[3][1] = 200;
    colors[3][2] = 155;
		    // 控制LED 4
    colors[4][0] = 55;   
    colors[4][1] = 0;
    colors[4][2] = 0;


    // 调用WS2812_Send函数发送颜色数据
    WS2812_Send(colors, NUM_LEDS);
}


WS2812.c

// An highlighted block
#include "ws2812b.h"
#include "stdlib.h"
#include "delay.h"

#define NUM_LEDS 10 // 假设有5个LED
uint8_t colors[NUM_LEDS][3]; // 每个LED有3个颜色通道(RGB)

void WS2812_Send(uint8_t (*color)[3], uint16_t len)
{

	uint8_t i;
	uint16_t memaddr;
	uint16_t buffersize;
	buffersize = (len*24)+43;	// number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes
	memaddr = 0;				// reset buffer memory index

	
	if(len>NUM_LEDS){//
	len=NUM_LEDS;    //控制灯光的数量
	}                //
	while (len)
	{	
		
		for(i=0; i<8; i++) // RED
		{
			LED_BYTE_Buffer[memaddr] = ((color[len-1][1]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
			memaddr++;
		}
		
		for(i=0; i<8; i++) // GREEN data
		{
			LED_BYTE_Buffer[memaddr] = ((color[len-1][0]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
			memaddr++;
		}
		
		for(i=0; i<8; i++) // BLUE
		{
			LED_BYTE_Buffer[memaddr] = ((color[len-1][2]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
			memaddr++;
		}
		len--;
	}
//===================================================================//	
//bug:最后一个周期波形是高电平,故增加一个低电平的波形
		LED_BYTE_Buffer[memaddr] = 0;
//===================================================================//	
	  memaddr++;	
		while(memaddr < buffersize)
		{
			LED_BYTE_Buffer[memaddr] = 0;
			memaddr++;
		}

		DMA_SetCurrDataCounter(DMA1_Channel7, buffersize); 	// load number of bytes to be transferred
		DMA_Cmd(DMA1_Channel7, ENABLE); 			// enable DMA channel 7
		TIM_Cmd(TIM2, ENABLE); 						// enable Timer 2
		while(!DMA_GetFlagStatus(DMA1_FLAG_TC7)) ; 	// wait until transfer complete
		DMA_Cmd(DMA1_Channel7, DISABLE); 			// disable DMA channel 7
		DMA_ClearFlag(DMA1_FLAG_TC7); 				// clear DMA1 Channel 7 transfer complete flag
		TIM_Cmd(TIM2, DISABLE); 	// disable Timer 2
}



//呼吸灯代码//
void WS2812_Random()	//随机闪灯
{
		uint8_t rgb0[1][3];
	  rgb0[0][0] = rand()%256;
		rgb0[0][1] = rand()%256;
		rgb0[0][2] = rand()%256;
		WS2812_Send(&rgb0[0],1);
		delay_ms(1);
}

void WS2812_Red_BLN()	//红色呼吸灯
{
	u16 i;
	uint8_t rgb0[256][3] ={0,0,0};
	for(i=0;i<=255;i++)
	{
		rgb0[i][0] = i;
	}
	for(i=0;i<=255;i++)
	{
		WS2812_Send(&rgb0[i],1);
		delay_ms(5);
	}
	for(i=0;i<=255;i++)
	{
		rgb0[i][0] = (255 - i);
	}
	for(i=0;i<=255;i++)
	{
		WS2812_Send(&rgb0[i],1);
		delay_ms(5);
	}
	delay_ms(500);
	
}

void WS2812_Green_BLN()	//绿色呼吸灯
{
	u16 i;
	uint8_t rgb0[256][3] ={0,0,0};
	for(i=0;i<=255;i++)
	{
		rgb0[i][1] = i;
	}
	for(i=0;i<=255;i++)
	{
		WS2812_Send(&rgb0[i],1);
		delay_ms(5);
	}
	for(i=0;i<=255;i++)
	{
		rgb0[i][1] = (255 - i);
	}
	for(i=0;i<=255;i++)
	{
		WS2812_Send(&rgb0[i],1);
		delay_ms(5);
	}
	delay_ms(500);
}
void WS2812_Blue_BLN()	//蓝色呼吸灯
{
	u16 i;
	uint8_t rgb0[256][3] ={0,0,0};
	for(i=0;i<=255;i++)
	{
		rgb0[i][2] = i;
	}
	for(i=0;i<=255;i++)
	{
		WS2812_Send(&rgb0[i],1);
		delay_ms(5);
	}
	for(i=0;i<=255;i++)
	{
		rgb0[i][2] = (255 - i);
	}
	for(i=0;i<=255;i++)
	{
		WS2812_Send(&rgb0[i],1);
		delay_ms(5);
	}
	delay_ms(500);
}	



//单色灯代码//

//初始化灯光
void InitLED()
{
    u16 i = 0;

    for (i = 0; i < NUM_LEDS; i++) {
        colors[i][0] = 255; // 红色通道
        colors[i][1] = 0;   // 绿色通道
        colors[i][2] = 0;   // 蓝色通道
			 // 调用WS2812_Send函数发送颜色数据
			WS2812_Send(colors, NUM_LEDS);
    }
		delay_ms(1000);
		
}


void controlMultipleLEDs() {
    // 控制LED 0
    colors[0][0] = 255; // 设置为红色
    colors[0][1] = 0;
    colors[0][2] = 0;

    // 控制LED 1
    colors[1][0] = 0;   // 设置为绿色
    colors[1][1] = 255;
    colors[1][2] = 0;
	    // 控制LED 2
    colors[2][0] = 0;   // 设置为蓝色
    colors[2][1] = 255;
    colors[2][2] = 0;
		    // 控制LED 3
    colors[3][0] = 100;   // 设置为蓝色
    colors[3][1] = 200;
    colors[3][2] = 155;
		    // 控制LED 4
    colors[4][0] = 55;   // 设置为蓝色
    colors[4][1] = 0;
    colors[4][2] = 0;


    // 调用WS2812_Send函数发送颜色数据
    WS2812_Send(colors, NUM_LEDS);
}


void controlDiffentLEDs() {
   u16 i;
	u16 j;
	u16 a;
	u16 b;
	// 控制LED 0
	for(i=0;i<255;i++){
		for(a=100;a<255;a++){
			for(b=255;b>0;b--){
		for(j=0;j<NUM_LEDS;j++){
    colors[j][0] = i; // 设置为红色
    colors[j][1] = a;
    colors[j][2] = b;
		 // 调用WS2812_Send函数发送颜色数据
    WS2812_Send(colors, NUM_LEDS);
		delay_ms(1);
	}
}
			}
		}

    
}


pwm.c

// An highlighted block
#include "pwm.h"

void TIM2_PWM_Init(u16 arr,u16 psc)
{ 
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	/* GPIOA Configuration: TIM2 Channel 1 as alternate function push-pull */
	GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); //TIM2选择全复用功能使能 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;				//
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = arr; // 800kHz 
	TIM_TimeBaseStructure.TIM_Prescaler = psc;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	
	/* PWM4 Mode configuration: Channel1 */
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;//初始化占空比
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OC4Init(TIM2, &TIM_OCInitStructure);
	TIM_OC4PreloadConfig(TIM2,TIM_OCPreload_Enable);//修复DMA数据丢失
  TIM_ARRPreloadConfig(TIM2,ENABLE);//ARPE使能 
	TIM_Cmd(TIM2, ENABLE);  //使能TIM9
	
}

DMA.c

// An highlighted block
#include "dma.h"
uint16_t LED_BYTE_Buffer[300];

void TIM2_DMA_Init(void){ //DMA初始化设置
	
	/* configure DMA */
	DMA_InitTypeDef DMA_InitStructure;//定义DMA初始化结构体

	/* DMA clock enable */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);	//使能DMA时钟(用于SPI的数据传输)
	
	/* DMA1 Channel7 Config for PWM4 by TIM2_CH4*/
	DMA_DeInit(DMA1_Channel7);
	
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM2_CCR4_Address;	// physical address of Timer 3 CCR1
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)LED_BYTE_Buffer;		// this is the buffer memory 
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;						// data shifted from memory to peripheral
	DMA_InitStructure.DMA_BufferSize = 300;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;					// automatically increase buffer index
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;							// stop DMA feed after buffer size is reached
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	
	DMA_Init(DMA1_Channel7, &DMA_InitStructure);

	/* TIM2 DMA Request enable */
	TIM_DMACmd(TIM2, TIM_DMA_CC4, ENABLE);
	TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);
	
	
}

void SPI2_DMA_Init(void){ //DMA初始化设置
	
	/* configure DMA */
	DMA_InitTypeDef DMA_InitStructure;//定义DMA初始化结构体

	/* DMA clock enable */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);	//使能DMA时钟(用于SPI的数据传输)
	
	/* DMA1 Channel7 Config for PWM4 by TIM2_CH4*/
	DMA_DeInit(DMA1_Channel5);
	
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR);	// physical address of Timer 3 CCR1
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)LED_BYTE_Buffer;		// this is the buffer memory 
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;						// data shifted from memory to peripheral
	DMA_InitStructure.DMA_BufferSize = 300;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;					// automatically increase buffer index
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;							// stop DMA feed after buffer size is reached
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	
	DMA_Init(DMA1_Channel5, &DMA_InitStructure);

	
	
}

main.c

// An highlighted block
#include "dma.h"
#include "pwm.h"
#include "delay.h"
#include "ws2812b.h"
#include "stm32f10x.h"
#include "sys.h"
//需要更改标准库中的sys.h和delay.h

int main (void){
	RCC_Configuration();//系统时钟初始化
	TIM2_PWM_Init(77,0);	//初始化PWM
	TIM2_DMA_Init();		//初始化DMA
	InitLED();

	while(1){ 
		
			//WS2812_Red_BLN();				//红色呼吸灯
		//	WS2812_Green_BLN();			//绿色呼吸灯
		//	WS2812_Blue_BLN();			//蓝色呼吸灯
		//	WS2812_Random();			//随机闪灯
		//controlMultipleLEDs();
		controlDiffentLEDs();
			
	}

}





需要源码可评论留言。我们一些喜欢嵌入式的朋友一起建立的一个技术交流平台,本着大家一起互相学习的心态而建立,不太成熟,希望志同道合的朋友一起来。QQ372991598

;