STM32 ADC1扫描模式DMA循环模式下程序滞留在回调的问题
问题分析与解决方案
你的问题核心是DMA循环模式配合DMAContinuousRequests = ENABLE时,ADC转换完成中断会被持续触发,如果回调函数处理不当或中断优先级配置不合理,会导致主循环(while(1))完全被抢占,无法获得执行机会。以下是具体解决方法:
1. 优化回调函数,避免阻塞
回调函数必须轻量化,仅完成必要的标记操作,把数据处理逻辑放到主循环中。示例如下:
首先定义一个转换完成标志:
static uint8_t adc_conv_done = 0;
修改回调函数:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if (hadc->Instance == ADC1) { adc_conv_done = 1; // 仅置位标志,快速退出回调 } }
在主循环中处理数据:
while(1) { if (adc_conv_done) { // 在这里处理adc_buffer中的数据,比如: // uint16_t ch1_val = adc_buffer[0]; // uint16_t ch2_val = adc_buffer[1]; // uint16_t ch3_val = adc_buffer[2]; adc_conv_done = 0; // 清除标志,等待下一次转换完成 } // 主循环的其他任务 }
2. 调整中断优先级配置
检查NVIC中ADC和DMA的中断优先级,避免其优先级过高导致完全抢占主循环。确保:
- ADC/DMA的中断抢占优先级不要设置得过高,在裸机环境中,过高的优先级会让中断持续占用CPU,主循环无法执行。
- 可以通过STM32CubeMX的「NVIC Configuration」页面,降低ADC和DMA通道的抢占优先级数值(数值越大,优先级越低)。
3. 按需调整DMA与ADC的循环配置
如果不需要持续不间断的转换,可以修改配置:
- 将
hadc1.Init.DMAContinuousRequests设为DISABLE,这样单次扫描完成后不会自动发起下一次转换,需要在回调中手动重启:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if (hadc->Instance == ADC1) { adc_conv_done = 1; HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, 3); // 手动重启下一次转换 } }
这种方式可以控制转换触发频率,减少中断触发次数,给主循环留出更多执行时间。
4. 排查回调内的阻塞代码
检查当前回调函数中是否存在while()循环、延时函数等阻塞操作,这类代码会直接导致回调无法退出,彻底卡住程序。确保回调函数内无任何阻塞逻辑。
内容的提问来源于stack exchange,提问作者Idin Esmkhani
相关产品推荐
相关产品推荐

