3、数据采集基础:传感器接口类型、ADC原理与配置、DMA传输机制
数据记录仪的本质是将物理世界中的模拟量或数字量转换为MCU可处理的数字信号,并最终落盘存储。在STM32项目中,传感器接口选型、ADC采样精度与DMA传输效率直接决定了数据记录仪的实时性、完整性与准确性。本章将围绕传感器接口类型(模拟、数字、I2C、SPI、UART)、ADC核心原理与配置方法、DMA传输机制三个维度展开,并结合实际工程案例说明如何构建一条高效、低CPU占用的数据采集链路。
3.1 传感器接口类型与选型判断
核心原理:传感器接口决定了信号从物理量到MCU可识别数据的传输路径。模拟接口输出连续电压或电流信号,需经ADC量化;数字接口(I2C、SPI、UART)则直接输出数字码流,MCU通过对应外设控制器解析。选择接口类型时需综合考虑采样率、分辨率、传输距离、功耗和引脚占用。
| 接口类型 | 典型传感器 | 最大速率 | 引脚数 | 适用场景 | STM32外设 |
|---|---|---|---|---|---|
| 模拟 | NTC热敏电阻、压力传感器、光敏电阻 | 取决于ADC采样率 | 1 | 低速、低成本、高分辨率需求 | ADC + DMA |
| 数字IO | 霍尔开关、编码器、风速计 | 取决于定时器输入捕获 | 1 | 频率/脉宽测量 | TIM + IC |
| I2C | SHT30温湿度、BMP280气压、MPU6050 | 400kbps (Fast Mode) | 2 (SDA/SCL) | 多设备、低速、板内通信 | I2C + DMA |
| SPI | MAX31865热电偶、ADXL345加速度、W25Q64 Flash | 可达45Mbps | 4 (MOSI/MISO/SCK/CS) | 高速、大数据量、板内通信 | SPI + DMA |
| UART | GPS模块、激光雷达、气体传感器 | 可达921600bps | 2 (TX/RX) | 远距离、异步通信、与PC交互 | USART + DMA |
判断方法:首先确认传感器数据手册中的输出类型。若为电压输出(如0-3.3V),则走模拟通道;若为数字协议,则需匹配对应外设。其次评估采样率需求:若单通道采样率超过10kHz,建议使用SPI或并行接口;若低于1kHz且设备数量多,I2C更合适。最后考虑系统复杂度——I2C通过地址区分设备,但速率受限;SPI速率高但需额外CS引脚管理。
3.2 ADC原理与STM32配置要点
核心原理:ADC(模数转换器)将连续模拟电压映射为离散数字值。STM32内置逐次逼近型(SAR)ADC,分辨率12位(部分系列支持16位),转换结果存储在数据寄存器中。关键参数包括:参考电压(VREF+)、采样时间(Sample Time)、转换周期(Conversion Cycle)和通道扫描模式。
操作流程:配置ADC需完成以下步骤:
- 时钟使能:开启GPIO、ADC和DMA时钟(如RCC->APB2ENR |= RCC_APB2ENR_ADC1EN)。
- GPIO模拟模式:将采样引脚配置为模拟输入(GPIO_Mode_AN)。
- ADC参数配置:设置分辨率、对齐方式(右对齐)、扫描模式、连续转换或单次转换。
- 采样时间设置:根据源阻抗选择采样周期(如239.5周期),确保内部采样电容充满。
- DMA请求使能:开启ADC的DMA输出,避免CPU频繁读取数据寄存器。
// 以STM32F407 ADC1 通道0 (PA0) 为例
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStruct.ADC_ScanConvMode = DISABLE; // 单通道
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; // 连续转换
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStruct);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_84Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
案例拆解:某工业数据记录仪需采集4-20mA电流环信号,经250Ω精密电阻转换为1-5V电压。由于STM32 ADC输入范围0-3.3V,需先经分压电阻(如30kΩ/20kΩ)将电压降至0.66-3.3V。此时源阻抗较高,需将采样时间设为最大(如480周期),否则采样值会偏低。实测发现,若采样时间设为84周期,读数偏差达2.5%;改为480周期后偏差降至0.3%。
3.3 DMA传输机制与双缓冲设计
核心原理:DMA(直接内存访问)允许外设(如ADC、SPI、UART)在无需CPU干预的情况下,将数据直接搬运到内存缓冲区。STM32的DMA控制器支持循环模式、双缓冲模式和突发传输。对于数据记录仪,DMA可显著降低CPU负载,使主循环专注于数据处理和存储。
判断方法:当外设产生数据的速度高于CPU处理速度,或需要连续采集大量数据时,必须使用DMA。例如,以10kHz采样率、12位分辨率连续采集,每秒产生20KB数据,若用中断方式,CPU将忙于响应中断而无法执行其他任务。此时DMA循环模式配合双缓冲是最佳方案。
| 特性 | 普通模式 | 循环模式 | 双缓冲模式 |
|---|---|---|---|
| 传输结束后行为 | 停止,需重新配置 | 自动重置并继续 | 在两个缓冲区之间切换 |
| CPU干预 | 每次传输完成需中断 | 仅在缓冲区满时中断 | 半传输/传输完成中断 |
| 适用场景 | 单次数据块传输 | 连续数据流采集 | 高速连续采集+实时处理 |
| 数据丢失风险 | 低 | 高(若处理不及时) | 低(乒乓切换) |
操作流程(双缓冲实现):
- 定义两个缓冲区
uint16_t buf1[1024], buf2[1024]; - 配置DMA为循环模式,内存地址交替指向buf1和buf2。
- 使能DMA半传输中断(Half Transfer)和传输完成中断(Transfer Complete)。
- 在半传输中断中处理buf1数据,在传输完成中断中处理buf2数据。
// DMA双缓冲配置伪代码
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; // 循环模式
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)buf1; // 内存基地址
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStruct.DMA_BufferSize = 1024;
DMA_Init(DMA2_Stream0, &DMA_InitStruct);
// 使能双缓冲
DMA_DoubleBufferModeConfig(DMA2_Stream0, (uint32_t)buf2, DMA_Memory_1);
DMA_DoubleBufferModeCmd(DMA2_Stream0, ENABLE);
// 中断处理
void DMA2_Stream0_IRQHandler(void) {
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HT)) { // 半传输
process_data(buf1, 1024);
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HT);
}
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TC)) { // 传输完成
process_data(buf2, 1024);
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TC);
}
}
案例复盘:某便携式振动记录仪需以25.6kHz采样率连续采集三轴加速度数据(每轴16位),总数据率约153.6KB/s。采用ADC1+DMA循环模式,双缓冲区各8KB。DMA半传输中断将数据写入SD卡FATFS缓冲区,传输完成中断处理下一批。实测CPU占用率从中断方式的78%降至12%,且未出现数据丢失。关键优化点:将DMA优先级设为最高,并将缓冲区大小对齐到SD卡扇区(512字节)的整数倍,减少写入次数。