基于STM32单片机的温度控制系统 可实现功能: 1、DS18B20监测环境温度,显示在LCD1602上 2、可以设置温度上下限 3、可以控制加热或者降温 4、超过限制温度用LED或者蜂鸣器进行提示 包含: 仿真、程序、参考报告

最近在实验室折腾了个基于STM32的温度控制系统,核心思路就是通过DS18B20实时测温,配合继电器控制加热制冷设备。调试过程中发现这玩意虽然功能简单,但各种坑真是踩了个遍,今天就把实战经验整理出来,给想自己做温控的朋友避避雷。

硬件方案

整个系统最核心的就是STM32F103C8T6这片性价比神U,配了LCD1602显示当前温度和设定阈值。DS18B20用单总线接在PA0,注意这里必须接4.7K上拉电阻,之前偷懒没接结果温度读数乱跳。报警模块用了有源蜂鸣器接PB8,控制端用PC13的LED做状态指示。加热和制冷分别通过两个继电器控制,接在PB12和PB13,记得加三极管驱动电路。

温度采集的坑

DS18B20的时序要求比较严格,刚开始用库函数直接操作总是超时,后来改用寄存器操作才稳定:

//DS18B20复位函数
uint8_t DS18B20_Reset(void){
    GPIO_InitTypeDef gpio;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    gpio.GPIO_Pin = GPIO_Pin_0;
    gpio.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_Init(GPIOA, &gpio);
    
    GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    delay_us(750); //保持480-960us
    GPIO_SetBits(GPIOA, GPIO_Pin_0);
    delay_us(15);
    
    gpio.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &gpio);
    while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)); //等待总线释放
    return 1;
}

这段代码的关键在于模式切换——先配置为开漏输出拉低总线,然后切回上拉输入检测响应。调试时用逻辑分析仪抓波形发现,温度转换时间不足会导致读取到前次数据,后来在启动转换后加了750ms延时才解决。

基于STM32单片机的温度控制系统 可实现功能: 1、DS18B20监测环境温度,显示在LCD1602上 2、可以设置温度上下限 3、可以控制加热或者降温 4、超过限制温度用LED或者蜂鸣器进行提示 包含: 仿真、程序、参考报告

PID控制实现

温控的核心算法用了位置式PID,参数整定过程简直要命。先上核心代码:

float PID_Control(float set_temp, float real_temp){
    static float errSum=0, lastErr=0;
    float err = set_temp - real_temp;
    errSum += err;
    float dErr = err - lastErr;
    lastErr = err;
    
    float output = Kp*err + Ki*errSum + Kd*dErr;
    
    //抗积分饱和处理
    if(output > MAX_OUTPUT){
        output = MAX_OUTPUT;
        errSum -= err; //回退积分
    }
    else if(output < MIN_OUTPUT){
        output = MIN_OUTPUT;
        errSum -= err;
    }
    return output;
}

实际调试发现当温差较大时积分项会累积导致超调,后来加了抗饱和处理才稳定。建议先用Z-N法整定参数,现场调试时先调P再调I最后调D,实验室环境最终用Kp=3.5, Ki=0.2, Kd=1.2效果不错。

人机交互设计

按键设置部分用了状态机处理长按加速:

//按键扫描状态机
void Key_Process(){
    static uint8_t key_cnt[3] = {0};
    for(int i=0; i<3; i++){
        if(KEY_State(i) == 0){
            if(++key_cnt[i] > 100){ //长按1秒后加速
                set_temp += (i==0)?1:-1;
                key_cnt[i] = 95; //保持加速节奏
            }
            else if(key_cnt[i] == 1){
                set_temp += (i==0)?1:-1; //短按步进1
            }
            LCD_UpdateFlag = 1;
        }
        else key_cnt[i] = 0;
    }
}

这里有个细节处理——长按超过1秒后每100ms调整一次数值,比直接累加体验好很多。LCD显示部分注意温度值要格式化成固定宽度,避免数字跳动影响观看。

系统联调经验

  1. 继电器控制务必加续流二极管,现场烧了两个三极管才长记性
  2. DS18B20走线要远离继电器等干扰源
  3. 系统上电先初始化GPIO再配置外设,否则可能出现IO状态冲突
  4. 最终在Proteus仿真时发现实际加热惯性比模拟的大,需要增大微分系数

完整工程里包含带注释的源码、仿真文件和调试记录,在实测中室温到50℃的升温过程控制精度能达到±0.5℃,降温由于用了半导体制冷片存在滞后,需要加入模糊控制改进,这个等下次有空再折腾了。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐