You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NUCLEO-F091RC开发板HAL ADC DMA无法触发HAL_ADC_ConvCpltCallback问题

NUCLEO-F091RC ADC DMA转换未完成、回调未触发问题解决

问题核心原因

  1. 缺失ADC底层硬件初始化(MspInit):未完成DMA通道与ADC的绑定配置,DMA无法接收ADC转换数据
  2. ADC EOC触发模式不匹配:单通道EOC触发无法适配多通道扫描+DMA连续传输的中断逻辑
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 02:47:02