1. 项目概述
作为一名嵌入式开发工程师,我最近在STM32平台上实现了ADC多通道采集的案例。这个项目让我对ADC的独立模式多通道采集有了更深入的理解,特别是在处理多通道数据时如何避免数据覆盖的问题。本文将详细介绍整个实现过程,包括硬件设计、软件架构以及实际测试结果。
2. 硬件设计
2.1 电路设计思路
在硬件设计上,我采用了两种不同的电压输入方式:
-
可变电阻输入:使用PC0引脚(ADC通道10)连接一个10kΩ的可调电阻,电阻两端分别接3.3V和GND。通过旋转电位器可以产生0-3.3V的可变电压。
-
固定电压输入:使用PC2引脚(ADC通道12)通过杜邦线直接连接3.3V或GND,用于测试固定电压的采集。
这种设计有以下优势:
- 可变电阻输入可以直观地观察ADC采集的线性度
- 固定电压输入可以验证ADC的基准电压精度
- 两种输入方式结合可以全面测试多通道采集功能
2.2 具体电路实现
2.2.1 可变电阻电路
code复制3.3V ---[10kΩ电位器]--- GND
|
PC0(ADC1_CH10)
电位器选用10kΩ线性电位器,中间抽头连接PC0引脚。当旋转电位器时,PC0引脚上的电压会在0-3.3V之间线性变化。
2.2.2 固定电压电路
code复制PC2(ADC1_CH12) ---[杜邦线]--- 3.3V/GND
通过杜邦线直接将PC2引脚连接到电源或地,可以产生固定的高电平或低电平输入。
3. 软件设计
3.1 整体架构设计
软件设计采用分层架构:
- 硬件抽象层:直接操作寄存器配置ADC和DMA
- 驱动层:封装ADC初始化和采集功能
- 应用层:实现数据采集和显示逻辑
这种架构有以下优点:
- 各层职责明确,便于维护
- 硬件相关代码集中管理
- 上层应用不依赖具体硬件实现
3.2 ADC配置详解
3.2.1 时钟配置
首先需要配置ADC和GPIO的时钟:
c复制// 开启ADC1和GPIOC时钟
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN | RCC_APB2ENR_IOPCEN;
// ADC时钟6分频(72MHz/6=12MHz)
RCC->CFGR |= RCC_CFGR_ADCPRE_1;
RCC->CFGR &= ~RCC_CFGR_ADCPRE_0;
时钟配置注意事项:
- ADC最大时钟不能超过14MHz
- GPIO时钟必须开启才能配置引脚模式
- 时钟分频会影响ADC转换速度
3.2.2 GPIO配置
将PC0和PC2配置为模拟输入模式:
c复制// PC0模拟输入
GPIOC->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0);
// PC2模拟输入
GPIOC->CRL &= ~(GPIO_CRL_MODE2 | GPIO_CRL_CNF2);
模拟输入模式的特点:
- 输入阻抗高,对信号影响小
- 内部不上拉也不下拉
- 适合连接高阻抗信号源
3.2.3 ADC工作模式配置
多通道采集需要配置扫描模式和连续转换模式:
c复制// 开启扫描模式
ADC1->CR1 |= ADC_CR1_SCAN;
// 开启连续转换模式
ADC1->CR2 |= ADC_CR2_CONT;
// 数据右对齐
ADC1->CR2 &= ~ADC_CR2_ALIGN;
模式配置要点:
- 扫描模式:按顺序转换所有使能的通道
- 连续模式:转换完成后自动开始新一轮转换
- 数据对齐:右对齐更方便数据处理
3.2.4 采样时间配置
为两个通道配置7.5周期的采样时间:
c复制// 通道10采样时间7.5周期
ADC1->SMPR1 |= ADC_SMPR1_SMP10_0;
ADC1->SMPR1 &= ~(ADC_SMPR1_SMP10_2 | ADC_SMPR1_SMP10_1);
// 通道12采样时间7.5周期
ADC1->SMPR1 |= ADC_SMPR1_SMP12_0;
ADC1->SMPR1 &= ~(ADC_SMPR1_SMP12_2 | ADC_SMPR1_SMP12_1);
采样时间选择考虑:
- 采样时间越长,转换精度越高
- 但转换速度会降低
- 7.5周期是常用折中选择
3.2.5 规则通道配置
配置规则通道序列:
c复制// 序列长度=2
ADC1->SQR1 &= ~ADC_SQR1_L;
ADC1->SQR1 |= ADC_SQR1_L_0;
// 序列1=通道10
ADC1->SQR3 &= ~ADC_SQR3_SQ1;
ADC1->SQR3 |= (10 << 0);
// 序列2=通道12
ADC1->SQR3 &= ~ADC_SQR3_SQ2;
ADC1->SQR3 |= (12 << 5);
规则通道配置要点:
- 序列长度必须与实际通道数一致
- 通道编号从0开始
- 转换按序列顺序进行
3.3 DMA配置详解
3.3.1 DMA初始化
配置DMA1通道1用于ADC数据传输:
c复制// 开启DMA1时钟
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
// 传输方向:外设到存储器
DMA1_Channel1->CCR &= ~DMA_CCR1_DIR;
// 数据宽度:16位
DMA1_Channel1->CCR &= ~DMA_CCR1_PSIZE_1;
DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;
DMA1_Channel1->CCR &= ~DMA_CCR1_MSIZE_1;
DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_0;
// 地址增量模式
DMA1_Channel1->CCR &= ~DMA_CCR1_PINC;
DMA1_Channel1->CCR |= DMA_CCR1_MINC;
// 循环模式
DMA1_Channel1->CCR |= DMA_CCR1_CIRC;
// 开启ADC的DMA模式
ADC1->CR2 |= ADC_CR2_DMA;
DMA配置关键点:
- 必须开启循环模式以匹配ADC连续转换
- 外设地址固定(ADC数据寄存器)
- 存储器地址需要自动递增
3.3.2 DMA传输参数设置
启动转换时设置DMA传输参数:
c复制void ADC1_DMA_StartConvert(uint32_t destAddr, uint8_t len)
{
// 设置源地址(ADC数据寄存器)
DMA1_Channel1->CPAR = (uint32_t)(&(ADC1->DR));
// 设置目标地址(用户缓冲区)
DMA1_Channel1->CMAR = destAddr;
// 设置传输数量
DMA1_Channel1->CNDTR = len;
// 使能DMA通道
DMA1_Channel1->CCR |= DMA_CCR1_EN;
// ADC上电和校准
ADC1->CR2 |= ADC_CR2_ADON;
ADC1->CR2 |= ADC_CR2_CAL;
while(ADC1->CR2 & ADC_CR2_CAL);
// 启动转换
ADC1->CR2 |= ADC_CR2_ADON;
// 等待首次转换完成
while((ADC1->SR & ADC_SR_EOC) == 0);
}
DMA传输特点:
- 传输完成后数据自动存入用户缓冲区
- 不需要CPU干预
- 可以大大提高系统效率
4. 实际测试与问题排查
4.1 正常工作情况测试
当PC2连接3.3V时,采集结果如下:
code复制PC0 = 1.23 v PC2 = 3.30 v
PC0 = 2.45 v PC2 = 3.30 v
PC0 = 0.98 v PC2 = 3.30 v
可以看到PC2通道稳定采集到3.3V电压,PC0通道随电位器旋转变化。
4.2 异常情况分析
4.2.1 引脚浮空问题
当PC2引脚浮空时,观察到以下现象:
code复制PC0 = 1.23 v PC2 = 1.25 v
PC0 = 2.45 v PC2 = 2.40 v
PC0 = 0.98 v PC2 = 1.02 v
这是因为:
- 浮空引脚容易受到邻近引脚干扰
- PC0和PC2物理位置接近
- 模拟输入阻抗高,容易耦合噪声
解决方法:
- 避免让ADC引脚浮空
- 可以配置内部下拉电阻
- 或者外部接固定电阻到地
4.2.2 数据覆盖问题
如果不使用DMA,直接读取ADC数据寄存器:
c复制uint16_t val1 = ADC1->DR;
uint16_t val2 = ADC1->DR;
会发现val1和val2值相同,这是因为:
- 规则通道组只有一个数据寄存器
- 新数据会覆盖旧数据
- 必须使用DMA或快速读取才能获取多通道数据
4.3 性能优化建议
-
采样时间优化:
- 高阻抗信号源需要更长采样时间
- 低阻抗信号可以缩短采样时间提高速率
-
DMA缓冲区设计:
- 可以使用双缓冲区减少数据处理延迟
- 缓冲区大小应为通道数的整数倍
-
软件滤波:
- 添加滑动平均滤波提高稳定性
- 中值滤波去除突发干扰
5. 经验总结与进阶思考
5.1 关键经验总结
- 多通道采集必须使用扫描模式
- 连续转换模式下DMA应该配置为循环模式
- ADC校准对精度影响很大,不能省略
- 浮空引脚会导致读数不稳定
- 规则通道只有一个数据寄存器,必须及时读取
5.2 进阶应用方向
-
注入通道的使用:
- 规则通道和注入通道可以配合使用
- 注入通道可以中断规则通道的转换
-
定时器触发ADC:
- 使用定时器精确控制采样间隔
- 适合需要固定采样率的应用
-
多ADC协同工作:
- 多个ADC可以并行工作提高吞吐量
- 支持交替模式和同步模式
5.3 实际项目建议
-
电源噪声处理:
- ADC参考电压要干净稳定
- 添加适当的去耦电容
-
PCB布局注意:
- 模拟信号走线要短
- 避免与数字信号平行走线
-
软件架构设计:
- 将ADC驱动与业务逻辑分离
- 使用回调机制处理采样数据
通过这个项目,我深刻理解了STM32 ADC多通道采集的工作原理和实现方法。DMA的使用大大提高了数据采集效率,避免了CPU频繁中断的开销。在实际应用中,还需要根据具体需求优化采样率和精度,处理好信号完整性问题。