RTOS环境下STM32动态调整PWM占空比无过渡效果问题排查
灯光渐变PWM在RTOS环境下无过渡效果问题排查
问题现象
为实现灯光亮度渐变编写了如下代码,该代码在非RTOS环境下运行正常,但在RTOS环境中,示波器观察到输出延迟约10秒后直接变为100%占空比的PWM,无渐变过渡效果。调试发现DutyCycle变量运行时正常递增,将DutyCycle设为固定整数值时,PWM可立即输出对应占空比。
原代码
控制任务代码
void output2ControlTask(void *argument) { /* USER CODE BEGIN output2ControlTask */ uint32_t DutyCycle = 0; /* Infinite loop */ for(;;) { if(flag_EN_OUTPUT2 == ON){ SteadyBurn_PWM_RTOS(&htim2, TIM_CHANNEL_3, DutyCycle); if(DutyCycle < 100){ DutyCycle++; } } if(flag_EN_OUTPUT2 == OFF){ SteadyBurn_PWM_RTOS(&htim2, TIM_CHANNEL_3, DutyCycle); if(DutyCycle > 0){ DutyCycle--; } } osDelay(100); } /* USER CODE END output2ControlTask */ }
PWM设置函数
void SteadyBurn_PWM_RTOS(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t intensity_percentage){ __HAL_TIM_SET_COMPARE(htim, Channel, (uint32_t)(COUNTER_PERIOD * (float)(intensity_percentage/100))); }
问题原因
这不是HAL库的问题,核心问题出在整数除法的精度丢失:
intensity_percentage是uint32_t类型,intensity_percentage/100属于整数除法,当intensity_percentage小于100时,运算结果始终为0;- 乘以
COUNTER_PERIOD后结果还是0,导致PWM占空比一直为0,直到DutyCycle递增到100时,100/100=1,才会输出满占空比的PWM; - 非RTOS环境下可能因编译器优化或隐式类型转换触发了正确的浮点运算,但这属于非预期行为。
解决方案
修改PWM设置函数中的除法运算,先将整数转换为浮点型再计算,避免整数除法丢失精度:
void SteadyBurn_PWM_RTOS(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t intensity_percentage){ float duty_ratio = (float)intensity_percentage / 100.0f; __HAL_TIM_SET_COMPARE(htim, Channel, (uint32_t)(COUNTER_PERIOD * duty_ratio)); }
或者直接在表达式中强制转换:
__HAL_TIM_SET_COMPARE(htim, Channel, (uint32_t)(COUNTER_PERIOD * ((float)intensity_percentage / 100.0f)));
额外建议
- 若系统对浮点数运算性能敏感,可改用整数运算替代(注意用64位中间变量避免溢出):
__HAL_TIM_SET_COMPARE(htim, Channel, (uint32_t)((uint64_t)COUNTER_PERIOD * intensity_percentage / 100)); - 确保
COUNTER_PERIOD的值足够大,避免低占空比时因整数截断导致精度不足。
内容的提问来源于stack exchange,提问作者Travis Su
相关产品推荐
相关产品推荐

