摘要
ADC 是嵌入式项目最常用的模拟采集外设,很多人调试时会遇到采样跳变、读数不准、分压算错的问题。本文基于气体监测工控项目实战,讲解 STM32 单通道 ADC 采集原理、电阻分压计算、硬件降噪、软件滤波方案,附带精简可移植代码,同时梳理现场调试踩坑点,适合快速落地模拟量采集。
适用主控:STM32F103RCT6
一、项目场景
项目中采集外部 0~3.3V 模拟电压信号;外部传感器输出最高 5V,不能直接接入 STM32 的 ADC 引脚,需要电阻分压电路降压。采集原始 ADC 值存在小幅噪声,需要软件滤波稳定输出电压,用于后续数据上传、阈值判断。
二、硬件分压原理与计算
STM32F103 ADC 参考电压VREF = 3.3V,12 位 ADC,分辨率:
(ADC_{max}=4095)
(V_{in} = \frac{ADC_val}{4095} \times V_{REF})
外部输入 5V 分压电路:上拉 R1=10k,下拉 R2=20k
分压公式:
(V_{adc_pin}=V_{in_ext} \times \frac{R2}{R1+R2})
当外部输入 5V:(V_{adc_pin}=5 \times 20/(10+20)=3.33V),接近 3.3V,实际选型可微调电阻留余量。
✅ 硬件要点
- ADC 引脚旁并联 0.1μF 陶瓷滤波电容,抑制高频噪声;
- 分压电阻选用 1% 精度金属膜电阻;
- 模拟地和数字地单点连接,减少电源干扰;
- 输入电压严禁超过 3.3V,否则会烧毁 MCU。
三、软件滤波方案
硬件滤波只能抑制高频噪声,工业场景仍会存在小幅跳变。这里采用滑动平均滤波 ,占用资源小,裸机项目首选。
原理:保存 N 次采样值,求和取平均值,剔除瞬时尖峰干扰。
四、代码实现(HAL 库,精简版)
#include "stm32f1xx_hal.h"
#define ADC_CH ADC_CHANNEL_1
#define AVG_CNT 8 //滑动平均采样次数
uint16_t adc_bufAVG_CNT;
uint8_t buf_idx = 0;
//ADC单次读取
uint16_t ADC_ReadRaw(void)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
return HAL_ADC_GetValue(&hadc1);
}
//滑动平均滤波
uint16_t ADC_ReadFilter(void)
{
uint32_t sum = 0;
adc_bufbuf_idx++ = ADC_ReadRaw();
if(buf_idx >= AVG_CNT) buf_idx = 0;
for(uint8_t i=0;i<AVG_CNT;i++)
{
sum += adc_buf[i];
}
return sum / AVG_CNT;
}
//转换为实际电压,单位:mV
uint16_t ADC_GetVoltage(void)
{
uint16_t adc_val = ADC_ReadFilter();
// V(mV) = adc_val / 4095 * 3300
return (uint32_t)adc_val * 3300 / 4095;
}
调用示例:放在 1ms 定时器任务中非阻塞采集
//1ms定时回调
void TIM_IRQ_Callback(void)
{
static uint16_t cnt = 0;
cnt++;
if(cnt >= 10) //10ms采集一次
{
cnt = 0;
uint16_t vol_mv = ADC_GetVoltage();
}
}
标准库极简版本(可选)
uint16_t ADC_ReadRaw(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
return ADC_GetConversionValue(ADC1);
}
五、工程踩坑总结
- 读数一直固定不变:检查 ADC 通道配置、引脚模式是否设置为模拟输入;
- 数值跳动很大:优先查硬件,确认 0.1uF 滤波电容、电源纹波,再加大滤波采样点数;
- 电压计算结果偏差:不要直接用 3.3 浮点数运算,嵌入式尽量用整数运算防止精度损失;
- 分压电阻选错:电阻不能太小,否则传感器负载过大;不能太大,ADC 采样阻抗不足,推荐 10k~100k 区间;
- 不要在中断里长时间采样,ADC 读取尽量放到主循环或者定时任务。
六、选型拓展
- 低速传感器(温湿度、电池电压):单通道查询采集 + 滑动平均;
- 多路模拟信号:ADC DMA 多通道连续采样;
- 高精度需求:增加外部基准源 TL431,替代片内 3.3V 参考。