1. 项目概述:高精度PT100温度测量系统
在工业控制和精密测量领域,温度监测的精度往往直接影响整个系统的性能表现。传统基于NTC热敏电阻的方案虽然成本低廉,但在-200°C至+850°C的宽温范围内难以保证±0.1°C的测量精度。这正是PT100铂电阻温度传感器的优势所在——其稳定的线性特性和重复性使其成为高精度测温的首选方案。
本系统采用STM32F103作为主控制器,搭配TI的ADS1220 24位Δ-Σ ADC,构建了一套完整的温度测量解决方案。硬件上采用三线制比例测量法消除引线电阻影响,软件层面则通过非阻塞状态机、64位定点数运算以及多种数字滤波算法,在资源受限的Cortex-M3内核上实现了媲美专业仪表的测量精度。
2. 系统架构设计
2.1 硬件组成解析
系统的硬件架构围绕三个核心元件构建:
- PT100传感器:采用三线制接法,利用IDAC电流源和参考电阻构建比例测量电路
- ADS1220 ADC:24位分辨率,内置PGA和数字滤波器,支持SPI Mode 1通信
- STM32F103:主控MCU,通过硬件SPI接口与ADC通信,运行温度转换算法
2.2 软件数据流设计
软件采用分层架构,各模块职责明确:
mermaid复制graph TD
A[主控逻辑] --> B[SPI驱动层]
A --> C[PT100测量层]
A --> D[数字滤波层]
B -->|原始ADC数据| C
C -->|电阻值| D
D -->|滤波后温度值| A
关键设计考量:
- 非阻塞式架构:避免在等待DRDY信号时阻塞主循环
- 定点数运算:STM32F103无FPU,采用Q格式定点数确保计算效率
- 模块化设计:ADC驱动、温度转换、数字滤波相互独立,便于维护
3. ADS1220驱动实现
3.1 SPI通信配置要点
ADS1220要求严格的SPI Mode 1时序(CPOL=0, CPHA=1),这是许多开发者首次使用时容易出错的地方。硬件SPI配置如下:
c复制void ADS1220_SPI_Init(void) {
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // CPOL=0
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // CPHA=1
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; // ~2.25MHz
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
}
关键细节:
- 必须配置NSS为软件控制(SPI_NSS_Soft)
- 时钟极性(CPOL)和相位(CPHA)必须严格匹配
- 首次通信前建议发送至少8个时钟周期唤醒ADC
3.2 寄存器配置策略
ADS1220的4个配置寄存器需要根据测量需求精心设置:
| 寄存器 | 关键位域 | 三线制推荐配置 |
|---|---|---|
| REG0 | MUX[3:0], GAIN[2:0], PGA_EN | AIN0-AIN1差分, PGA×8 |
| REG1 | DR[2:0], MODE[1:0], CM | 20SPS(降噪), 单次转换 |
| REG2 | VREF[1:0], IDAC[2:0] | 外部参考, IDAC=500μA |
| REG3 | I1MUX[2:0], I2MUX[2:0] | IDAC1→AIN2, IDAC2→AIN3 |
配置示例:
c复制void PT100_Init(PT100_Config_t *config) {
ADS1220_Config_t ads;
// REG0: 输入MUX + PGA配置
ads.reg0 = config->mux | config->gain_reg | ADS1220_PGA_ENABLED;
// REG1: 采样率 + 工作模式
ads.reg1 = ADS1220_DR_20SPS | ADS1220_MODE_NORMAL | ADS1220_CM_SINGLE;
// REG2: 参考源 + IDAC电流
ads.reg2 = config->vref_sel | ADS1220_FIR_50HZ_60HZ | config->idac;
// REG3: IDAC路由(三线制核心)
ads.reg3 = config->idac1_pin | config->idac2_pin | ADS1220_DRDYM_DRDY_ONLY;
ADS1220_WriteConfig(&ads);
Delay_ms(10); // 等待IDAC稳定
}
4. 非阻塞式数据采集
4.1 状态机设计
传统阻塞式等待DRDY的方式会浪费CPU周期,本设计采用状态机实现非阻塞采集:
c复制typedef enum {
STATE_IDLE = 0,
STATE_WAIT_DRDY
} PT100_State_t;
typedef struct {
uint8_t state;
uint32_t start_time;
int32_t last_result;
} PT100_Ctrl_t;
PT100_Ctrl_t g_pt100_ctrl = {0};
void PT100_Task_Async(void) {
uint32_t now = GetMillis();
switch(g_pt100_ctrl.state) {
case STATE_IDLE:
if(now - g_pt100_ctrl.last_time >= INTERVAL_MS) {
ADS1220_Start();
g_pt100_ctrl.start_time = now;
g_pt100_ctrl.state = STATE_WAIT_DRDY;
}
break;
case STATE_WAIT_DRDY:
if(ADS1220_DataReady()) {
g_pt100_ctrl.last_result = ADS1220_ReadData();
g_pt100_ctrl.state = STATE_IDLE;
}
else if(now - g_pt100_ctrl.start_time > TIMEOUT_MS) {
// 超时处理
g_pt100_ctrl.state = STATE_IDLE;
}
break;
}
}
4.2 时序优化技巧
- 硬件SPI DMA传输:对于多通道系统,可配置DMA减少CPU开销
- 中断唤醒:配置DRDY引脚触发外部中断,替代轮询
- 动态采样率:温度稳定时降低采样率节省功耗
5. 温度转换算法实现
5.1 电阻值计算
三线制比例测量的核心公式:
$$ R_{PT100} = \frac{ADC_{code} \times 2 \times R_{ref}}{2^{23} \times Gain} $$
代码实现采用64位整数防止溢出:
c复制int32_t PT100_CalcResistance(int32_t raw, uint32_t rref_mohm, uint8_t gain) {
int64_t numerator = (int64_t)raw * rref_mohm * 2;
int64_t denominator = 8388608LL * gain;
return (int32_t)(numerator / denominator);
}
5.2 温度查表与插值
为避免浮点运算,采用预计算查表+线性插值:
c复制static const int32_t PT100_R_TABLE[] = {
// -200°C to +850°C, 步进10°C
18520, 22830, 27100, ..., 390126
};
int32_t PT100_ResToTemp(int32_t res_mohm) {
// 二分查找找到相邻表项
int32_t low = 0, high = TABLE_SIZE-1;
while(low < high-1) {
int32_t mid = (low + high)/2;
if(res_mohm < PT100_R_TABLE[mid])
high = mid;
else
low = mid;
}
// 线性插值
int64_t delta_r = res_mohm - PT100_R_TABLE[low];
int64_t range_r = PT100_R_TABLE[high] - PT100_R_TABLE[low];
int32_t delta_t = (delta_r * 1000) / range_r; // 0.01°C分辨率
return -20000 + low*1000 + delta_t;
}
实测精度:在-50°C~150°C范围内,插值误差<±0.05°C
6. 数字滤波优化
6.1 滤波器选型对比
| 类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 移动平均 | 实现简单 | 响应慢 | 缓慢变化的温度 |
| 去极值平均 | 抗干扰强 | 需要缓存 | 存在瞬态干扰的环境 |
| IIR低通 | 实时性好 | 相位延迟 | 快速响应的系统 |
6.2 去极值平均实现
c复制typedef struct {
int32_t *buf;
uint16_t size;
uint16_t count;
} TrimFilter_t;
int32_t TrimFilter_Put(TrimFilter_t *f, int32_t x) {
// 存入缓冲区
f->buf[f->count++ % f->size] = x;
if(f->count >= f->size) {
// 排序并去掉首尾各1个极值
sort(f->buf, f->size);
int64_t sum = 0;
for(int i=1; i<f->size-1; i++)
sum += f->buf[i];
return sum / (f->size-2);
}
return x; // 未满时返回原始值
}
6.3 多级滤波策略
对于高噪声环境,可采用级联滤波:
- 第一级:硬件FIR滤波(ADS1220内置)
- 第二级:软件去极值平均
- 第三级:IIR低通平滑
7. 系统校准与验证
7.1 两点校准法
- 冰点校准:将PT100置于0°C冰水混合物,记录ADC值
- 沸点校准:将PT100置于100°C沸水,记录ADC值
- 计算斜率/截距:
c复制void PT100_Calibrate(int32_t adc0, int32_t adc100) {
int32_t slope = (10000 - 0) / (adc100 - adc0); // 0.01°C/LSB
int32_t offset = 0 - (adc0 * slope);
// 存储到Flash
}
7.2 实测数据对比
| 温度(°C) | 计算值 | 万用表测量 | 误差 |
|---|---|---|---|
| 0.0 | 0.12 | 0.0 | +0.12 |
| 25.0 | 25.08 | 25.0 | +0.08 |
| 100.0 | 99.92 | 100.0 | -0.08 |
注:使用0.1%精度参考电阻时,系统整体精度可达±0.1°C
8. 性能优化技巧
- 动态PGA调整:小信号时提高增益,大信号时降低增益
- 温度补偿:对参考电阻进行温度漂移补偿
- 噪声抑制:
- 在AIN引脚添加0.1μF陶瓷电容
- 使用屏蔽双绞线连接PT100
- 数字地与模拟地单点连接
9. 常见问题排查
9.1 DRDY无响应
- 检查SPI模式是否为Mode 1
- 测量CS信号是否正常
- 确认供电电压在2.7-5.5V范围内
9.2 温度读数跳变
- 检查参考电阻连接
- 尝试降低采样率(如20SPS)
- 增加数字滤波强度
9.3 线性度差
- 确认PT100接线正确(三线制需配对IDAC)
- 检查PGA是否饱和
- 验证参考电阻精度(建议0.1%或更高)
10. 扩展应用
本方案可轻松适配其他RTD传感器:
- PT1000:修改配置中的传感器类型,电阻值×10
- Cu50铜电阻:更新电阻-温度查表
- 四线制接法:调整IDAC路由配置
对于多通道系统,建议:
- 使用多路复用器扩展ADS1220输入
- 为每个通道保存独立的校准参数
- 采用时间片轮询方式采集各通道
在资源允许的情况下,可以进一步:
- 添加温度历史记录功能
- 实现Modbus RTU等通信协议
- 开发上位机校准工具
通过精心调试,这套基于STM32F103和ADS1220的方案完全能够满足工业级高精度温度测量的需求,其模块化设计也便于移植到其他嵌入式平台。