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
相关产品推荐
相关产品推荐

