通过示波器观察PWM+DMA的方式驱动WS2812灯珠的波形及分析对应的现象
文章目录
1. 在DMA传送完PWM波形后不关闭PWM的DMA输出
灯珠显示效果:
灯珠会错乱显示(没有按正常设定的颜色显示)
示波器显示如下:
2. 在DMA传送完PWM波形后,在PWM传输完成后回调函数中关闭PWM的DMA输出
灯珠显示效果:
会按照设定的颜色正常显示,但灯带的起始位置会有绿色的余光(基于自己测试时使用的灯带)
示波器显示如下
3. 在DMA传送完PWM波形后,在DMA中断函数中关闭PWM的DMA输出
灯珠显示效果:
按照设定的颜色模式正常显示
示波器显示效果如下:
分析
方式1在pwm通过DMA的方式传输完成后会保持高电平,且会产生杂波,可能是导致灯珠显示错乱的主要原因.
方式2在DMA传输完成的回调函数关闭PWM输出,还会产生杂波,而将关闭PWM输出的函数放到DMA中断中便不会产生杂波,这个现象感觉很怪异,DMA中断函数HAL_DMA_IRQ()
会调用传输完成的回调函数HAL_TIM_PWM_PulseFinishedCallback()
但不知到为什么就不可以.
- 会产生杂波的方式:
/* 中断回调函数,在设定的pwm通过DMA发送完成后会调用 */
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef* htim)
{
/*
TODO:无论在这里是否关闭DMA输出,在PWM传输完成后都会产生一段杂波(用示波器看到的)。但是在这里关闭DMA输出后
灯珠的颜色可以正常显示,杂波不会影响当前及后续灯珠的显示。但是在这里不关闭DMA输出,便会影响灯珠的显示。
(不清楚原因)
TODO:在DMA中断函数中关闭DMA输出便不会产生杂波
*/
/* 注意这里的通道号要用 HAL_TIM_ACTIVE_CHANNEL_x而不能用TIM_CHANNEL_x,看定时器句柄定义的Channel类型便可知晓*/
if(htim->Instance == TIM3) {
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_1);
} else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {
HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_2);
}
}
}
- 不会产生杂波的方式
/**
* @brief This function handles DMA1 stream4 global interrupt.
*/
void DMA1_Stream4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_tim3_ch1);
/* 传输完成后,关闭DMA传输 */
HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_1);
}
/**
* @brief This function handles DMA1 stream5 global interrupt.
*/
void DMA1_Stream5_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_tim3_ch2);
/* 传输完成后,关闭DMA传输 */
HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_2);
}
感觉非常不能理解的一点是:HAL_DMA_IRQHandler()
函数中会调用HAL_TIM_PWM_PulseFinishedCallback()
函数,这就相当于产生杂波的方式比不产生杂波的方式提前调用了HAL_TIM_PWM_Stop_DMA()
函数.
如有大佬知道,希望能够不吝赐教!