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

这篇具有很好参考价值的文章主要介绍了STM32+PWM+DMA驱动WS2812彩灯模块(附源码)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

WS2812模块介绍

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

经典电路

stm32 ws2812,stm32,单片机,嵌入式硬件
C1为VDD的滤波电容,一般大小为100NF。

实物展示

stm32 ws2812,stm32,单片机,嵌入式硬件

点亮灯光

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

}





需要源码可评论留言。文章来源地址https://www.toymoban.com/news/detail-550698.html

到了这里,关于STM32+PWM+DMA驱动WS2812彩灯模块(附源码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32G0 定时器PWM DMA输出驱动WS2812配置 LL库

    优点:不消耗CPU资源 缺点:占用内存较大 定时器配置 定时器通道:TIM3 CH2 分频:0 重装值:79,芯片主频64Mhz,因此PWM输出频率:64Mhz/79 ≈ 800Khz,满足芯片要求。 auto-reload preload 要关闭 output compare preload 要打开 DMA配置 外设一定要选择TIM3_UP,不要选TIM_CHx 方向是内存到外设,

    2024年02月10日
    浏览(18)
  • 关于STM32利用TIM+PWM+DMA控制WS2812

    MCU:STM32F103c8t6 开发工具:STM32CubeMX  使用板子参考原理图:STM32F103C8T6最小系统板开源链接 脉宽调制(PWM)基本原理:控制方式就是对逆变电路开关器件的通断进行控制,使输出端得到一系列幅值相等但宽度不一致的脉冲,用这些脉冲来代替正弦波或所需要的波形。也就是在输

    2024年02月01日
    浏览(19)
  • [HAL]STM32 SPI+DMA驱动WS2812

    该程序是纯手敲,非Cube生成!所有代码均注释。 源码在文章后面获取 Keyword: 单线通讯、归零码、Reset、RGB顺序 RGB一共有24bit位 -相当于驱动一个灯要24bit位 -驱动若干个灯要24* n bit位,通过Reset码决定数据终止(保持) 24bit位应该如何发送? 可见: 表示低电平需要 T0H和T0L的配

    2024年02月09日
    浏览(17)
  • 【STM32F4系列】【HAL库】【自制库】WS2812(软件部分)(PWM+DMA)

    硬件介绍(PCB设计方案) 模拟时序发送 WS2812是一种异步串行通信,它每一位数据时间是ns级别的 默认是高电平状态 0码:220-380ns高电平+580-1600ns低电平 1码:580-1600ns高电平+220-380ns低电平 复位码:280us低电平 24Bit数据来代表GRB的亮度值 从高位到低位发送,分别按照G-R-B的顺序发送

    2024年02月15日
    浏览(58)
  • 使用STM32F103的SPI+DMA驱动ws2812 LED

    目录 前言 一、WS2812协议 1.1 数据传输编码方式:  1.2 传输的数据结构 二、驱动方式:SPI+DMA 2.1 原理介绍 2.2 SPI+DMA操作  2.3 编写代码 2.4 使用 三 总结 参考文章 主要使用的STM32F103C8T6芯片的SPI+DMA方式实现WS2812的驱动协议,总体可以看作是使用SPI来实现一种通信协议来发送信号。

    2024年02月09日
    浏览(31)
  • 软件STM32cubeIDE下STM32F1xx使用定时器(TIM8)+DMA+PWM点亮灯带WS2812-基础样例

    好长时间不调试灯带ws2812了,最近项目上,要在STM32F1上进行点灯带ws2812,虽然自己之前做了很多了,但是人有个性质,一旦某个事情做完了,你不在去惦记它了,基本会完全抛在脑后。所以才体现记录的重要性,本次在做STM32F1上验证时,即使之前有经验的情况下,还是掉坑

    2024年02月01日
    浏览(36)
  • STM32驱动全彩LED灯模块WS2812

    WS2812全彩LED灯模块系列,可以进行级联实现灯带的效果,MCU端通过一个管脚可以控制所有级联的LED灯的不同发光颜色显示。 WS2811(未集成LED)的级联电路如下所示: WS2812(集成LED)的级联电路如下所示: STM32是3.3V供电芯片,输出Push-Pull模式只有3.3V,WS2812采用5V供电,输入Vi

    2024年01月17日
    浏览(16)
  • 电子模块|外控集成 LED 光源 WS2812模块---硬件介绍和stm32驱动

    WS2812是一个集控制电路与发光电路于一体的智能外控LED光源。其外型与一个5050LED灯珠相同,每个元件即为一个像素点。像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路,还包含有高精度的内部振荡器和12V高压可编程定电流控制部分,有效保证了像素点光的颜色

    2024年02月10日
    浏览(20)
  • 讲解STM32驱动WS281x灯珠的多种实现方式:普通IO、SPI+DMA、以及PWM+DMA驱动方法

    STM32作为一款高性能、功能丰富的单片机,其丰富的外设和强大的性能,使其在嵌入式领域得到了广泛的应用。本篇文章将介绍如何利用STM32驱动WS281x系列的LED灯珠。我们会使用三种不同的驱动方式进行实现:一种是普通IO方式驱动,一种是SPI+DMA方式驱动,最后一种是PWM+DMA方

    2024年02月11日
    浏览(15)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包