STM32CUBEMX使用PWM+DMA驱动WS2812

STM32CUBEMX使用PWM+DMA驱动WS2812

  1. 首先在stm32cubemx中设置pwm和dma。我设置了TIM1的CH1为PWM引脚
  2. 编写DMA响应函数,即PWM DMA完成数据发送后的回调函数
// PWM DMA 完成回调函数
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
	HAL_TIM_PWM_Stop_DMA(&htim1, TIM_CHANNEL_1);
}

  1. 编写DMA载入数据的代码,运行后将会把数组(内存)中的数据写入到WS2812中。要更新WS2812的数据,只需要更改数组的内容即可。在此处LED_N为led数量
uint16_t led_buffer[LED_N*24 + 50];		// 最后50为reset信号,全设置为0
extern TIM_HandleTypeDef htim1;
// 启动DMA载入数据
void WS_Load(void)
{
	HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *)led_buffer, LED_N*24+50);
}
  1. 编写一些改变数组数据的函数,例如全红,全蓝之类的。
/ 关闭所有LED灯
void WS_Clear(void)
{
	uint16_t i;
	
	for(i=0; i<LED_N*24; i++)
		led_buffer[i] = LED_0;			// 写入逻辑0的占空比
	
	for(; i<LED_N*24+50; i++)
		led_buffer[i] = 0;					// 占空比比为0,全为低电平
	
	WS_Load();
}

// 全部led灯设置成一样的亮度,其中RGB分别设置亮度
// WS2812的写入顺序是GRB,高位在前面
void WS_Write_RGB(uint8_t n_R, uint8_t n_G, uint8_t n_B)
{
	uint16_t i, j;
	uint8_t dat[24];
	
	// 将RGB数据进行转换
	for(i=0; i<8; i++)
	{
		if((n_G&0x80) == 0)
			dat[i] = LED_0;
		else
			dat[i] = LED_1;
		n_G <<= 1;
	}
	for(i=0; i<8; i++)
	{
		if((n_R&0x80) == 0)
			dat[i+8] = LED_0;
		else
			dat[i+8] = LED_1;
		n_R <<= 1;
	}
	for(i=0; i<8; i++)
	{
		if((n_B&0x80) == 0)
			dat[i+16] = LED_0;
		else
			dat[i+16] = LED_1;
		n_B <<= 1;
	}
	
	for(i=0; i<LED_N; i++)
	{
		for(j=0; j<24; j++)
		{
			led_buffer[i*24 + j] = dat[j];
		}
	}
	
	for(i=LED_N*24; i<LED_N*24+50; i++)
	{
		led_buffer[i] = 0;					// 占空比比为0,全为低电平
	}
	
	WS_Load();
}

// 单独打开所有的LED R,亮度为n
void WS_Write_R(uint8_t n_R)
{
	WS_Write_RGB(n_R, 0, 0);
}

void WS_Write_G(uint8_t n_G)
{
	WS_Write_RGB(0, n_G, 0);
}

void WS_Write_B(uint8_t n_B)
{
	WS_Write_RGB(0, 0, n_B);
}
  1. 在main.c中调用这些函数即可。可以将改变WS2812数组的代码放入到定时器中,以固定的频率进行亮度和颜色改变

最后,WS2812的工作电压最好超过3.5V,当使用3.3V电压时,亮度和颜色已经不准确(正)了,在5V的时候亮度很正

使用PWM+DMA的可以使STM32不必一直处理这个,只需改变数组内容即可。同时时序控制也非常方便

猜你喜欢

转载自blog.csdn.net/Hot_Ant/article/details/107252154