八路温度控制程序(基于STM32F103与MAX31855驱动)

一、系统概述

以STM32F103C8T6为主控,通过8路MAX31855热电偶数字转换器实现多路温度采集,结合PID控制算法驱动执行器(如加热/冷却装置),实现八路独立温度闭环控制。系统支持实时温度显示、故障诊断、参数设置,适用于工业烘箱、多区恒温箱、反应釜等场景。

二、硬件设计

2.1 核心组件选型

模块 型号/参数 功能说明
主控 STM32F103C8T6(72MHz,64KB Flash) 8路SPI通信、温度数据处理、PID控制、执行器驱动
温度采集 8×MAX31855(SPI接口,K型热电偶) 采集8路温度(范围-270~+1800℃,精度±0.5℃)
执行器 8路继电器/PWM输出(加热/冷却) 根据温度偏差控制加热/冷却(如SSR固态继电器)
显示 0.96寸OLED(I2C,SSD1306) 显示8路温度、设定值、故障状态
存储 AT24C02(I2C EEPROM,2KB) 掉电保存PID参数、温度设定值

2.2 硬件连接

模块 STM32F103引脚 说明
MAX31855(8路) SCK→PA5(SPI1_SCK) SPI时钟(共用)
SO→PA6(SPI1_MISO) SPI数据输出(共用)
CS0→PA4,CS1→PA3,...,CS7→PB0 8路独立片选(GPIO控制)
VCC→3.3V,GND→GND 电源与地
执行器 PB1~PB8(8路PWM/IO) 控制加热/冷却(如PWM占空比调节)
OLED PB6(SCL),PB7(SDA) I2C显示接口

三、软件设计(STM32 HAL库)

3.1 开发环境

  • IDE:STM32CubeIDE 1.13.0+

  • :STM32Cube_FW_F1_V1.8.0(HAL库)

  • 工具链:GCC ARM Embedded

3.2 核心原理

  1. MAX31855通信:通过SPI接口读取16位数据(14位温度+2位故障码),数据格式为高位在前(MSB),温度分辨率0.25℃。

  2. 多路管理:循环切换8路片选(CS),分时读取各传感器数据,避免总线冲突。

  3. PID控制:对每路温度独立计算偏差(设定值-实际值),通过PID算法输出控制量(0~100%占空比)。

3.3 核心代码实现

3.3.1 MAX31855驱动(单路读取)

#include "max31855.h"
#include "spi.h"
#include "gpio.h"

// 片选引脚定义(8路)
#define CS0_PIN GPIO_PIN_4
#define CS0_PORT GPIOA
#define CS1_PIN GPIO_PIN_3
#define CS1_PORT GPIOA
// ... 省略CS2~CS7定义(依次对应PA2、PA1、PA0、PB5、PB4、PB3、PB0)

// 读取单路MAX31855数据(返回温度值,单位℃;故障返回NaN)
float MAX31855_Read(uint8_t ch) {
    uint8_t tx_buf[2] = {0xFF, 0xFF};  // 发送dummy字节(16位)
    uint8_t rx_buf[2] = {0};
    GPIO_TypeDef* cs_port;
    uint16_t cs_pin;
    
    // 根据通道选择片选引脚
    switch(ch) {
        case 0: cs_port=CS0_PORT; cs_pin=CS0_PIN; break;
        case 1: cs_port=CS1_PORT; cs_pin=CS1_PIN; break;
        // ... 省略ch2~ch7的片选配置
        default: return 0.0f/0.0f;  // 无效通道返回NaN
    }
    
    // 拉低片选
    HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_RESET);
    // SPI接收16位数据(MSB在前)
    HAL_SPI_TransmitReceive(&hspi1, tx_buf, rx_buf, 2, 100);
    // 拉高片选
    HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_SET);
    
    // 解析数据(16位:D15~D2=温度,D1=热电偶故障,D0=断偶故障)
    uint16_t data = (rx_buf[0] << 8) | rx_buf[1];
    if (data & 0x0001) return 0.0f/0.0f;  // 断偶故障
    if (data & 0x0002) return 0.0f/0.0f;  // 热电偶故障
    
    // 温度计算(14位有符号数,0.25℃/LSB)
    int16_t temp_raw = (int16_t)(data >> 2);  // 右移2位,保留14位
    return temp_raw * 0.25f;  // 单位:℃
}

3.3.2 八路温度采集与PID控制

// PID控制器结构体(每路独立)
typedef struct {
    float Kp, Ki, Kd;    // PID参数
    float setpoint;      // 设定温度
    float integral;      // 积分项
    float prev_error;    // 上次偏差
} PID_TypeDef;

// 全局变量
PID_TypeDef pid[8];  // 8路PID控制器
float temp[8];        // 8路实际温度
float output[8];      // 8路控制输出(0~100%)

// PID计算函数
void PID_Compute(PID_TypeDef *pid, float actual, float *output) {
    float error = pid->setpoint - actual;
    pid->integral += error * 0.1f;  // 采样周期0.1s
    float derivative = (error - pid->prev_error) / 0.1f;
    *output = pid->Kp*error + pid->Ki*pid->integral + pid->Kd*derivative;
    // 限幅(0~100%)
    if (*output > 100.0f) *output = 100.0f;
    if (*output < 0.0f) *output = 0.0f;
    pid->prev_error = error;
}

// 主循环(每0.1s执行一次)
void Temperature_Control_Loop(void) {
    for (uint8_t ch=0; ch<8; ch++) {
        // 1. 读取温度
        temp[ch] = MAX31855_Read(ch);
        if (isnan(temp[ch])) {
            // 故障处理(关闭执行器,报警)
            HAL_GPIO_WritePin(HEATER_PORT, HEATER_PIN[ch], GPIO_PIN_RESET);
            continue;
        }
        
        // 2. PID计算
        PID_Compute(&pid[ch], temp[ch], &output[ch]);
        
        // 3. 执行器控制(PWM输出)
        __HAL_TIM_SET_COMPARE(&htimx, TIM_CHANNEL_x[ch], (uint16_t)(output[ch] * 10));  // 假设PWM周期1000,占空比0~1000
    }
}

3.3.3 SPI与GPIO初始化(CubeMX配置)

// SPI1初始化(8MHz,全双工,MSB先行)
void MX_SPI1_Init(void) {
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;  // 只读(MAX31855无MOSI数据)
    hspi1.Init.DataSize = SPI_DATASIZE_16BIT;  // 16位数据
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;  // 时钟极性(MAX31855:SCK空闲低)
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;     // 第一个边沿采样(MAX31855:SCK下降沿输出数据)
    hspi1.Init.NSS = SPI_NSS_SOFT;             // 软件控制片选
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;  // 72MHz/8=9MHz(MAX31855支持≤5.5MHz,需降为4分频=18MHz/4=4.5MHz)
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    HAL_SPI_Init(&hspi1);
}

// GPIO初始化(片选引脚)
void MX_GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    // 片选引脚(PA4~PA0,PB5~PB0)
    uint16_t cs_pins[] = {GPIO_PIN_4, GPIO_PIN_3, GPIO_PIN_2, GPIO_PIN_1, GPIO_PIN_0, GPIO_PIN_5, GPIO_PIN_4, GPIO_PIN_0};
    GPIO_TypeDef* cs_ports[] = {GPIOA, GPIOA, GPIOA, GPIOA, GPIOA, GPIOB, GPIOB, GPIOB};
    
    for (int i=0; i<8; i++) {
        GPIO_InitStruct.Pin = cs_pins[i];
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(cs_ports[i], &GPIO_InitStruct);
        HAL_GPIO_WritePin(cs_ports[i], cs_pins[i], GPIO_PIN_SET);  // 初始高电平(未选中)
    }
}

参考代码 八路温度控制程序,max31855 stm32F103驱动程序 www.youwenfan.com/contentcnt/182694.html

四、关键问题与解决方案

4.1 多路SPI通信冲突

  • 问题:8路MAX31855共用SCK/MISO,分时切换片选时可能出现数据错位。

  • 解决

    • 片选切换后添加10μs延时,确保从设备就绪;

    • 使用SPI DMA传输,减少CPU干预,提高稳定性。

4.2 温度数据跳变

  • 问题:热电偶干扰或MAX31855噪声导致温度值突变。

  • 解决

    • 软件添加滑动平均滤波(如取5次采样的平均值);

    • 硬件在SO引脚加10kΩ上拉电阻,并联0.1μF滤波电容。

4.3 PID参数整定

  • 问题:多路温度控制参数难统一,易出现超调或震荡。

  • 解决

    • 为每路独立设置PID参数(通过AT24C02存储);

    • 采用自适应PID(根据偏差大小动态调整Kp/Ki/Kd)。

五、测试与验证

  1. 单路测试:接入K型热电偶,对比标准温度计,误差<±1℃(0~100℃范围)。

  2. 多路同步:8路同时采集,数据刷新率>1Hz,无丢包。

  3. 控制效果:设定温度50℃,8路温度稳定在49.5~50.5℃,超调<2℃。

六、总结

基于STM32F103实现了八路温度采集与PID控制,核心是多路SPI分时通信、MAX31855数据解析与独立PID控制。通过模块化设计,可扩展Modbus通信、Web远程监控等功能,满足多区精密温控需求。

posted @ 2026-04-06 11:23  cozicx  阅读(8)  评论(0)    收藏  举报