共计 2661 个字符,预计需要花费 7 分钟才能阅读完成。
ADC 在嵌入式系统中的作用
ADC(模数转换器)是嵌入式系统中连接模拟世界和数字世界的桥梁。无论是传感器数据采集、音频处理还是电源监控,都需要 ADC 将连续的模拟信号转换为离散的数字信号。参数设定直接影响系统精度、响应速度和功耗,不当配置可能导致信号失真、数据丢失或资源浪费。

关键参数解析
1. 采样率与奈奎斯特定理
采样率决定了每秒采集样本的数量,必须满足奈奎斯特定理——至少为信号最高频率的 2 倍。实际工程中建议预留 20-30% 余量:
- 语音信号(8kHz 带宽):至少 16kHz 采样率
- 工业振动监测(1kHz 带宽):建议 2.5kHz 采样率
2. 分辨率与 ENOB
标称分辨率(如 12bit)不等于实际有效位数(ENOB)。受噪声影响,ENOB 通常低 1 - 2 位:
ENOB = (SNR - 1.76)/6.02
3. 参考电压选择
参考电压 (Vref) 决定 ADC 量程,需匹配信号幅度:
- 3.3V 系统:Vref=3.3V 时,1mV/LSB(12bit)
- 电池设备:可选用内部 1.2V 基准提高低电压测量精度
硬件平台特性对比
| 特性 | STM32F4 系列 | ESP32 系列 |
|---|---|---|
| 分辨率 | 12bit(16bit 可选) | 12bit |
| 采样率 | 2.4MSPS | 6kHz(APB 时钟分频) |
| 参考电压 | 外部 Vref+ 引脚 | 内部 1.1V±10% |
| 通道间隔离 | 较好 | 较差(需校准) |
实战代码示例
STM32 HAL 库配置(DMA 模式)
// 初始化结构体
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
void ADC1_Init(void) {
// DMA 配置(循环模式)hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR; // 循环缓冲
HAL_DMA_Init(&hdma_adc1);
// ADC 参数设定
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE; // 多通道扫描
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DMAContinuousRequests = ENABLE;
HAL_ADC_Init(&hadc1);
// 通道配置(以通道 0 为例)ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
ESP32 多通道校准
from machine import ADC, Pin
import time
# 电压分压校准系数(实测得到)calib_coeff = [1.02, 0.98, 1.05]
adc_pins = [ADC(Pin(36)), ADC(Pin(39)), ADC(Pin(34))]
for adc in adc_pins:
adc.atten(ADC.ATTN_11DB) # 量程 3.3V
adc.width(ADC.WIDTH_12BIT)
def read_calibrated():
raw = [adc.read() for adc in adc_pins]
return [raw[i]*3.3/4095*calib_coeff[i] for i in range(3)]
while True:
print(read_calibrated())
time.sleep_ms(100)
性能优化实践
PCB 布局建议
- 模拟电源与数字电源星型接地
- ADC 输入引脚布置 10-100nF 去耦电容
- 敏感走线远离高频信号线(至少 3 倍线宽距离)
软件滤波算法
移动平均滤波(C 实现):
#define FILTER_WINDOW 8
uint16_t moving_avg(uint16_t new_sample) {static uint16_t buf[FILTER_WINDOW] = {0};
static uint8_t idx = 0;
uint32_t sum = 0;
buf[idx++] = new_sample;
if(idx >= FILTER_WINDOW) idx = 0;
for(uint8_t i=0; i<FILTER_WINDOW; i++)
sum += buf[i];
return sum / FILTER_WINDOW;
}
常见问题规避
阻抗匹配方案
输入阻抗 (Rin) 与采样电容 (Csample) 形成 RC 电路,需满足:
Rin × Csample << 采样周期
建议:
– 高阻信号源前增加电压跟随器
– 采样时间设置为 RC 时间常数的 5 倍以上
动态参数调整
根据信号变化率自动调节采样率:
void adaptive_sampling(float signal_slope) {if(fabs(signal_slope) > THRESHOLD_HIGH)
set_sample_rate(MAX_RATE);
else if(fabs(signal_slope) < THRESHOLD_LOW)
set_sample_rate(MIN_RATE);
else
set_sample_rate(DEFAULT_RATE);
}
思考与延伸
在电池供电场景下,可采取以下策略平衡精度与功耗:
- 动态分辨率切换(高精度模式仅在有信号变化时激活)
- 参考电压跟随电池电压波动(需软件补偿)
- 采用窗口比较器唤醒机制(超阈值才启动 ADC)
通过本文介绍的方法,开发者可以构建从基础配置到高阶优化的完整 ADC 参数设定知识体系。实际应用中建议结合具体场景进行参数权衡,并通过实验验证最优配置。
正文完
