NUCLEO-F091RC开发板HAL ADC DMA无法触发HAL_ADC_ConvCpltCallback问题
NUCLEO-F091RC ADC DMA转换未完成、回调未触发问题解决
问题核心原因
- 缺失ADC底层硬件初始化(MspInit):未完成DMA通道与ADC的绑定配置,DMA无法接收ADC转换数据
- ADC EOC触发模式不匹配:单通道EOC触发无法适配多通道扫描+DMA连续传输的中断逻辑
- UART传输参数不合理:使用
sizeof发送缓冲区会包含冗余空字符
具体修改方案
1. 添加ADC Msp初始化函数
在/* USER CODE BEGIN 0 */区域添加以下代码,完成ADC时钟、GPIO模拟输入、DMA通道的配置与绑定:
#include <string.h> // 用于strlen函数 void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(hadc->Instance==ADC1) { /* 开启ADC时钟 */ __HAL_RCC_ADC1_CLK_ENABLE(); /* 开启GPIOA时钟(PA0/PA1对应ADC_IN0/IN1) */ __HAL_RCC_GPIOA_CLK_ENABLE(); /**ADC GPIO配置 PA0 ------> ADC_IN0 PA1 ------> ADC_IN1 */ GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* DMA通道初始化 */ hdma_adc.Instance = DMA1_Channel1; hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE; // 外设地址不递增(ADC数据寄存器固定) hdma_adc.Init.MemInc = DMA_MINC_ENABLE; // 内存地址递增(存储多个通道结果) hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; // ADC输出16位数据 hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; // 内存存储16位数据 hdma_adc.Init.Mode = DMA_CIRCULAR; // 循环模式,配合ADC连续转换自动重复采样 hdma_adc.Init.Priority = DMA_PRIORITY_MEDIUM; if (HAL_DMA_Init(&hdma_adc) != HAL_OK) { Error_Handler(); } /* 将DMA与ADC句柄绑定 */ __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc); } } void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc) { if(hadc->Instance==ADC1) { __HAL_RCC_ADC1_CLK_DISABLE(); HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0|GPIO_PIN_1); HAL_DMA_DeInit(hadc->DMA_Handle); } }
2. 修改ADC初始化的EOC触发模式
在MX_ADC_Init函数中,将EOC选择改为序列转换完成触发:
// 原代码 // hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // 修改为: hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;
原因:多通道扫描模式下,只有序列转换完成时触发EOC,才能正确触发DMA传输完成中断,进而调用HAL_ADC_ConvCpltCallback。
3. 优化UART传输逻辑
修改主循环中的UART传输代码,使用strlen获取有效数据长度,避免发送冗余空字符:
if(adc_conversion_complete_flag == 1) { snprintf(dma_result_buffer, 100, "ch1: %d, ch2: %d\r\n", adc_dma_results[0], adc_dma_results[1] ); // 原代码:sizeof(dma_result_buffer) // 修改为:strlen(dma_result_buffer) HAL_UART_Transmit(&huart2, (uint8_t*)dma_result_buffer, strlen(dma_result_buffer), HAL_MAX_DELAY); adc_conversion_complete_flag = 0; HAL_Delay(500); }
验证说明
修改完成后,重新编译烧录:
- ADC会自动连续扫描两个通道,DMA循环将转换结果存入
adc_dma_results数组 - 每次序列转换完成后,触发
HAL_ADC_ConvCpltCallback并设置标志位 - 主循环检测到标志位后,通过UART输出转换结果,500ms后等待下一次回调
内容的提问来源于stack exchange,提问作者persona
相关产品推荐
相关产品推荐

