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

STM32F103C8T6多通道ADC采集电压波动异常,求原因分析

STM32F103C8T6多通道ADC采集值波动问题排查与优化

问题描述

使用STM32F103C8T6进行多通道电压采集,通过电位器控制输入电压变化,但ADC采集值存在严重波动。已尝试调整ADC采样周期长度,问题未得到改善。

相关代码

uint32_t ADC_Get_Average(uint8_t ch,uint8_t times)
{
    ADC_ChannelConfTypeDef sConfig;     
    uint32_t value_sum=0;   
    uint8_t i;
    switch(ch)                          
    {
        case 1:sConfig.Channel = ADC_CHANNEL_1;break;   
        case 2:sConfig.Channel = ADC_CHANNEL_2;break;
        case 3:sConfig.Channel = ADC_CHANNEL_3;break;
    }
    sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;     
    sConfig.Rank = 1;
    HAL_ADC_ConfigChannel(&hadc1,&sConfig);                                         
    for(i=0;i<times;i++)
    {
        HAL_ADC_Start(&hadc1);                                           
        HAL_ADC_PollForConversion(&hadc1,5);        
        value_sum += HAL_ADC_GetValue(&hadc1);                       
        HAL_ADC_Stop(&hadc1);                                            
    }
    return value_sum/times;                                              
}

void ADC_PROC(void)
{
  ADC_value1 = ADC_Get_Average(1,5) / 4096.0 * 3.3;
  ADC_value2 = ADC_Get_Average(2,5) / 4096.0 * 3.3;
  ADC_value3 = ADC_Get_Average(3,5) / 4096.0 * 3.3;
    
  sprintf(adcbuff1, "V1:%.2fV", ADC_value1);
  oled_show_string(24, 0, adcbuff1, 2);
  sprintf(adcbuff2, "V2:%.2fV", ADC_value2);
  oled_show_string(24, 2, adcbuff2, 2);
  sprintf(adcbuff3, "V3:%.2fV", ADC_value3);
  oled_show_string(24, 4, adcbuff3, 2);
}

优化方案

1. 代码逻辑优化:减少通道切换冗余操作

当前每次采集单通道都重复配置通道、启停ADC,频繁的硬件操作会引入额外干扰。建议改为多通道序列扫描模式,初始化时一次性配置所有通道,采集时启动一次ADC即可连续获取多通道数据:

// 初始化多通道序列
void ADC_MultiChannel_Init(void)
{
    ADC_ChannelConfTypeDef sConfig;
    // 配置通道1,序列排名1
    sConfig.Channel = ADC_CHANNEL_1;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
    // 配置通道2,序列排名2
    sConfig.Channel = ADC_CHANNEL_2;
    sConfig.Rank = 2;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
    // 配置通道3,序列排名3
    sConfig.Channel = ADC_CHANNEL_3;
    sConfig.Rank = 3;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

// 多通道采集函数
void ADC_Get_MultiChannel(uint32_t *values, uint8_t times)
{
    uint32_t sum1 = 0, sum2 = 0, sum3 = 0;
    for(uint8_t i=0; i<times; i++)
    {
        HAL_ADC_Start(&hadc1);
        // 等待通道1转换完成
        HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
        sum1 += HAL_ADC_GetValue(&hadc1);
        // 等待通道2转换完成
        HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
        sum2 += HAL_ADC_GetValue(&hadc1);
        // 等待通道3转换完成
        HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
        sum3 += HAL_ADC_GetValue(&hadc1);
        HAL_ADC_Stop(&hadc1);
    }
    values[0] = sum1 / times;
    values[1] = sum2 / times;
    values[2] = sum3 / times;
}

// 处理函数修改
void ADC_PROC(void)
{
    uint32_t adc_vals[3];
    ADC_Get_MultiChannel(adc_vals, 20); // 增加平均次数
    ADC_value1 = adc_vals[0] / 4096.0 * 3.3;
    ADC_value2 = adc_vals[1] / 4096.0 * 3.3;
    ADC_value3 = adc_vals[2] / 4096.0 * 3.3;
    
    // OLED显示代码不变
    sprintf(adcbuff1, "V1:%.2fV", ADC_value1);
    oled_show_string(24, 0, adcbuff1, 2);
    sprintf(adcbuff2, "V2:%.2fV", ADC_value2);
    oled_show_string(24, 2, adcbuff2, 2);
    sprintf(adcbuff3, "V3:%.2fV", ADC_value3);
    oled_show_string(24, 4, adcbuff3, 2);
}

2. 延长ADC采样时间

当前使用ADC_SAMPLETIME_1CYCLE_5,采样时间极短,输入信号还未稳定就被采样。建议改为更长的采样时间,比如ADC_SAMPLETIME_239CYCLES_5,确保输入电压在采样阶段充分稳定。

3. 增强软件滤波

仅5次均值滤波对突发干扰抑制有限,可改为中值+均值滤波:先采集一组数据,去掉最大值和最小值,再对剩余值求平均;或者直接增加平均次数到20次以上,进一步平滑输出。

4. 硬件滤波优化

  • 在ADC输入引脚与电位器之间添加RC滤波电路:推荐10kΩ电阻串联+100nF电容接地,滤除高频干扰。
  • 缩短电位器到MCU引脚的走线长度,避免引入电磁干扰;必要时对走线做屏蔽处理。
  • 检查VREF+参考电压稳定性:若使用内部参考电压,需在VREF引脚焊接100nF滤波电容;优先选择外部高精度参考源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 16:50:25