阅读量: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(未满)