
简介一套完整的基于51单片机的温湿度控制Proteus仿真与开发资料适合作课程设计、毕业设计及单片机入门练习。系统采用DS18B20采集环境温度SHT11采集湿度数据LCD1602实时显示数值并附带系统时间同时设有按键、报警和时钟模块。控制逻辑上当温度超过设定阈值时启动风扇降温湿度低于设定下限时自动开启加湿实现典型的双路闭环调节并预留手动控制接口。配套资料共50个文件压缩包仅834KB包含Keil工程C语言源码与头文件、编译生成的Hex文件、Proteus仿真工程DSN/DBK、原理图SchDoc/PDF、流程图BMP以及物料清单xlsx覆盖软件开发、硬件设计、仿真验证与元件选型全过程。文件类型包括源程序、目标文件、库文件和文档等结构清晰便于按模块学习。目前已有241人学习下载适合需要快速理解温湿度控制方案、研究传感器时序或扩展联动功能的开发者。借助仿真图与原理图可直观对照程序运行效果为实物制作、报告撰写及教学演示提供完整参考。1. 双传感器加双执行器这套51温湿度控制难点在哪搜索“基于51单片机的温湿度控制”时最常见的结果不是缺原理图就是缺物料清单真正卡人的是DS18B20和SHT11同时出现在一个工程里。它们都工作在串行协议族里但DS18B20是异步的OneWire时序SHT11却要靠SCK时钟同步读写放在同一颗51上不能简单并线。再加上LCD1602要占用至少7个IO风扇、加湿器又要接继电器驱动硬件引脚和软件时序容易缠在一起。下面按“硬件接线→传感器驱动→控制决策→Proteus仿真→交付校验”的顺序把DS18B20时序、SHT11读取、LCD1602驱动和滞回控制串成一条可复现路径适合做51单片机课程设计或想把温控风扇扩展成温湿度一体控制的工程师。2. DS18B20与SHT11两种单总线共存时序差异、上拉电阻与接线分配2.1 同为单总线为什么不能共用一条数据线先厘清概念。DS18B20是真正的单总线只有DQ一根线总线上所有通信都由主机发起每个位都有一个60us到120us的时间窗从机靠这个窗口内电平拉低的时间区分0和1同时也支持总线上挂多个器件通过64位ROM寻址。SHT11则更接近“两线”接口SCK提供时钟DATA传输数据。虽然不少教程把它也归到单总线里但它的启动序列、命令帧和ACK应答方式都和DS18B20完全不同。如果把SHT11的DATA直接并到DS18B20的DQ上DS18B20复位时主机要把总线拉低480us以上这个长低电平对SHT11来说已经接近一组完整命令帧SHT11会进入错误状态并把DATA线拉低响应而SHT11释放DATA线前的ACK脉冲又会干扰DS18B20的存在脉冲检测。两条线的空闲电平、位时序、握手状态机都不一致共用一条数据线没有收益。常见做法是分两个IO引脚接软件互不干扰排查问题也更快。2.2 硬件电路与物料清单怎么对应以AT89C51或STC89C52为例IO分配可以这样安排LCD1602的D4~D7接P2.0~P2.3RS、RW、E分别接P2.4、P2.5、P2.6DS18B20的DQ接P3.7SHT11的SCK接P3.5、DATA接P3.4P1.0~P1.2接三路继电器输出分别控制风扇、加湿器和可选的半导体制冷片。P3.2和P3.3接两个按键用于调整温度湿度阈值。这套分配的好处是LCD占用连续的P2口低四位传感器走P3口继电器独立在P1口布线时不容易交叉。表格是物料清单里相对完整的版本实际采购时半导体制冷片可以后置先把风扇和加湿器跑通器件数量关键参数用途AT89C51/STC89C52112MHz晶振、22pF电容×2主控DS18B201TO-92封装DQ上拉4.7k温度采集SHT111SCK/DATA各上拉10k温湿度采集LCD16021HD44780控制器3.3V或5V显示ULN20031DIP16继电器驱动继电器35V线圈10A触点执行切换风扇112V/0.2A风冷降温加湿器模块15V雾化片或继电器型加湿半导体制冷片1可选需配散热片辅助降温电位器110kLCD对比度调节按键2轻触开关阈值设置接继电器时不要直接把线圈接在单片机IO上。ULN2003输入端接P1口输出端接到继电器线圈和电源之间继电器线圈两端反向并联一个1N4007续流二极管否则断电瞬间的反向电动势会打坏IO口。风扇、加湿器这些负载的火线走继电器触点和单片机控制电路隔离调试时才不会因为电机干扰导致液晶乱码。2.3 DS18B20复位与读时序的C语言实现DS18B20驱动分三步复位、写命令、读数据。时序的微秒级延时在12MHz晶振下用循环加_nop_()实现包含intrins.h头文件即可。参考实现#include reg52.h #include intrins.h sbit DQ P3^7; // DS18B20数据线 void Delay_Micros(unsigned int us) { while (us--) { _nop_(); // 12MHz下约1us _nop_(); } } /* 复位主机拉低至少480us释放后检测存在脉冲 */ bit DS18B20_Reset(void) { bit present 1; DQ 0; Delay_Micros(500); // 拉低至少480us DQ 1; Delay_Micros(60); // 释放15~60us后再采样 present DQ; // 从机拉低存在此时读回0 Delay_Micros(450); return present; // 返回0表示检测到DS18B20 }这段代码里最容易错的是释放总线后的采样时机。主机把DQ拉高后DS18B20需要等待15us以上才会发出存在脉冲提前读会误判为“无设备”。Delay_Micros(60)之后读到的低电平才是从机真正的响应。实际读温度时在复位之后还要依次发送跳过ROM命令0xCC、启动转换命令0x44再复位一次并发送读暂存器命令0xBE最后连续读两个字节。转换时间在12位分辨率下约750ms不能转换完立刻去读主程序里要留出时间片。2.4 SHT11启动序列与测量命令怎么发SHT11发送测量命令前必须执行特定的启动序列SCK高电平时DATA由1变0接着SCK翻转一次DATA由0变1。之后按高位先发的方式把命令字节送进去命令0x03测量温度0x05测量湿度。命令发送完毕后主机释放DATA线SHT11会在一段时间内把DATA拉低表示“测量完成”主机再产生SCK脉冲读取两字节数据和可选CRC。sbit SHT_SCK P3^5; sbit SHT_DATA P3^4; void SHT11_Start(void) { SHT_SCK 0; SHT_DATA 1; SHT_SCK 1; SHT_DATA 0; // SCK为高时DATA拉低 SHT_SCK 0; SHT_SCK 1; SHT_DATA 1; // 再拉高完成启动 SHT_SCK 0; } void SHT11_SendByte(unsigned char cmd) { unsigned char i; for (i 0; i 8; i) { SHT_DATA (cmd 0x80) ? 1 : 0; cmd 1; SHT_SCK 1; // SCK上升沿写入 SHT_SCK 0; } SHT_DATA 1; // 释放数据线 SHT_SCK 1; SHT_SCK 0; }SHT11的命令发送完以后要等待它把DATA拉低再读数据这个等待时间在几十毫秒量级。读取时每字节前SHT11会先发一个ACK低脉冲顺序是MSB、LSB、CRC。很多程序只读两个数据字节不读CRC在仿真里没问题到硬件上建议把CRC读出来做校验能过滤掉不少偶发错位。3. LCD1602显示与风扇/加湿/降温执行逻辑从驱动代码到主循环流程图3.1 LCD1602四线接法与最小驱动代码LCD1602控制器HD44780支持8线和4线两种模式。8线一次送一字节速度快但要接11个IO4线先送高四位再送低四位只占7个IO51课程设计里普遍选它。网上搜LCD1602驱动代码时注意区分是8线还是4线版本直接复制8线代码到4线电路上只会看到满屏方块。四线初始化必须先发0x02让控制器切换到4线模式再发0x28设置两行显示、5x7点阵。数据线用sfr位定义单独操作不要用整个P2口赋值否则RS、RW、E的状态会被冲掉sbit LCD_D4 P2^0; sbit LCD_D5 P2^1; sbit LCD_D6 P2^2; sbit LCD_D7 P2^3; sbit LCD_RS P2^4; sbit LCD_RW P2^5; sbit LCD_E P2^6; void Lcd_WriteCmd(unsigned char cmd) // RS0 写命令 { LCD_RS 0; LCD_RW 0; LCD_D7 (cmd 7) 0x01; // 先送高四位 LCD_D6 (cmd 6) 0x01; LCD_D5 (cmd 5) 0x01; LCD_D4 (cmd 4) 0x01; LCD_E 1; Delay_Micros(2); LCD_E 0; LCD_D7 (cmd 3) 0x01; // 再送低四位 LCD_D6 (cmd 2) 0x01; LCD_D5 (cmd 1) 0x01; LCD_D4 cmd 0x01; LCD_E 1; Delay_Micros(2); LCD_E 0; }写数据函数就是把LCD_RS置1其余流程一样。初始化时序建议上电后延时15ms发0x02再延时5ms发0x28、0x0C、0x01、0x06每次命令之间留2ms。如果LCD第二行不显示检查0x28是否在0x02之后发或者第二行起始地址是否写成了0xC0而不是0xC0与0x80的组合。3.2 温度湿度阈值与滞回控制风扇、加湿器、制冷片的分工执行机构挂在继电器上以后用单阈值比较会让继电器在临界点反复吸合。温度刚超过26℃就开风扇降到25.9℃又关闭一秒钟能切换十几次继电器触点很快烧黑。常见做法是引入滞回区间开和关用两个阈值两个阈值之间形成一个安全带。示例规则控制对象开启条件关闭条件风扇风冷降温温度 26.0℃温度 24.0℃半导体制冷片温度 30.0℃温度 28.0℃加湿器湿度 40%RH湿度 55%RH这套规则的含义是温度在24℃到26℃之间时风扇保持原状态不变。从26℃以上降温时要等到低于24℃才停机避免在26℃附近来回跳动。湿度同理加湿器在40%开、55%关中间是盲区。代码实现如下#define TEMP_FAN_ON 26.0f #define TEMP_FAN_OFF 24.0f #define HUMI_ON 40 #define HUMI_OFF 55 bit fan_state 0, humi_state 0; void ControlActuator(float temp, unsigned char humi) { if (temp TEMP_FAN_ON) { fan_state 1; // 温度高开风扇 } else if (temp TEMP_FAN_OFF) { fan_state 0; // 温度降到下限以下再关 } if (humi HUMI_ON) { humi_state 1; // 湿度低开加湿 } else if (humi HUMI_OFF) { humi_state 0; // 湿度高关加湿 } Relay_Fan fan_state; Relay_Humi humi_state; }继电器切换尽量放到主循环里统一执行不要在定时器中断里做否则中断频繁时会抖。硬件上如果继电器吸合声音明显可以在软件里加一个最低动作间隔比如每次切换后500ms内不允许再次切换牺牲一点响应速度换继电器寿命。3.3 主循环流程图映射与键盘设定原理图旁边的流程图通常画成这样上电 → 时钟和IO初始化 → LCD初始化 → DS18B20复位 → SHT11启动 → 进入主循环主循环里读DS18B20温度读SHT11温湿度做温度补偿刷新LCD扫描按键修改阈值按滞回规则刷新继电器喂狗延时500ms回到读温度这一步。用C语言写出来就是下面这个模式void main(void) { unsigned char t_int, h_int; float temp; WDT_Init(); // 如果用STC系列先开看门狗 Lcd_Init(); // 初始化LCD1602 DS18B20_Reset(); // 复位DS18B20 SHT11_Start(); // 给SHT11一个干净的初始状态 while (1) { temp DS18B20_GetTemp(); // 启动转换并读取温度 SHT11_GetValue(t_int, h_int);// 读取SHT11温湿度 Lcd_Display(temp, h_int); // 第一行显示温度第二行显示湿度 Key_Scan(); // 按键扫描修改阈值 ControlActuator(temp, h_int); // 滞回控制继电器 WDT_Feed(); // 喂狗放在循环末尾 Delay_ms(500); // 500ms调度周期 } }DS18B20_GetTemp里注意区分“发启动转换”和“读结果”两个动作12位分辨率转换约750ms如果在同一个函数里发完转换立即读读到的永远是0xFFFF。常见做法是第一次进循环发0x44启动转换做显示和按键下一轮循环再发0xBE读结果这样时间片刚好被填满。按键扫描不要用阻塞式延时消抖用“检测按下→置标志→下次循环再处理”的方式长按时每500ms自动加一调阈值更顺手。4. Proteus联合仿真元件库、原理图搭线与温度跳变排错4.1 Proteus元件选型DS18B20、LM016L与SHT11模型怎么找在Proteus里做整机仿真元件库的检索和实物不太一样。DS18B20通常在传感器分类里搜关键字能直接找到模型支持单总线仿真但DQ外部必须加4.7k上拉电阻否则复位时存在脉冲检测不到。LCD1602在元件库里直接搜LCD1602可能出不来最常用的替代模型是LM016L引脚定义和1602完全兼容搜LM016L就能放置。SHT11不是所有Proteus版本都自带模型有的版本只能搜到SHT1x系列。找不到时不要死等更实用的做法是保留SHT11的SCK和DATA两个网络节点先放两个普通IO口电平指示或脉冲发生器代替把DS18B20和LCD1602的联合仿真跑通硬件板上再烧SHT11真实代码。仿真模型和真实芯片的电气特性有差异SHT11在仿真里能读到硬件上也不见得一次过这两个环节要分开验证。4.2 仿真原理图连线与常用参数原理图画好后第一件事检查AT89C51的EA引脚是否接VCC。EA接地会让单片机去外部程序存储器取指仿真里芯片直接不跑这是Proteus里最常遇到的问题。晶振选12MHz两个22pF电容接地和代码里的延时时间窗匹配。DS18B20的DQ接4.7k上拉到VCCLCD1602的VEE接10k电位器中间抽头电位器两端分别接VCC和GND。表格里是仿真时几个关键网络的推荐参数网络连接方式参数DS18B20 DQ4.7k上拉到VCC必要时串联300ΩSHT11 SCK/DATA各10k上拉到VCCSCK与DATA分开放线LCD VEE10k电位器中间抽头调节对比度EA直接接VCC必须晶振负载22pF×2配合12MHz继电器和风扇在仿真里用虚拟模型代替不要直接让单片机IO口驱动虚拟灯泡或大电流电机仿真电流和功耗模型会拖慢整个工程。Proteus 8运行时负责计算器件模型的是pds.exe进程仿真一卡就先看这个进程的CPU占用率如果占满就把虚拟终端、示波器探头和多余探针删掉再把仿真步长调粗。4.3 三个常见仿真故障与验证方法DS18B20始终检测不到存在脉冲先检查DQ上拉电阻是接在单片机同一电源网络上还是接到了悬空节点其次看单片机供电是否正常Proteus里VCC和GND符号不规范时会出现隐性断路。LCD1602黑屏且调节电位器没反应检查VDD和VSS是否反接LM016L模型对负压偏置兼容性差VEE电位器接地端保持参考地即可。SHT11数据跳变是最难排查的除了模型本身时序精度外SCK和DATA两条线在原理图上挨得太近会造成信号串扰物理上相邻时影响小仿真里数值振荡反而更明显。把两条线分开走再在SCK上串一个100Ω电阻模拟线阻能减少跳变。验证时用如下串口发送函数接虚拟终端void UART_Init(void) { SCON 0x50; // 8位可变波特率清RI和TI TMOD 0x0F; TMOD | 0x20; // 定时器1做波特率发生器 TH1 0xF3; // 12MHz下约2400bps TR1 1; } void UART_SendChar(unsigned char c) { SBUF c; while (!TI); // 等待发送完成 TI 0; }串口打印时把DS18B20读到的温度值和SHT11返回的状态码一起发出去比如“T:25.5 S:0”状态码非0说明SHT11时序出错或命令没被正确响应。有了这组数据在Proteus里定位是硬件连线还是时序问题比对着波形猜快得多。5. 双温度源校验、看门狗降级与交付验证三招5.1 用DS18B20给SHT11做湿度修正SHT11的湿度原始值经过内部线性化后在25℃附近误差最小温度偏离越多湿度读数偏移越明显。常见做法是读出SHT11湿度后用DS18B20的温度值做温度系数补偿补偿公式的参数从SHT11数据手册取通常都是几位小数程序里用整型乘法和位移近似就够。这样既保留DS18B20测温的精度又避开了SHT11自带温度通道一致性稍差的问题。补偿后的湿度同时用于显示和控制比直接用原始湿度值可靠。5.2 SHT11读取失败时降级运行SHT11在环境湿度极高或连续上电瞬间可能读不到ACK程序里连续读三次状态位都不正常就置一个HUMI_VALID标志为0LCD湿度位置显示“--”温度控制继续用DS18B20跑。不要让湿度传感器卡死把整个闭环停掉这是温湿度控制工程里最常见的失败模式if (status ! OK) { retry_count; if (retry_count 3) { HUMI_VALID 0; // 降级只控温度 LCD_ShowHumi(0xFF); // 显示“--” } WDT_Feed(); // 重试期间也要喂狗 }看门狗喂在主循环末尾重试和延时期间都要喂否则看门狗会把正常工作的系统当作死机复位。STC单片机的看门狗溢出时间通常可以设到1秒到2秒主循环500ms周期内完整喂一次留足余量。5.3 出板校验冰水混合物、串口打印与三组数据留档交付前做两点校准DS18B20用冰水混合物做0℃点再用手持温度计对比40℃热水做第二点把两个点的差值按比例补偿进代码。湿度校验可以用密封袋加氯化钠饱和溶液理论湿度约75%RHSHT11放进去半小时再对比读数偏差超过5%就要重新检查传感器焊接和上拉电阻。校验过程中用串口按“DS18B20温度,SHT11湿度,状态码”的格式打印CSV数据留三小时记录看阈值回差有没有松动、继电器切换频率是否正常。数据都合格后原理图、流程图和物料清单就可以连同源码一起归档。本文还有配套的精品资源点击获取