ADC的过采样技术与STM32F407应用
一、核心原理
STM32 ADC过采样是用时间换精度的低成本技术,利用量化噪声的白噪声特性,对同一信号多次采样后做数学处理,在不更换硬件的前提下提升有效分辨率。
量化噪声整形:过采样将量化噪声功率分散到更宽的频带上,通过数字滤波器滤除带外噪声,使带内噪声功率降低 。
分辨率提升规律:过采样率(OSR)每增加4倍,理论上可提升1 bit的有效分辨率(信噪比提高6 dB);若需提升n位分辨率,需进行4n次过采样,对应信噪比提升6dB,理论上可将12位ADC最高提升至16位及以上精度。。
简化模拟前端:高采样率放宽了对模拟抗混叠滤波器的要求,允许使用过渡带更宽、成本更低的滤波器
二、软硬件实现差异
硬件过采样:仅STM32G4、H7、L4+等新款系列内置专用过采样器,直接通过寄存器配置即可实现,无需占用CPU资源,支持最高1024倍过采样率。
软件模拟过采样:F1、F4等老款无硬件单元的系列,可通过DMA连续采集、软件累加后右移的方式实现,效果和硬件方案一致,但会占用部分CPU资源。
三、关键配置要点
开启功能:在CubeMX的ADC设置中,将Oversampling Mode选为ENABLE。
参数匹配:过采样倍率设为4的N次方,右移位数等于要提升的分辨率位数(如16倍过采样对应右移2位,提升2位精度)。
采样时间:可根据信号源阻抗选择1.5~480个ADC周期,高阻抗信号推荐选择更长的采样时间保证采样稳定。
四、STM32F407示例
STM32F407的ADC外设是12bit的采样精度,当我们采集模拟信号时可以利用过采样技术提高采样精度。即利用”每提升1位有效分辨率,过采样率需提高4倍”的规律来配置参数。我们以单ADC独立模式进行采样,在ADCCLK为36MHz、12位分辨率下,单次转换总耗时15个时钟周期,最高采样率可达2.4Msps,对应转换时间约0.417μs。
4.1 核心参数计算
目标提升位数:16bit - 12bit = 4位
所需最小过采样率:根据公式 OSR = 4^(N-M),代入数值得到 OSR = 4^4 = 256,即每输出1个16bit精度结果,需要采集256个原始12bit样本。
采样率换算:原始ADC采样率为2.4MHz,最终输出的有效吞吐率为 2.4MHz / 256 ≈ 9.375kHz,需确保该速率高于被测信号的奈奎斯特频率。
4.2 关键配置步骤
硬件采样配置
数据处理规则
用32位无符号整型变量累加256个12bit原始样本,累加完成后将总和右移4位(等价于除以16),即可得到等效16bit的高精度结果,避免溢出同时完成分辨率提升。
必要前提条件
输入信号必须叠加至少1LSB的随机白噪声,让ADC输出码能在相邻数值间随机波动,完全静止的直流信号无法通过该方法提升精度。
4.3 实际效果说明
受ADC本身的微分非线性(DNL)、积分非线性(INL)硬件限制,STM32等主流MCU的12bit ADC通过该方案通常可实现15~16位的有效位数(ENOB),接近理论16bit精度水平。
五、使用注意事项
信号本身需要有至少1LSB的随机噪声,否则过采样无法实现精度提升。
过采样会降低输出采样率,倍率越高响应速度越慢,需要平衡精度与实时性需求。
该技术仅能抑制随机量化噪声,无法消除偏移、增益等系统性误差,高精度场景需配合ADC校准流程。
六、示例代码
最后附上HAL库的ADC初始化代码,配置ADC1采集3个通道并通过DMA存入数组。
#include "stm32f4xx_hal.h"
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
uint16_t adc_values; // 存储3个通道的结果
void MX_ADC1_DMA_Init(void) {
// 1. DMA 配置
__HAL_RCC_DMA2_CLK_ENABLE();
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; // 循环模式
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_adc1);
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
// 2. ADC 配置
__HAL_RCC_ADC1_CLK_ENABLE();
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; // 21MHz
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE; // 开启扫描模式
hadc1.Init.ContinuousConvMode = ENABLE; // 连续转换
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; // 软件触发
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 3; // 3个通道
hadc1.Init.DMAContinuousRequests = ENABLE; // 开启DMA连续请求
HAL_ADC_Init(&hadc1);
// 3. 配置通道序列
ADC_ChannelConfTypeDef sConfig = {0};
// 通道 0 (例如 PA0) - Rank 1
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// 通道 1 (例如 PA1) - Rank 2
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// 通道 2 (例如 PA2) - Rank 3
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = 3;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// 4. 启动 DMA 和 ADC
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_values, 3);
}
我要赚赏金
