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