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

STM32F072C8U6 ADC读取异常排查:值与示波器不符且读取不稳定

STM32F072C8U6 ADC采样异常问题排查

我在读取STM32F072C8U6 MCU引脚的ADC值时,遇到两个问题:读取值与示波器测量结果不一致,且存在间歇性读取失败的情况。多次重新配置ADC初始化均未解决问题。相关代码如下:

读取电压代码

bool PM_ReadVoltage(const TestPointSpec *spec, float *val, bool raw)
{
    bool success = false;
    ADC_ChannelConfTypeDef channelConf;

    HAL_ADC_Stop(&hadc);
    HAL_ADCEx_Calibration_Start(&hadc);

    channelConf.Rank = 1;
    channelConf.SamplingTime = CONFIG_ADC_SAMPLE_TIME;
    channelConf.Channel = spec->adcChannel;

    if (HAL_ADC_ConfigChannel(&hadc, &channelConf) != HAL_OK)
    {
        return false;
    }

    HAL_ADC_Start(&hadc);
    HAL_StatusTypeDef rc = HAL_ADC_PollForConversion(&hadc, 500);

    if (rc == HAL_OK)
    {
        uint32_t res = HAL_ADC_GetValue(&hadc);

        #if CONFIG_CALIB_MODE == 1
                COM_Trace("Raw %s=%d", spec->name, res);
        #endif

        if (!raw && spec->isHalf)
        {
            *val = (float)res * gAdcResolution * 2;
        }
        else
        {
            *val = (float)res * gAdcResolution;
        }
    }
    else
    {
        goto out;
    }

    *val += *val * spec->testPointVolLinearCalib;
    success = true;
out:
    channelConf.Rank = ADC_RANK_NONE;
    HAL_ADC_ConfigChannel(&hadc, &channelConf);
    HAL_ADC_Stop(&hadc);
    HAL_Delay(100);

    return success;
}

HAL初始化代码

static void ADC1_Init(void)
{
    ADC_ChannelConfTypeDef sConfig = {0};

      hadc.Instance = ADC1;
      hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
      hadc.Init.Resolution = ADC_RESOLUTION_12B;
      hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
      hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
      hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
      hadc.Init.LowPowerAutoWait = DISABLE;
      hadc.Init.ContinuousConvMode = ENABLE;
      hadc.Init.DiscontinuousConvMode = DISABLE;
      hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
      hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
      hadc.Init.DMAContinuousRequests = DISABLE;
      hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

    if (HAL_ADC_Init(&hadc) != HAL_OK)
    {
        Error_Handler();
    }

    HAL_ADCEx_Calibration_Start(&hadc);
    HAL_Delay(10);

    sConfig.Channel = ADC_CHANNEL_VREFINT;
    sConfig.Rank = 1;
    sConfig.SamplingTime = CONFIG_ADC_SAMPLE_TIME;

    const uint16_t VREFIN_CAL = *((uint16_t*)0x1FFFF7BA);

    if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
    {
        Error_Handler();
    }

    HAL_ADC_Start(&hadc);

    if (HAL_ADC_PollForConversion(&hadc, 500) == HAL_OK)
    {
        uint32_t val = HAL_ADC_GetValue(&hadc);
        uint32_t vdda = (3300UL * (uint32_t)VREFIN_CAL) / val;
        PM_SetVDDA(vdda / 1000.0f);
    }

    sConfig.Rank = ADC_RANK_NONE;
    HAL_ADC_ConfigChannel(&hadc, &sConfig);

    HAL_ADC_Stop(&hadc);
}

GPIO ADC配置

#define ADC_PIN_NUM     7

#define ADC_INPUT_3     { .port = GPIOA, .pin = GPIO_PIN_3 }
#define ADC_INPUT_4     { .port = GPIOA, .pin = GPIO_PIN_4 }
#define ADC_INPUT_5     { .port = GPIOA, .pin = GPIO_PIN_5 }
#define ADC_INPUT_6     { .port = GPIOA, .pin = GPIO_PIN_6 }
#define ADC_INPUT_7     { .port = GPIOA, .pin = GPIO_PIN_7 }
#define ADC_INPUT_8     { .port = GPIOB, .pin = GPIO_PIN_0 }
#define ADC_INPUT_9     { .port = GPIOB, .pin = GPIO_PIN_1 }

问题分析与修复建议

  • 校准操作滥用:每次采样前执行HAL_ADCEx_Calibration_Start会破坏ADC稳定性,校准只需在初始化时执行一次。移除PM_ReadVoltage中的校准调用。
  • 连续转换模式冲突:初始化时开启连续转换模式,但采样逻辑是单次触发,会导致数据溢出或读取旧值。将ContinuousConvMode改为DISABLE。
  • 采样时间不足:若CONFIG_ADC_SAMPLE_TIME过小,无法让输入电压稳定。建议设置为最长采样时间(如ADC_SAMPLETIME_239CYCLES_5)验证偏差问题。
  • 冗余通道配置:采样完成后无需将通道Rank设为ADC_RANK_NONE,简化流程,直接在下次采样时重新配置通道即可。
  • VDDA校准精度:单次采样VREFINT易受干扰,建议多次采样取平均值后计算VDDA,提高转换精度。

内容的提问来源于stack exchange,提问作者jayy_nguyen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:18:09