恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

温室温湿度 PID 闭环控制:STM32/ESP32 增量式实现

  • 首页
  • 资讯中心
  • /
  • 温室温湿度 PID 闭环控制:STM32/ESP32 增量式实现

相关资讯

Obsidian + Git 在 Mac 上构建知识版本化系统 2026/9/20 12:30:33
Linux系统负载与性能监控:load average、top、vmstat、iostat排查指南 2026/9/20 12:30:33
爱聊App一对一视频相亲交友源码:可运营社交系统完整拆解 2026/9/20 12:30:33

最新资讯

n8n实战:如何用开源工作流工具实现公众号运营自动化
AssetRipper资产提取快速指南
hwinfo64免费版使用指南:用传感器数据精准排查硬件故障
华为IFS财经变革启示:业财融合与流程重构的落地路径
BrewUI:给 Homebrew 套上图形界面,让 macOS 软件管理不再依赖命令行
实测降AIGC平台效果!实测下来谁更胜一筹?

今日推荐

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

温室温湿度 PID 闭环控制:STM32/ESP32 增量式实现

发布时间:2026/9/20 12:30:33
温室温湿度 PID 闭环控制:STM32/ESP32 增量式实现 简介围绕PID算法在温室环境调控中的应用这份技术文献以单篇PDF形式呈现面向自动化、智慧农业与嵌入式控制方向的学习者及研究人员回应传统温湿度控制系统精度偏低、稳定性不足的问题。包内仅1个PDF文件约1.44MB为完整论文版式依次展开摘要、硬件设计、软件设计、实验对比与参考文献等模块。硬件部分给出SLZ2016-558微处理器、TL-W温度传感器、TL-N湿度传感器及电源电路的选型与性能指标软件部分说明如何以温湿度为目标函数通过参数编码、解码与误差调节完成PID算法落地实验环节以葡萄种植温室8小时采集数据对比传统系统验证控制精度可达80%以上、最优约90%。目前已有331人学习。读者可据此借鉴硬件架构、算法实现步骤与实验验证思路适合毕业设计、课程论文及智慧农业控制系统方案参考兼具专业指导与参考文献价值。1. 温室温湿度控制为什么要用 PID 算法做闭环凌晨三点棚内温度从 18℃ 掉到 13.5℃湿度因为叶面蒸腾爬到 93%值班的人只能看一眼手机再手动开加热和风机。用开关量做温湿度控制加热器要么全开要么全关温度在设定值上下 2~3℃ 来回振荡湿度更糟除湿一停就反弹这就是典型的继电特性震荡。问题不在执行器在控制律。PID 算法做的事情很朴素把当前温湿度偏离目标多少、偏离持续了多久、偏离得有多快这三件事加权求和换算成一个连续输出量送给加热片、加湿器、风机和湿帘。一套能长期无人值守跑起来的温湿度智能控制系统核心就是这条闭环。下面针对的读者是已经能读传感器、能驱动继电器但回路一上电就震荡、或者半天拉不回设定值的嵌入式与物联网工程师STMicroelectronics 与 Espressif 两条常见硬件路线的参数和代码都会给到。2. 温湿度被控对象建模与 PID 算法选型2.1 温室温湿度对象的动态特性近似调参之前先搞清楚被控对象长什么样。温室温度回路的阶跃响应可以近似成一阶惯性加纯滞后G(s) K / (T·s 1) · e^(-τ·s)K 是静态增益单位是「℃/输出百分比」实测方法是让加热输出从 30% 阶跃到 70%等温度稳定后看温升除以输出变化量。T 是时间常数取温度走完阶跃总变化量 63% 所需的时间。τ 是纯滞后从输出变化的时刻算起到温度传感器第一次出现可辨识变化为止温室里通常在 60~300 秒量级取决于传感器位置和空气循环。湿度回路更麻烦。相对湿度不是独立变量它随温度反向变化温度每升高 1℃在含湿量不变的前提下相对湿度大约下降 4%~6%。这意味着加热回路一动湿度回路立刻被扰动两个回路天然耦合。空气循环差的小棚里这个耦合强度足以让两个独立 PID 互相打架——加热一开湿度跌到下限加湿一开温度又掉下来。我一般的处理是先按两个独立回路整定把加热/加湿的触发在时间上错开至少一个采样周期观察是否出现交替震荡如果出现再引入耦合补偿项把温度偏差的符号和幅值折算成一个湿度设定值修正量。多数中小型温室做到这一步就够用了不必上完整的解耦控制。2.2 位置式 PID 与增量式 PID 算法在嵌入式上的取舍位置式公式u(k) Kp·e(k) Ki·Σe(j)·dt Kd·(e(k) - e(k-1))/dt增量式公式Δu Kp·(e(k) - e(k-1)) Ki·e(k)·dt Kd·(e(k) - 2e(k-1) e(k-2))/dt u(k) u(k-1) Δu两者数学上等价工程上差别很大。位置式每一步都要对偏差做累加累加项一旦因为输出限幅而饱和退饱和时会带出一大段超调增量式只累加输出量本身限幅时把输出回写即可抗饱和天然容易。另外增量式在手动转自动时只要保持 u(k-1) 连续就不会有阀门或继电器被「跳一下」的问题这一点在温室这种需要人工干预的场景里很关键。我通常的做法是温度回路用增量式湿度回路也用增量式只有在需要直接观察绝对输出量比如调试阶段记录占空比曲线时才临时切到位置式。/* 增量式 PID输出为累积占空比范围 0 ~ 1000 */ typedef struct { float Kp, Ki, Kd; float e1, e2; /* 上两次偏差 */ float out; /* 累积输出必须长期保存 */ float out_min, out_max; /* 输出限幅对应执行器有效区间 */ } PID_Inc; float pid_inc_calc(PID_Inc *p, float set, float fb, float dt) { float e set - fb; /* 增量式三项比例看待偏差变化积分看当前偏差微分看偏差加速度 */ float du p-Kp * (e - p-e1) p-Ki * e * dt p-Kd * (e - 2.0f * p-e1 p-e2) / dt; p-e2 p-e1; p-e1 e; p-out du; /* 限幅时把累积量回写否则积分项会继续累积造成退饱和滞后 */ if (p-out p-out_max) p-out p-out_max; if (p-out p-out_min) p-out p-out_min; return p-out; }逻辑上du 是这一拍输出的增量p-out 是历史累积值因此任何一次限幅都必须写回结构体否则下一次计算会拿着一个「虚高」的基准值继续累加。参数上Kp 决定响应速度Ki 消除稳态误差Kd 抑制超调dt 是采样周期单位秒必须和定时器实际节拍一致写成常数最容易埋雷——一旦后续把节拍从 1 秒改成 2 秒Ki 的实际作用会翻倍。2.3 采样周期、死区与积分限幅的工程取值采样周期不是越快越好。温室热惯性大温度采样做到 1 秒已经足够更小的周期只会让微分项被传感器噪声放大。湿度响应稍快1~2 秒合适。下面是常用来做起步的取值参数温度回路湿度回路说明采样周期 dt1 s2 s与定时器中断节拍严格一致控制死区±0.3 ℃±2 %RH死区内保持上一输出抑制执行器频繁动作输出范围0~10000~1000映射到 PWM 或最小开/关时间积分限幅输出的 ±40%输出的 ±40%防止长时间偏差导致积分项撑满微分先行开启开启设定值阶跃时不产生微分冲击死区的处理方式要写进代码不能在比较器里随手一个 if 了事因为死区边界附近的抖动会让继电器一分钟吸合十几次机械寿命和温控品质一起完蛋。/* 死区处理偏差落在死区内时冻结积分增量只保留比例与微分 */ float e set - fb; if (fabsf(e) DEADBAND) { e 0.0f; /* 比例项归零输出保持不变 */ p-Ki 0.0f; /* 临时屏蔽积分避免死区内缓慢爬升 */ } else { p-Ki p-Ki_nominal; /* 出死区立刻恢复 */ }这段代码的关键点在于「冻结」而不是「清零输出」。如果死区内直接把输出置零加热器会周期性停摆温度反而在设定值下方形成一个低频波动比死区本身的代价更大。3. 基于 STM32 与 ESP32 的温湿度终端硬件与驱动3.1 传感器与执行器器件选型对比传感器选型直接决定控制回路的上限。DHT22 便宜、单总线、免外围但响应时间约 2 秒、长期漂移大放在湿度长期 90% 以上的棚里半年后读数能偏 5 %RH。SHT30/SHT31 是 I2C 数字输出出厂校准湿度精度 ±2 %RH价格高一些但重复性好适合做闭环反馈。DS18B20 只测温防水探头版本适合埋在基质或水肥管路里做第二路温度参考。器件接口温度精度湿度精度响应时间适用位置DHT22单总线±0.5 ℃±2 %RH约 2 s成本敏感的展示型终端SHT30I2C±0.3 ℃±2 %RH约 8 s闭环反馈主传感器SHT31I2C±0.2 ℃±2 %RH约 8 s对精度要求更高的场景DS18B20单总线±0.5 ℃无约 0.75 s基质、水温等辅助测点MCU 侧STM32 系列外设规整、定时器资源多适合同时跑多路 PWM 和 ADCESP32 自带 Wi-Fi适合需要把温湿度数据推到上位机或手机端的场景代价是 Wi-Fi 射频工作瞬间的电流尖峰可能干扰模拟采样布局时要把传感器走线和天线拉开。全球行业数据也提示带联网能力的温湿度监测终端在设施农业里的部署比例逐年上升但联网只是链路控制品质仍取决于回路本身。3.2 用 CubeMX 配置 I2C 与定时器采样节拍在 STM32CubeMX 里要配的主要是四件事I2C1 用于 SHT30TIM6 做 1 秒基准节拍TIM1 的 PWM 通道驱动加热与加湿USART 用于调试输出。配置项取值理由I2C1 速率100 kHzSHT30 标准模式长排线时更抗干扰I2C1 上拉4.7 kΩ 外置内部上拉偏弱长线通信易失败TIM6 预分频719972 MHz 主频下得到 10 kHz 计数TIM6 周期9999合计 1 Hz 中断TIM1 PWM 频率1 kHz高于加热丝热惯性低于继电器可听噪声时钟源外部晶振内部 RC 温漂会影响采样节拍采样和控制建议不在中断里做中断只置标志位浮点运算放在主循环避免中断执行时间过长影响其他外设。/* TIM6 中断只置标志控制运算留在主循环 */ volatile uint8_t g_ctrl_tick 0; void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM6) { g_ctrl_tick 1; } } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_I2C1_Init(); MX_TIM1_Init(); MX_TIM6_Init(); HAL_TIM_PWM_Start(htim1, TIM_CHANNEL_1); /* 加热 */ HAL_TIM_PWM_Start(htim1, TIM_CHANNEL_2); /* 加湿 */ HAL_TIM_Base_Start_IT(tim6); /* 1 Hz 节拍 */ PID_Inc temp_loop { .Kp 40.0f, .Ki 0.6f, .Kd 0.0f, .out_min 0.0f, .out_max 1000.0f }; PID_Inc humi_loop { .Kp 25.0f, .Ki 0.4f, .Kd 0.0f, .out_min 0.0f, .out_max 1000.0f }; while (1) { if (g_ctrl_tick) { g_ctrl_tick 0; float t, h; if (sht30_read(t, h) 0) { actuator_apply(pid_inc_calc(temp_loop, 26.0f, t, 1.0f), pid_inc_calc(humi_loop, 65.0f, h, 1.0f)); } else { /* 读取失败按最保守策略处理全部执行器关闭并报警 */ actuator_safe_off(); } } } }逻辑上TIM6 每满 1 秒产生一次中断主循环检测到标志后执行一次「采样—计算—输出」。参数说明pid_inc_calc 的第四个参数 dt 必须写成 1.0f与 TIM6 的 1 Hz 严格对应两个回路的设定值分别是 26.0℃ 和 65 %RH实际部署时从 Flash 读取便于现场修改而不用重新烧录。SHT30 的读取用单次测量模式最省事#define SHT30_ADDR (0x44 1) /* 7 位地址左移一位HAL 要求 */ int sht30_read(float *temp, float *humi) { uint8_t cmd[2] {0x2C, 0x06}; /* 单次测量高重复性禁用时钟拉伸 */ uint8_t rx[6]; if (HAL_I2C_Master_Transmit(hi2c1, SHT30_ADDR, cmd, 2, 100) ! HAL_OK) return -1; HAL_Delay(20); /* 等待转换完成高重复性约 15 ms */ if (HAL_I2C_Master_Receive(hi2c1, SHT30_ADDR, rx, 6, 100) ! HAL_OK) return -1; uint16_t rawT ((uint16_t)rx[0] 8) | rx[1]; uint16_t rawH ((uint16_t)rx[3] 8) | rx[4]; *temp -45.0f 175.0f * rawT / 65535.0f; *humi 100.0f * rawH / 65535.0f; return 0; }两个字节高位在前后一个字节是 CRC8 校验产品代码里必须校验工棚电磁环境差I2C 偶发位翻转会导致湿度读数直接跳到 100 %RH进而把加湿器打开后果比读不到数据严重得多。3.3 执行机构驱动与安全互锁温室里同时存在加热和制冷湿帘、风机、加湿和除湿物理上互斥。互锁必须在软件和硬件两层做软件层保证同一时刻只有一组输出非零硬件层用继电器的常闭触点串联另一个回路的供电。安全策略表异常条件检测方式动作温度超过上限 5℃软件比较 独立温控开关切断加热全开风机传感器读数越界取值范围校验关闭全部执行器上报故障通信超时I2C 超时返回保持最后输出不超过 60 秒之后关断加湿与除湿同时请求逻辑互斥按优先级只执行加湿延迟除湿断电恢复上电初始化输出从 0 起步禁止直接跳到历史值最后一条容易被忽略。增量式 PID 的累积输出如果存在 Flash 里上电直接恢复上一次的占空比一旦上次是因为故障关机重启后就会立刻重复同样的错误动作。稳妥做法是上电后强制从 0 开始用 2~3 个采样周期缓慢爬升到计算值。4. 控制回路落地从双回路到整定与抗饱和4.1 温湿度双通道独立回路与耦合补偿先按两个独立回路跑可以解决大部分场景。为了削弱耦合可以在输出侧做互斥约束当温度回路的输出大于 200占空比 20%时湿度回路的加湿输出按系数衰减反之当加湿输出较大时温度回路的加热输出按系数衰减。这个系数不建议超过 0.3否则等于人为放慢了主回路。另一种做法是切到串级结构外环是湿度输出作为内环温度的设定值修正。这在食用菌菇房这种湿度优先级高于温度的场所更合适实现上只需把外环输出限幅到 ±2℃ 之后叠加到温度设定值上。4.2 PID 参数整定临界比例度法与工程试凑临界比例度法的步骤是先把 Ki 和 Kd 置零逐步增大 Kp 直到系统出现等幅振荡记录此时的 Kp 为临界增益 Ku振荡周期为 Tu然后按经验关系取值。温室回路滞后大这套方法实操中振荡容易持续很久我更常用的是「先比例、后积分、最后微分」的试凑法每一步观察 5~10 分钟。整定阶段温度回路湿度回路观察指标只用 Kp从 20 逐步加到 60从 15 逐步加到 40升到设定值的时间、有无持续振荡加入 Ki0.2 起每次加 0.20.15 起每次加 0.15稳态误差是否收敛有无低频摆动加入 Kd5~15仅在升降温快时加一般不使用超调量是否下降输出是否抖动冻结死区±0.3℃±2 %RH执行器动作频率是否降到可接受一个常见的误用是把 Kp 调得过大来「加快响应」。温度回路的输出一旦长期顶在 100%加热器的余热会让温度冲过设定值好几度接着冷却过程又要等很久最终形成 10 分钟量级的极限环比不控还差。判断方法很直接看输出曲线的形状如果长期贴着上限走就是 Kp 或前馈不够而不是 Kp 需要再大。4.3 输出限幅、抗积分饱和与手动自动无扰切换执行器有物理下限。加湿器开度低于 10% 时基本喷不出雾继电器型加热在 5% 占空比下会频繁吸合。所以输出映射要做成「死区 线性段」/* 把 0~1000 的 PID 输出映射到执行器可用区间 */ uint16_t map_output(float u, uint16_t min_on, uint16_t max_on) { if (u 0.0f) return 0; /* 完全关闭 */ if (u 50.0f) return 0; /* 低区死区避免无效动作 */ /* 50~1000 线性映射到 min_on~max_on */ float ratio (u - 50.0f) / 950.0f; return (uint16_t)(min_on ratio * (max_on - min_on)); } /* 手动/自动无扰切换切换瞬间把 PID 累积输出同步为手动值 */ void pid_bumpless(PID_Inc *p, float manual_out) { p-out manual_out; /* 累积量对齐下一拍不会跳变 */ p-e1 0.0f; /* 清历史偏差避免微分冲击 */ p-e2 0.0f; }逻辑说明map_output 把连续输出转成执行器真正能用的区间50 这个阈值是按加湿器最小雾化量实测定的每个项目要重新标。pid_bumpless 解决的是从手动切回自动那一瞬间的输出跳变不这样做的话PID 会拿着旧的累积值加上一个新算的增量输出可能直接从 30% 跳到 80%湿帘阀门会发出明显的撞击声。5. 阶跃响应验证与长期运行排错技巧5.1 用阶跃响应曲线量化超调与稳态误差调完之后一定要做一次完整验证让系统从室温稳定运行然后手动把设定值从 24℃ 阶跃到 26℃用串口按秒打印设定值、实测值、PID 输出三列画成曲线看四个指标——上升时间到达设定值 90% 的耗时、超调量峰值超出设定值的百分比、调节时间进入 ±0.5℃ 且不再出的时间、稳态误差。温室温度回路超调控制在 1℃ 以内、调节时间 15~25 分钟属于正常如果超调超过 3℃先查微分项和执行器余热再考虑降 Kp。# 采集串口数据并落盘1 秒一行便于离线画图 python -c import serial, csv, time s serial.Serial(COM3, 115200, timeout1) with open(step_response.csv, w, newline) as f: w csv.writer(f) w.writerow([t, set, temp, humi, out]) t0 time.time() while time.time() - t0 1800: # 采 30 分钟 line s.readline().decode().strip() if line: w.writerow([round(time.time() - t0, 1)] line.split(,)) 参数说明波特率 115200 要和固件一致采集 1800 秒覆盖了完整阶跃过程行首加时间戳是为了让不同步的采样点还能对齐。5.2 温室长期运行的高频故障排查清单现象首要怀疑验证方法处理湿度读数长期偏高传感器结露与手持表对比加装透气防尘罩定期烘干校准温度控制周期性振荡Kp 过大或死区过小看输出是否顶限幅降 Kp放大死区到 ±0.5℃加湿器频繁启停死区边界抖动统计 10 分钟动作次数增加最小开启时间 30 秒白天正常夜间失控夜间通风差、耦合增强分时段记录数据夜间启用耦合补偿系数I2C 偶发读取失败排线过长、上拉不足示波器看波形边沿改 4.7 kΩ 上拉缩短走线上电后输出直接拉满断电恢复未清零查初始化代码强制从 0 起步缓慢爬升最后补一个实战细节把 PID 参数、死区、设定值都放到 Flash 或 NVS 里现场调参时通过串口指令改写不要每次改参数都重新编译烧录。同时给参数加一个 CRC 和默认值回退一旦存储区校验失败就加载一组保守参数宁可控得慢一点也不要让温室在深夜跑在一组被写坏的数字上。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号