基于 STM32F103C8T6 的恒定水温控制系统

一、系统总体设计

1、系统架构

复制代码
┌─────────────────────────────────────────────────────────┐
│                  恒定水温控制系统                        │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐  │
│  │  温度采集层  │    │  控制算法层  │    │  执行控制层  │  │
│  │             │    │             │    │             │  │
│  │ • DS18B20   │───▶│ • PID控制   │───▶│ • PWM加热   │  │
│  │ • NTC热敏电阻│    │ • 自适应调节 │    │ • 固态继电器 │  │
│  │ • 滤波算法  │    │ • 抗积分饱和 │    │ • 散热风扇  │  │
│  └─────────────┘    └─────────────┘    └─────────────┘  │
│                                                         │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐  │
│  │  人机交互层  │    │  系统监控层  │    │  通信接口层  │  │
│  │             │    │             │    │             │  │
│  │ • OLED显示  │    │ • 超温保护  │    │ • USART     │  │
│  │ • 按键设置  │    │ • 传感器诊断 │    │ • RS485     │  │
│  │ • LED指示   │    │ • 故障报警  │    │ • WiFi可选  │  │
│  └─────────────┘    └─────────────┘    └─────────────┘  │
└─────────────────────────────────────────────────────────┘

2、技术指标

参数 指标
控温范围 20°C ~ 90°C
控温精度 ±0.5°C
稳定时间 < 5分钟
加热功率 500W ~ 2000W
显示分辨率 0.1°C
工作电压 AC 220V / DC 12V

二、硬件设计

1、核心器件选型

器件 型号 说明
MCU STM32F103C8T6 72MHz,64KB Flash,20KB RAM
温度传感器 DS18B20 数字输出,-55°C~125°C,±0.5°C
备用传感器 NTC 10K 模拟输出,高精度
加热元件 不锈钢加热管 1000W/1500W,220V
功率控制 SSR-40DA 固态继电器,40A/250VAC
显示模块 OLED 128x64 I2C接口,0.96寸
电源模块 HLK-PM12 AC220V转DC12V
散热风扇 5015直流风扇 12V,用于过热保护

2、硬件连接图

复制代码
STM32F103C8T6 引脚分配:
┌─────────────────────────────────────────────┐
│  GPIOA                                      │
│  PA0  ── NTC_ANALOG    (ADC1_IN0)           │
│  PA1  ── HEATER_PWM    (TIM2_CH2)           │
│  PA2  ── FAN_PWM       (TIM2_CH3)           │
│  PA3  ── DS18B20_DQ     (单总线)            │
│  PA4  ── OLED_CS        (SPI1_NSS)          │
│  PA5  ── OLED_SCK       (SPI1_SCK)          │
│  PA6  ── OLED_MISO      (SPI1_MISO)         │
│  PA7  ── OLED_MOSI      (SPI1_MOSI)         │
│  PA8  ── KEY_SET        (按键设置)          │
│  PA9  ── USART1_TX      (调试输出)          │
│  PA10 ── USART1_RX      (调试输入)          │
│                                             │
│  GPIOB                                      │
│  PB0  ── KEY_UP          (按键+)            │
│  PB1  ── KEY_DOWN        (按键-)            │
│  PB6  ── OLED_SDA        (I2C1_SDA)         │
│  PB7  ── OLED_SCL        (I2C1_SCL)         │
│  PB8  ── ALARM_LED       (报警指示)         │
│  PB9  ── STATUS_LED      (状态指示)         │
└─────────────────────────────────────────────┘

3、关键电路设计

加热控制电路
复制代码
STM32 PA1 ──┬── 1kΩ ──┬── SSR控制端+
            │          │
            └── 10kΩ ──┴── SSR控制端-
                           │
AC 220V ──── 加热管 ──── SSR负载端 ─── AC 220V
温度采集电路
复制代码
DS18B20:
VDD ── 3.3V
DQ  ── PA3 (需4.7kΩ上拉)
GND ── GND

NTC 10K:
3.3V ── 10kΩ ──┬── PA0 (ADC)
               │
               └── NTC ── GND

三、软件系统设计

1、系统状态机

c 复制代码
typedef enum {
    SYS_INIT = 0,        // 系统初始化
    SYS_IDLE,            // 空闲状态
    SYS_HEATING,         // 加热状态
    SYS_STABLE,          // 恒温状态
    SYS_COOLING,         // 降温状态
    SYS_ALARM,           // 报警状态
    SYS_MAINTENANCE      // 维护状态
} System_State_t;

2、PID 控制器设计

c 复制代码
/* PID 控制器结构体 */
typedef struct {
    float Kp;            // 比例系数
    float Ki;            // 积分系数
    float Kd;            // 微分系数
    
    float target;        // 目标温度
    float feedback;      // 反馈温度
    float error;         // 当前误差
    float error_last;    // 上次误差
    float integral;      // 积分项
    float derivative;    // 微分项
    float output;        // 控制器输出
    
    float out_max;       // 输出上限
    float out_min;       // 输出下限
    float integral_max;  // 积分限幅
} PID_Controller_t;

3、主程序框架

c 复制代码
#include "stm32f10x.h"
#include "ds18b20.h"
#include "oled.h"
#include "pid.h"
#include "heater.h"

/* 全局变量 */
System_State_t system_state = SYS_INIT;
PID_Controller_t temp_pid;
float current_temp = 0.0f;
float target_temp = 60.0f;  // 默认目标温度60°C

int main(void)
{
    /* 系统初始化 */
    System_Init();
    
    /* PID 初始化 */
    PID_Init(&temp_pid);
    
    while(1) {
        /* 温度采集 */
        current_temp = DS18B20_GetTemp();
        
        /* 系统状态机 */
        switch(system_state) {
            case SYS_INIT:
                System_Init_Process();
                break;
                
            case SYS_HEATING:
                Heating_Process();
                break;
                
            case SYS_STABLE:
                Stable_Process();
                break;
                
            case SYS_ALARM:
                Alarm_Process();
                break;
                
            default:
                break;
        }
        
        /* 显示更新 */
        Display_Update();
        
        /* 延时 */
        Delay_ms(100);
    }
}

4、PID 控制器实现

c 复制代码
#include "pid.h"

/* PID 初始化 */
void PID_Init(PID_Controller_t *pid)
{
    pid->Kp = 25.0f;        // 比例系数
    pid->Ki = 0.8f;         // 积分系数
    pid->Kd = 120.0f;       // 微分系数
    
    pid->out_max = 100.0f;  // 输出限幅100%
    pid->out_min = 0.0f;
    pid->integral_max = 50.0f;
    
    pid->integral = 0.0f;
    pid->error_last = 0.0f;
}

/* PID 计算 */
float PID_Calculate(PID_Controller_t *pid, float target, float feedback)
{
    pid->target = target;
    pid->feedback = feedback;
    pid->error = target - feedback;
    
    /* 比例项 */
    float proportional = pid->Kp * pid->error;
    
    /* 积分项(带抗积分饱和) */
    pid->integral += pid->Ki * pid->error;
    if(pid->integral > pid->integral_max)
        pid->integral = pid->integral_max;
    if(pid->integral < -pid->integral_max)
        pid->integral = -pid->integral_max;
    
    /* 微分项 */
    pid->derivative = pid->Kd * (pid->error - pid->error_last);
    pid->error_last = pid->error;
    
    /* PID 输出 */
    pid->output = proportional + pid->integral + pid->derivative;
    
    /* 输出限幅 */
    if(pid->output > pid->out_max)
        pid->output = pid->out_max;
    if(pid->output < pid->out_min)
        pid->output = pid->out_min;
    
    return pid->output;
}

5、加热器控制

c 复制代码
#include "heater.h"

/* 加热器初始化 */
void Heater_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    /* PWM 定时器配置 */
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    
    TIM_TimeBaseStructure.TIM_Period = 999;        // PWM周期 1kHz
    TIM_TimeBaseStructure.TIM_Prescaler = 71;      // 72MHz/72 = 1MHz
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_Cmd(TIM2, ENABLE);
}

/* 设置加热功率 */
void Heater_SetPower(float power_percent)
{
    uint16_t pwm_value;
    
    if(power_percent > 100.0f) power_percent = 100.0f;
    if(power_percent < 0.0f) power_percent = 0.0f;
    
    pwm_value = (uint16_t)(power_percent * 10.0f);  // 0-1000
    TIM_SetCompare2(TIM2, pwm_value);
}

6、温度采集(DS18B20)

c 复制代码
#include "ds18b20.h"

/* DS18B20 初始化 */
uint8_t DS18B20_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    DS18B20_Reset();
    return DS18B20_Check();
}

/* 获取温度 */
float DS18B20_GetTemp(void)
{
    uint8_t temp_l, temp_h;
    int16_t temp;
    float temperature;
    
    DS18B20_Start();
    DS18B20_WriteByte(0xCC);  // Skip ROM
    DS18B20_WriteByte(0xBE);  // Read Scratchpad
    
    temp_l = DS18B20_ReadByte();
    temp_h = DS18B20_ReadByte();
    
    temp = (temp_h << 8) | temp_l;
    temperature = (float)temp * 0.0625f;
    
    return temperature;
}

7、OLED 显示界面

c 复制代码
#include "oled.h"

/* 显示主界面 */
void Display_MainInterface(float current_temp, float target_temp, System_State_t state)
{
    char buffer[20];
    
    OLED_Clear();
    
    /* 显示标题 */
    OLED_ShowString(0, 0, "Water Temp Ctrl");
    
    /* 显示当前温度 */
    sprintf(buffer, "Now: %.1f C", current_temp);
    OLED_ShowString(0, 2, buffer);
    
    /* 显示目标温度 */
    sprintf(buffer, "Set: %.1f C", target_temp);
    OLED_ShowString(0, 4, buffer);
    
    /* 显示系统状态 */
    switch(state) {
        case SYS_HEATING:
            OLED_ShowString(0, 6, "Status: HEATING");
            break;
        case SYS_STABLE:
            OLED_ShowString(0, 6, "Status: STABLE ");
            break;
        case SYS_ALARM:
            OLED_ShowString(0, 6, "Status: ALARM  ");
            break;
        default:
            OLED_ShowString(0, 6, "Status: IDLE   ");
            break;
    }
}

四、高级功能实现

1、自适应 PID 参数调整

c 复制代码
/* 自适应 PID 调整 */
void Adaptive_PID_Adjust(PID_Controller_t *pid, float error)
{
    static float error_history[10];
    static uint8_t index = 0;
    
    /* 存储误差历史 */
    error_history[index] = fabsf(error);
    index = (index + 1) % 10;
    
    /* 计算平均误差 */
    float avg_error = 0;
    for(int i = 0; i < 10; i++) {
        avg_error += error_history[i];
    }
    avg_error /= 10;
    
    /* 根据误差调整 PID 参数 */
    if(avg_error > 5.0f) {           // 大误差,增强比例作用
        pid->Kp = 35.0f;
        pid->Ki = 0.5f;
        pid->Kd = 80.0f;
    } else if(avg_error > 2.0f) {    // 中等误差
        pid->Kp = 25.0f;
        pid->Ki = 0.8f;
        pid->Kd = 120.0f;
    } else {                         // 小误差,增强积分作用
        pid->Kp = 15.0f;
        pid->Ki = 1.2f;
        pid->Kd = 150.0f;
    }
}

2、安全保护机制

c 复制代码
/* 安全监控 */
void Safety_Monitor(float current_temp, float target_temp)
{
    static uint32_t overheat_time = 0;
    
    /* 超温保护 */
    if(current_temp > 95.0f) {
        Heater_SetPower(0);  // 立即关闭加热
        system_state = SYS_ALARM;
        Alarm_Trigger(ALARM_OVERHEAT);
        return;
    }
    
    /* 传感器故障检测 */
    if(current_temp < -50.0f || current_temp > 150.0f) {
        system_state = SYS_ALARM;
        Alarm_Trigger(ALARM_SENSOR_FAULT);
        return;
    }
    
    /* 长时间未达目标温度报警 */
    if(fabsf(current_temp - target_temp) > 10.0f) {
        if(overheat_time == 0) {
            overheat_time = HAL_GetTick();
        } else if(HAL_GetTick() - overheat_time > 1800000) {  // 30分钟
            system_state = SYS_ALARM;
            Alarm_Trigger(ALARM_HEATING_TIMEOUT);
            overheat_time = 0;
        }
    } else {
        overheat_time = 0;
    }
}

3、数据记录与统计

c 复制代码
/* 温度数据记录 */
typedef struct {
    uint32_t timestamp;
    float temperature;
    float target_temp;
    float heating_power;
    System_State_t state;
} Temp_Record_t;

#define MAX_RECORDS 100
Temp_Record_t temp_records[MAX_RECORDS];
uint16_t record_index = 0;

void Record_Temperature(float temp, float target, float power, System_State_t state)
{
    temp_records[record_index].timestamp = HAL_GetTick();
    temp_records[record_index].temperature = temp;
    temp_records[record_index].target_temp = target;
    temp_records[record_index].heating_power = power;
    temp_records[record_index].state = state;
    
    record_index = (record_index + 1) % MAX_RECORDS;
}

参考代码 基于STM32F103C8T6的恒定水温控制系统 www.youwenfan.com/contentcsv/72753.html

五、系统调试与优化

1、PID 参数整定步骤

复制代码
1. 纯比例控制(Ki=0, Kd=0)
   - 从小到大调整 Kp,直到系统出现小幅振荡
   - 记录临界比例度 Ku 和振荡周期 Tu
   
2. Ziegler-Nichols 整定法
   Kp = 0.6 * Ku
   Ki = 1.2 * Ku / Tu
   Kd = 0.075 * Ku * Tu
   
3. 微调优化
   - 响应过快:减小 Kp,增大 Kd
   - 稳态误差大:增大 Ki
   - 振荡严重:减小 Kp,增大 Kd

2、性能测试指标

测试项目 测试方法 合格标准
稳态精度 设定60°C,稳定后测量 ±0.5°C
动态响应 从30°C升至60°C < 5分钟
抗干扰性 加入冷水扰动 恢复时间<2分钟
长期稳定性 连续运行24小时 温度漂移<1°C
安全保护 人为制造超温 立即切断加热

六、扩展功能建议

1、远程监控(可选)

c 复制代码
/* WiFi 模块通信 */
void ESP8266_Send_Temp_Data(float temp, float target)
{
    char json_buffer[100];
    sprintf(json_buffer, 
            "{\"temp\":%.1f,\"target\":%.1f,\"status\":%d}",
            temp, target, system_state);
    
    USART_SendString(USART1, "AT+CIPSEND=0,");
    USART_SendString(USART1, json_buffer);
}

2、多段温控程序

c 复制代码
/* 多段温控 */
typedef struct {
    float target_temp;
    uint32_t hold_time;    // 保持时间(秒)
    uint32_t ramp_time;    // 升温时间(秒)
} Temp_Segment_t;

Temp_Segment_t temp_program[5] = {
    {40.0f, 300, 120},     // 40°C,保持5分钟,2分钟升温
    {60.0f, 600, 180},     // 60°C,保持10分钟,3分钟升温
    {80.0f, 300, 120},     // 80°C,保持5分钟,2分钟升温
    {60.0f, 600, 180},     // 降温到60°C
    {40.0f, 300, 120}      // 最终40°C
};
相关推荐
JNX_SEMI1 小时前
EG2129带过流保护全桥驱动芯片:600V耐压双路比较器,硬件级过流保护让全桥设计更安全
单片机·嵌入式硬件
崇山峻岭之间1 小时前
单片机USmart实验
单片机·嵌入式硬件
SmartRadio1 小时前
STM32WLE5 Smart TDMA 完整工程(STOP2 低功耗终极版)-【10】
stm32·单片机·lora·tdma·低功耗自组网·smart tdma
国科安芯1 小时前
AS32S601芯片抗辐照性能试验验证与空间环境适应性分析
前端·分布式·单片机·嵌入式硬件·架构·risc-v·安全性测试
sxstj2 小时前
stm32最小板和uno I2C能直接连接吗?
stm32·单片机·嵌入式硬件
sxstj2 小时前
5伏的传感器能直接在stm32上使用吗?
stm32·单片机·嵌入式硬件
搁浅小泽2 小时前
SCM、MCU、SoC 三者区别与详解
单片机·嵌入式硬件
Silicore_Emma2 小时前
芯谷科技—D3815 40V/0.8A 高调光比LED恒流驱动器
单片机·消费电子·芯谷科技·智能家居系统·恒流驱动器·控制器电路·智能照明设备
jllllyuz2 小时前
STM8S 系列单片机 + RC522读写 IC 卡
单片机·嵌入式硬件·mongodb