热电偶采集温度源代码(AD7124 + Pt100冷端补偿方案)

热电偶采集温度源代码(AD7124 + Pt100冷端补偿方案)

一、系统概述

本方案使用AD7124高精度Σ-Δ ADC同时采集热电偶信号和Pt100冷端温度,实现高精度温度测量。系统包含:

系统通过硬件同步采集热电偶电压和冷端温度,软件实现冷端补偿算法,最终输出精确的热端温度。

二、硬件设计

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. 系统校准步骤

  1. 零点校准

    • 将热电偶和Pt100置于冰水混合物(0℃)
    • 记录AD7124输出值
    • 计算零点偏移量
  2. 满量程校准

    • 将热电偶和Pt100置于沸水(100℃)
    • 记录AD7124输出值
    • 计算满量程增益
  3. 冷端补偿校准

    • 在不同环境温度下测量冷端温度
    • 与标准温度计比较
    • 调整补偿算法参数

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 管式炉

七、项目资源

专注于matlab/simulink,电子电路,编程