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

avatar
作者
猴君
阅读量:0

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(); 			 	}  }      

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

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!