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

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

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

    需要源码可评论留言。

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32使用PWM DMA驱动WS2812彩灯模块(附源码)

    发表评论