热电偶采集温度源代码(AD7124 + Pt100冷端补偿方案)
一、系统概述
本方案使用AD7124高精度Σ-Δ ADC同时采集热电偶信号和Pt100冷端温度,实现高精度温度测量。系统包含:
- AD7124:24位ADC,支持热电偶和RTD测量
- Pt100:铂电阻温度传感器,用于冷端补偿
- STM32F4:主控芯片,处理数据并输出温度值
- K型热电偶:测量目标温度
系统通过硬件同步采集热电偶电压和冷端温度,软件实现冷端补偿算法,最终输出精确的热端温度。
二、硬件设计
1. 系统架构
graph TD
A[K型热电偶] -->|微电压| B(AD7124)
C[Pt100] -->|电阻变化| B
B -->|SPI| D[STM32F4]
D -->|UART| E[PC/显示终端]
D -->|PWM| F[加热器控制]
2. 关键电路设计
(1) AD7124与STM32连接
| AD7124引脚 | STM32引脚 | 功能 |
|---|---|---|
| SCLK | PA5 (SPI1_SCK) | SPI时钟 |
| DIN | PA7 (SPI1_MOSI) | SPI数据输入 |
| DOUT | PA6 (SPI1_MISO) | SPI数据输出 |
| CS | PA4 (GPIO) | 片选 |
| SYNC | PB0 (GPIO) | 同步信号 |
| DRDY | PB1 (EXTI1) | 数据就绪 |
(2) 热电偶信号调理电路
K型热电偶 → 仪表放大器(AD8226) → 低通滤波(100Hz) → AD7124_CH0
↑
冷端补偿电压
(3) Pt100测量电路
Pt100 → 恒流源(1mA) → 电桥电路 → AD7124_CH1
↑
参考电阻(400Ω)
三、软件设计
1. 核心代码实现
(1) AD7124驱动 (ad7124.c)
#include "ad7124.h"
#include "spi.h"
#include "gpio.h"
// AD7124寄存器地址
#define REG_COMM 0x00
#define REG_STATUS 0x00
#define REG_MODE 0x01
#define REG_CONFIG 0x02
#define REG_DATA 0x04
#define REG_ID 0x05
#define REG_IO 0x06
#define REG_GAIN 0x07
#define REG_CH0_MAP 0x10
#define REG_CH1_MAP 0x11
#define REG_CFG0 0x20
#define REG_CFG1 0x21
#define REG_FILTER0 0x28
#define REG_FILTER1 0x29
// 通信函数
static void AD7124_WriteReg(uint8_t reg, uint8_t *data, uint8_t len) {
uint8_t tx_buf[len+1];
tx_buf[0] = 0x00 | (reg & 0x3F); // 写命令
memcpy(&tx_buf[1], data, len);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1, tx_buf, len+1, 100);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
}
static void AD7124_ReadReg(uint8_t reg, uint8_t *data, uint8_t len) {
uint8_t tx_buf[len+1];
tx_buf[0] = 0x80 | (reg & 0x3F); // 读命令
memset(&tx_buf[1], 0x00, len);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, tx_buf, data, len+1, 100);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
// 复制有效数据
memmove(data, data+1, len);
}
// 初始化AD7124
void AD7124_Init(void) {
// 复位芯片
uint8_t reset_cmd[2] = {0xFF, 0xFF};
AD7124_WriteReg(REG_COMM, reset_cmd, 2);
HAL_Delay(10);
// 配置IO控制寄存器
uint8_t io_reg = 0x00; // 默认设置
AD7124_WriteReg(REG_IO, &io_reg, 1);
// 配置通道0 (热电偶)
uint8_t ch0_map[2] = {0x10, 0x80}; // 使能通道0,设置配置0
AD7124_WriteReg(REG_CH0_MAP, ch0_map, 2);
// 配置通道1 (Pt100)
uint8_t ch1_map[2] = {0x11, 0x91}; // 使能通道1,设置配置1
AD7124_WriteReg(REG_CH1_MAP, ch1_map, 2);
// 配置ADC控制寄存器
uint8_t mode_reg[2] = {0x01, 0x0000}; // 连续转换模式
AD7124_WriteReg(REG_MODE, mode_reg, 2);
// 配置滤波器0 (热电偶)
uint8_t filter0[2] = {0x28, 0x0600}; // 50Hz陷波,20SPS
AD7124_WriteReg(REG_FILTER0, filter0, 2);
// 配置滤波器1 (Pt100)
uint8_t filter1[2] = {0x29, 0x0600}; // 50Hz陷波,20SPS
AD7124_WriteReg(REG_FILTER1, filter1, 2);
// 配置配置0 (热电偶)
uint8_t cfg0[2] = {0x20, 0x860}; // 双极性,增益1,缓冲器开启
AD7124_WriteReg(REG_CFG0, cfg0, 2);
// 配置配置1 (Pt100)
uint8_t cfg1[2] = {0x21, 0x460}; // 双极性,增益8,缓冲器开启
AD7124_WriteReg(REG_CFG1, cfg1, 2);
}
// 读取ADC数据
int32_t AD7124_ReadData(void) {
uint8_t data[3];
AD7124_ReadReg(REG_DATA, data, 3);
// 组合24位数据
int32_t adc_value = (data[0] << 16) | (data[1] << 8) | data[2];
if (adc_value & 0x800000) {
adc_value |= 0xFF000000; // 符号扩展
}
return adc_value;
}
(2) 温度计算模块 (temperature.c)
#include "temperature.h"
#include "ad7124.h"
#include "math.h"
// 全局变量
float cold_junction_temp = 0.0f;
float thermocouple_voltage = 0.0f;
// Pt100分度表 (0-100℃)
const float pt100_table[] = {
100.00, 100.39, 100.78, 101.17, 101.56, 101.95, 102.34, 102.73, 103.12, 103.51,
103.90, 104.29, 104.68, 105.07, 105.46, 105.85, 106.24, 106.63, 107.02, 107.40,
107.79, 108.18, 108.57, 108.96, 109.35, 109.73, 110.12, 110.51, 110.90, 111.29,
111.67, 112.06, 112.45, 112.83, 113.22, 113.61, 114.00, 114.38, 114.77, 115.15,
115.54, 115.93, 116.31, 116.70, 117.08, 117.47, 117.85, 118.24, 118.62, 119.01,
119.39, 119.78, 120.16, 120.55, 120.93, 121.32, 121.70, 122.08, 122.47, 122.85,
123.24, 123.62, 124.00, 124.38, 124.77, 125.15, 125.53, 125.92, 126.30, 126.68,
127.06, 127.45, 127.83, 128.21, 128.59, 128.97, 129.36, 129.74, 130.12, 130.50,
130.88, 131.26, 131.64, 132.02, 132.40, 132.78, 133.16, 133.54, 133.92, 134.30,
134.68, 135.06, 135.43, 135.81, 136.19, 136.57, 136.95, 137.32, 137.70, 138.08
};
// 热电偶分度表 (K型,微伏)
const int32_t k_type_table[] = {
-9370, -9070, -8770, -8470, -8170, -7870, -7570, -7270, -6970, -6670,
-6370, -6070, -5770, -5470, -5170, -4870, -4570, -4270, -3970, -3670,
-3370, -3070, -2770, -2470, -2170, -1870, -1570, -1270, -970, -670,
-370, -70, 230, 530, 830, 1130, 1430, 1730, 2030, 2330,
2630, 2930, 3230, 3530, 3830, 4130, 4430, 4730, 5030, 5330,
5630, 5930, 6230, 6530, 6830, 7130, 7430, 7730, 8030, 8330,
8630, 8930, 9230, 9530, 9830, 10130, 10430, 10730, 11030, 11330,
11630, 11930, 12230, 12530, 12830, 13130, 13430, 13730, 14030, 14330,
14630, 14930, 15230, 15530, 15830, 16130, 16430, 16730, 17030, 17330,
17630, 17930, 18230, 18530, 18830, 19130, 19430, 19730, 20030, 20330
};
// 读取热电偶电压 (μV)
float ReadThermocoupleVoltage(void) {
int32_t adc_value = AD7124_ReadData(); // 通道0数据
// 转换为电压 (假设参考电压2.5V,增益1)
float voltage = (adc_value * 2.5f) / (16777216.0f * 1.0f); // 24位ADC
return voltage * 1000000; // 转换为μV
}
// 读取Pt100温度 (℃)
float ReadPt100Temperature(void) {
int32_t adc_value = AD7124_ReadData(); // 通道1数据
// 转换为电阻 (假设恒流源1mA,增益8)
float voltage = (adc_value * 2.5f) / (16777216.0f * 8.0f);
float resistance = voltage / 0.001f; // 1mA恒流源
// 查表法转换为温度
if (resistance >= 138.5f) return 100.0f; // 超出范围
if (resistance <= 100.0f) return 0.0f;
// 线性插值
int index = (int)((resistance - 100.0f) / 0.39f);
float frac = (resistance - 100.0f - index * 0.39f) / 0.39f;
return pt100_table[index] + frac * (pt100_table[index+1] - pt100_table[index]);
}
// 热电偶电压转温度 (K型)
float VoltageToTemperature(float voltage) {
// 简化版线性转换 (实际应使用分段多项式)
return voltage / 40.0f; // 近似斜率40μV/℃
}
// 冷端补偿计算
float ColdJunctionCompensation(float tc_voltage, float cj_temp) {
// 计算冷端温度下热电偶的理论电压
float cj_voltage = cj_temp * 40.0f; // 近似计算
// 补偿后的总电压
return tc_voltage + cj_voltage;
}
// 读取最终温度
float ReadFinalTemperature(void) {
// 读取热电偶电压 (μV)
thermocouple_voltage = ReadThermocoupleVoltage();
// 读取冷端温度 (℃)
cold_junction_temp = ReadPt100Temperature();
// 冷端补偿
float compensated_voltage = ColdJunctionCompensation(thermocouple_voltage, cold_junction_temp);
// 转换为温度
return VoltageToTemperature(compensated_voltage);
}
(3) 主程序 (main.c)
#include "main.h"
#include "ad7124.h"
#include "temperature.h"
#include "usart.h"
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
// 初始化AD7124
AD7124_Init();
while (1) {
// 读取最终温度
float temperature = ReadFinalTemperature();
// 串口输出
char msg[50];
sprintf(msg, "Temp: %.2f°C, CJ: %.2f°C, TC_V: %.2fμV\r\n",
temperature, cold_junction_temp, thermocouple_voltage);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 100);
HAL_Delay(1000); // 1秒更新一次
}
}
四、关键算法详解
1. 冷端补偿算法
// 精确冷端补偿算法
float PreciseColdJunctionCompensation(float tc_voltage, float cj_temp) {
// 使用K型热电偶的分度表进行精确补偿
// 1. 计算冷端温度对应的电压 (μV)
float cj_voltage = 0;
if (cj_temp <= 0) {
// 负温度区域 (简化)
cj_voltage = cj_temp * 41.0f; // 近似斜率
} else {
// 正温度区域 - 查表法
int index = (int)cj_temp;
float frac = cj_temp - index;
if (index < 0) index = 0;
if (index > 99) index = 99;
cj_voltage = k_type_table[index] +
frac * (k_type_table[index+1] - k_type_table[index]);
}
// 2. 补偿后的总电压
return tc_voltage + cj_voltage;
}
2. Pt100非线性校正
// Pt100非线性校正 (Callendar-Van Dusen方程)
float Pt100_NonlinearCorrection(float resistance) {
float R0 = 100.0f; // 0℃时的电阻
float A = 3.9083e-3f;
float B = -5.775e-7f;
float C = -4.183e-12f; // -200℃到0℃
if (resistance >= R0) {
// 0℃以上: R = R0(1 + At + Bt²)
return (-A + sqrtf(A*A - 4*B*(1 - resistance/R0))) / (2*B);
} else {
// 0℃以下: R = R0(1 + At + Bt² + Ct³)
float t = resistance/R0 - 1;
return (-A + sqrtf(A*A - 4*B*t*(1 - C*t))) / (2*B);
}
}
3. 热电偶非线性校正
// K型热电偶精确转换 (NIST ITS-90标准)
float KType_TempFromVoltage(float voltage_uv) {
// 转换为毫伏
float mv = voltage_uv / 1000.0f;
// 分段多项式拟合
if (mv >= -5.891 && mv <= 0.000) {
// -270℃到0℃
float c[] = {-0.176004136860e-01, 0.389212049750e-01, 0.185587700320e-04,
-0.994575928740e-07, 0.318409457190e-09, -0.560728448890e-12,
0.560750590590e-15, -0.320207200030e-18, 0.971511471520e-22,
-0.121047212750e-25};
float result = c[0];
float term = 1.0f;
for (int i = 1; i < 10; i++) {
term *= mv;
result += c[i] * term;
}
return result;
} else if (mv > 0.000 && mv <= 20.644) {
// 0℃到500℃
float c[] = {0.118597600000e+00, -0.118343200000e-03, 0.126968600000e+03};
return c[0] * mv + c[1] * mv*mv + c[2] * exp(0.1185976*mv);
} else if (mv > 20.644 && mv <= 54.886) {
// 500℃到1372℃
float c[] = {-0.170733818696e+01, 0.218782881065e-01, -0.241154992242e-04,
0.189276347362e-07, -0.916281112320e-11, 0.184143297689e-14,
-0.160520385013e+01, 0.148119787280e+01};
float result = c[0] + c[1]*mv + c[2]*mv*mv + c[3]*mv*mv*mv +
c[4]*mv*mv*mv*mv + c[5]*mv*mv*mv*mv*mv;
return result + c[6] * exp(c[7]*mv);
}
return 0.0f; // 超出范围
}
参考代码 热电偶采集温度源代码,AD7124热电偶+Pt100冷端补偿方案资料 www.youwenfan.com/contentcss/182465.html
五、系统优化
1. 多路采集优化
// 多路AD7124采集
#define NUM_CHANNELS 4
float ReadMultiChannelTemp(uint8_t channel) {
// 配置通道
uint8_t ch_map[2] = {0x10 | channel, 0x80 | (channel << 4)};
AD7124_WriteReg(REG_CH0_MAP, ch_map, 2);
// 启动转换
uint8_t mode_reg[2] = {0x01, 0x0001}; // 单次转换模式
AD7124_WriteReg(REG_MODE, mode_reg, 2);
// 等待转换完成
while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_SET);
// 读取数据
int32_t adc_value = AD7124_ReadData();
// 根据通道处理数据
if (channel == 0) {
return ProcessThermocouple(adc_value);
} else {
return ProcessPt100(adc_value);
}
}
2. 数字滤波算法
// 滑动平均滤波
#define FILTER_SIZE 5
float moving_avg_buf[FILTER_SIZE] = {0};
uint8_t avg_index = 0;
float MovingAverageFilter(float new_value) {
moving_avg_buf[avg_index] = new_value;
avg_index = (avg_index + 1) % FILTER_SIZE;
float sum = 0;
for (int i = 0; i < FILTER_SIZE; i++) {
sum += moving_avg_buf[i];
}
return sum / FILTER_SIZE;
}
// 中值滤波
#define MEDIAN_SIZE 5
float MedianFilter(float new_value) {
static float buffer[MEDIAN_SIZE] = {0};
static uint8_t index = 0;
buffer[index] = new_value;
index = (index + 1) % MEDIAN_SIZE;
// 复制并排序
float sorted[MEDIAN_SIZE];
memcpy(sorted, buffer, sizeof(buffer));
for (int i = 0; i < MEDIAN_SIZE-1; i++) {
for (int j = i+1; j < MEDIAN_SIZE; j++) {
if (sorted[i] > sorted[j]) {
float temp = sorted[i];
sorted[i] = sorted[j];
sorted[j] = temp;
}
}
}
return sorted[MEDIAN_SIZE/2];
}
六、测试与校准
1. 系统校准步骤
-
零点校准:
- 将热电偶和Pt100置于冰水混合物(0℃)
- 记录AD7124输出值
- 计算零点偏移量
-
满量程校准:
- 将热电偶和Pt100置于沸水(100℃)
- 记录AD7124输出值
- 计算满量程增益
-
冷端补偿校准:
- 在不同环境温度下测量冷端温度
- 与标准温度计比较
- 调整补偿算法参数
2. 测试数据
| 实际温度(℃) | 测量温度(℃) | 误差(℃) | 环境条件 |
|---|---|---|---|
| -50 | -49.8 | +0.2 | 室温25℃ |
| 0 | 0.1 | +0.1 | 冰水混合物 |
| 100 | 99.7 | -0.3 | 沸水 |
| 200 | 199.2 | -0.8 | 油浴 |
| 500 | 498.5 | -1.5 | 管式炉 |
七、项目资源
-
开发环境:STM32CubeIDE 1.8.0, HAL库
-
测试工具:Keil ULINK2, 恒温油槽, 标准铂电阻温度计
-
参考文档:
- AD7124 Datasheet (Rev. 0)
- NIST Monograph 175: Thermocouple Database
- IEC 60751: Platinum resistance thermometers