STM32F103RC与LTC1864高精度ADC信号采集方案
1. 项目背景与核心需求
在工业控制、医疗设备和消费电子等领域,我们经常需要将模拟信号(如温度、压力、光强等传感器输出)转换为数字信号进行处理。LTC1864作为一款16位高精度ADC芯片,配合STM32F103RC这款经典ARM Cortex-M3微控制器,能够构建高性价比的模拟信号采集系统。
这个组合的核心价值在于:
- LTC1864提供±2.5V的输入范围、250ksps采样率和低至1.5mW的功耗
- STM32F103RC内置硬件SPI接口,可高效读取ADC数据
- 整套方案BOM成本控制在50元以内,适合中小批量生产
提示:虽然STM32F103系列已上市多年,但其稳定的性能和丰富的生态资源,使其在2023年仍然是许多工程师的首选,特别是在需要平衡成本和性能的场景。
2. 硬件设计与接口连接
2.1 关键器件选型依据
选择LTC1864而非其他ADC芯片的主要原因:
- 真正的16位分辨率(无丢码)
- 单电源5V供电简化了电源设计
- 内置采样保持电路,无需外置组件
- SPI兼容接口(支持3线模式)
STM32F103RC的硬件优势:
- 72MHz主频满足实时处理需求
- 3个独立SPI接口(我们使用SPI1)
- 内置DMA控制器可减轻CPU负担
2.2 硬件连接示意图
以下是典型连接方式(使用SPI模式0):
| LTC1864引脚 | STM32F103RC引脚 | 备注 |
|---|---|---|
| VDD | 5V | 需加0.1μF去耦电容 |
| GND | GND | 模拟地要单点连接 |
| CONV | PA4 | 普通GPIO用于启动转换 |
| SDO | PA6 (SPI1_MISO) | 主入从出数据线 |
| SCK | PA5 (SPI1_SCK) | 时钟信号线 |
| CS | PA3 | 片选信号(低有效) |
| VIN+ | 信号源正极 | 通过RC滤波(如1kΩ+0.1μF) |
| VIN- | 信号源负极/地 | 差分输入时接信号负极 |
注意:当测量单端信号时,VIN-应接模拟地;测量差分信号时,需确保(VIN+)-(VIN-)在±2.5V范围内。
3. 软件实现与SPI配置
3.1 CubeMX初始化设置
使用STM32CubeMX配置SPI1的步骤:
- 选择SPI1工作在Master模式
- 时钟极性(CPOL)=Low,时钟相位(CPHA)=1Edge
- 数据大小设置为16位(对应LTC1864的输出格式)
- 预分频器设为8,得到9MHz SPI时钟(LTC1864最大支持8MHz)
- 启用DMA接收通道(可选但推荐)
关键配置代码片段:
hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES_RXONLY; hspi1.Init.DataSize = SPI_DATASIZE_16BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;3.2 数据采集流程实现
完整的ADC读取函数示例:
uint16_t LTC1864_Read(SPI_HandleTypeDef *hspi, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { uint16_t adc_value = 0; // 启动转换(拉低CONV引脚至少50ns) HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_RESET); Delay_us(1); // 实际延时约500ns // 读取转换结果(自动产生16个SCK周期) HAL_SPI_Receive(hspi, (uint8_t*)&adc_value, 1, 100); // 结束转换 HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_SET); return adc_value; }实测发现几个关键点:
- 转换结果的高4位是无效位(实际有效数据是D11-D0)
- 单端输入时,实际值 = (adc_value >> 4) * (2.5V / 4096)
- 差分输入时,需将结果视为有符号数处理
4. 性能优化与噪声处理
4.1 采样速率优化技巧
通过示波器实测发现:
- 纯软件轮询方式最高采样率约80ksps
- 启用DMA后可达180ksps
- 进一步优化GPIO操作可突破200ksps
DMA配置建议:
// 在CubeMX中配置: // DMA1 Channel2 -> SPI1_RX // 循环模式,数据宽度半字(16bit) // 内存地址递增禁用 // 代码中启动DMA接收 HAL_SPI_Receive_DMA(&hspi1, (uint8_t*)adc_buffer, BUFFER_SIZE);4.2 噪声抑制实践方案
实测中遇到的噪声问题及解决方案:
- 电源噪声:在LTC1864的VDD引脚增加10μF钽电容+0.1μF陶瓷电容组合
- 数字干扰:在SCK和SDO线上串联33Ω电阻
- 接地环路:采用星型接地,模拟地和数字地在MCU下方单点连接
一个有效的软件滤波算法(移动平均):
#define FILTER_SIZE 8 uint16_t filter_buffer[FILTER_SIZE]; uint8_t filter_index = 0; uint16_t MovingAverage_Filter(uint16_t new_value) { static uint32_t sum = 0; sum = sum - filter_buffer[filter_index] + new_value; filter_buffer[filter_index] = new_value; filter_index = (filter_index + 1) % FILTER_SIZE; return (uint16_t)(sum / FILTER_SIZE); }5. 实际应用案例
5.1 工业温度监测系统
在某烘箱温度监控项目中,我们使用该方案实现了:
- 8通道热电偶信号采集(通过多路复用器)
- 0.1℃的温度分辨率(配合PT100传感器)
- 通过Modbus RTU协议上传数据
关键电路改进:
- 每路输入增加1kΩ/100nF RC低通滤波
- 采用AD8606运放进行信号调理
- 在STM32的UART1上实现Modbus协议栈
5.2 便携式ECG设备原型
在医疗电子原型开发中,我们验证了:
- 0.5mV级心电信号采集
- 250Hz采样率下60dB共模抑制
- 锂电池供电时的低功耗设计
特殊处理措施:
- 采用右腿驱动电路降低共模干扰
- 使用STM32的硬件CRC校验数据完整性
- 开发了基于FreeRTOS的任务调度系统
6. 调试经验与常见问题
6.1 SPI通信故障排查
遇到SPI无数据返回时的检查清单:
- 用逻辑分析仪确认SCK信号是否正常产生
- 检查CS引脚电平是否在转换期间保持低电平
- 确认STM32的SPI时钟相位(CPHA)设置正确
- 测量LTC1864的VDD是否达到4.75V以上
一个实用的调试技巧:临时改用GPIO模拟SPI,可以隔离硬件SPI配置问题:
// 简化的软件SPI读取函数 uint16_t SoftSPI_Read() { uint16_t data = 0; HAL_GPIO_WritePin(CS_GPIO, CS_PIN, GPIO_PIN_RESET); for(int i=0; i<16; i++) { HAL_GPIO_WritePin(SCK_GPIO, SCK_PIN, GPIO_PIN_SET); data <<= 1; if(HAL_GPIO_ReadPin(SDO_GPIO, SDO_PIN)) data |= 1; HAL_GPIO_WritePin(SCK_GPIO, SCK_PIN, GPIO_PIN_RESET); } HAL_GPIO_WritePin(CS_GPIO, CS_PIN, GPIO_PIN_SET); return data; }6.2 精度不达标的改进方法
当实测ENOB(有效位数)低于14位时:
- 检查参考电压稳定性(建议使用ADR441基准源)
- 降低SPI时钟频率到1MHz以下测试
- 在信号输入端增加EMI滤波器
- 避免将ADC芯片放置在MCU正下方
实测数据对比(使用5V基准):
| 条件 | 实测ENOB | 噪声(LSB) |
|---|---|---|
| 直接连接 | 13.2位 | 8.3 |
| 增加RC滤波 | 14.1位 | 4.1 |
| 使用独立基准源 | 14.7位 | 2.2 |
| 优化PCB布局后 | 15.0位 | 1.5 |
7. 进阶应用方向
7.1 多芯片同步采样方案
通过STM32的定时器触发多个LTC1864同步转换:
- 配置TIM2产生50kHz PWM输出
- 将PWM信号连接到所有LTC1864的CONV引脚
- 使用SPI的NSS信号轮流读取各芯片数据
关键代码:
// 定时器配置 htim2.Instance = TIM2; htim2.Init.Prescaler = 71; // 1MHz计数 htim2.Init.Period = 19; // 20us周期(50kHz) htim2.Init.RepetitionCounter = 0; HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // 在PWM上升沿中断中启动DMA传输 void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) { static uint8_t chip_select = 0; HAL_GPIO_WritePin(CS1_GPIO, CS1_PIN, (chip_select == 0) ? GPIO_PIN_RESET : GPIO_PIN_SET); HAL_GPIO_WritePin(CS2_GPIO, CS2_PIN, (chip_select == 1) ? GPIO_PIN_RESET : GPIO_PIN_SET); chip_select ^= 1; }7.2 低功耗设计实践
电池供电场景下的优化措施:
- 将STM32主频降至8MHz(SPI分频设为2)
- 使用LTC1864的睡眠模式(CONV保持高电平)
- 采用间断采样模式(每秒唤醒一次)
实测电流对比:
| 工作模式 | 平均电流 | 采样率 |
|---|---|---|
| 全速运行 | 12.6mA | 250ksps |
| 间歇采样(10Hz) | 180μA | 10sps |
| 深度睡眠 | 22μA | 仅RTC |
在最近的一个野外监测项目中,这套方案配合2000mAh锂电池实现了超过1年的持续工作。关键是在STM32中合理配置了Stop模式,并通过RTC定时唤醒采集数据,只有在数据传输时才启用射频模块。
