简介一份面向粮仓管理、自动化专业学生及嵌入式初学者的本科毕业设计论文完整呈现基于AT89S52单片机的粮仓温湿度检测与控制系统方案。系统由SHT10温湿度传感器、AT89S52单片机、TC1602液晶显示模块及报警电路组成采用模块化设计电路简单、集成度高、工作稳定、调试方便可实现温湿度实时采集、显示与超限自动报警有效避免因温湿度异常导致的粮食损失适用于大型粮库、食品仓储等环境。资源包共1个docx文档为完整毕业设计论文内容涵盖摘要、目录、系统总体方案、硬件电路设计、软件流程图、调试过程及参考文献文档大小1.25MB结构清晰排版规范便于查阅。目前已有322人浏览学习。读者可从中获得完整的单片机温湿度控制系统设计思路包括传感器选型与接口方式、单片机处理流程、显示与报警电路设计及软硬件联调要点可作为嵌入式课程设计或毕业设计的可靠参考。1. 大型粮库的温湿度检测与控制一套能直接复现的单片机项目粮仓温湿度控制不是说装一个空调那么简单。粮堆内部的温度、湿度变化是缓慢的但一旦超限霉菌和储粮害虫的繁殖速度会快得吓人。很多中小型粮库到现在还是人工拿温度计逐点测量记录周期长、漏检率高出了霉变才后悔。我拆完这套资料后最大的感受是它把大型粮库的温湿度检测与控制压缩成一块 AT89S52 单片机加数字传感器 SHT10 和一块 LCD1602 的完整方案硬件不贵代码也足够直白适合做毕设、课设或者小型仓储改造的参考。这套资源的核心逻辑并不复杂SHT10 负责采集温湿度单片机判断是否超过上下限再驱动报警和加热、加湿、通风、降温开关。下面我从选型、硬件、软件、踩坑到验证全链路拆开讲。2. 为什么选 51 单片机加数字传感器方案对比里的三个决定性理由2.1 三种方案选型从 80C51 模拟采样到 PLC 控制原文档在方案选择部分做了三个方向的对比我实际复现时也认同它的结论。方案一是把温湿度传感器放进粮仓信号经过放大、A/D 转换之后送到 80C51 单片机最后用数码管显示。这套路线早在十年前很常见但问题是模拟传感器的一致性差每一路信号都要单独调零、调增益PCB 上全是电位器和运放焊接和调试的时间比写代码还长。方案二是用 AT89C51 或者 AT89S52 这类带 Flash 的 51 单片机搭配 SHT10 数字温湿度传感器输出就是数字信号不需要额外 A/D。显示用 LCD1602控制部分留了按键设定、蜂鸣器报警以及加热、加湿、通风、降温的驱动接口。这是我最终选择复现的路线。方案三更重用 PC 机做上位机经过模糊自调整 PID 输出到 PLC再由 PLC 控制加热阀、制冷阀、风机。这套东西放在工业车间没问题但放在粮库就有点杀鸡用牛刀。它需要一个稳定的上位机、通信链路和 PLC 模块成本比方案二高出好几个数量级。而且粮库环境对实时性要求并不苛刻缓变过程用 PID 调节反而容易让风机频繁启停。三个方案的核心差异可以用这张表概括对比项方案一方案二方案三温湿度采集模拟传感器 运放 A/DSHT10 数字输出模拟传感器 A/D 到 PC主控核心80C51AT89C52PC PLC显示方式8 位 LED 数码管LCD1602 字符型液晶工业屏或上位机组态系统复杂度高外围多低集成度高高需要通信和上位机成本与维护中等低高选型结论非常明显方案二没有牺牲功能反而把布线和编程简化了一大截。后面所有硬件设计和软件流程本质上都围绕“数字传感器 51 单片机”这个组合展开。2.2 SHT10 数字温湿度传感器的关键参数与读取逻辑SHT10 是这套系统里最值得注意的芯片它把湿度传感器、温度传感器、A/D 转换器、校准存储器和 I2C 类接口封装在一个接近火柴头大小的元件里。和传统的湿敏电阻相比它最大的价值是出厂前做过校准使用时不配任何外部电路就能出结果。我习惯先看数据手册里的关键参数。SHT10 的湿度测量范围是 0100%RH分辨率能达到 0.03%RH最高精度是 ±2%RH温度测量范围是 -40℃ 到 123.8℃分辨率 0.01℃。内部 A/D 转换器在测量湿度时是 12 位测温度时是 14 位。供电电压 2.4V 到 5.5V所以从单片机 5V 系统取电也能工作但为了降低自身发热带来的测量误差我一般单独给它供 3.3V。SHT10 的接口只有 4 个引脚GND、DATA、SCK、VDD。DATA 是双向数据线SCK 是串行时钟输入。它的协议和标准 I2C 不完全一样但可以用 51 单片机的普通 I/O 口模拟。读取温湿度之前必须先发一组启动时序。下面是常见做法里最基础的实现sbit sht_sck P2^0; sbit sht_data P2^1; void SHT_Start(void) { sht_data 1; sht_sck 1; sht_data 0; sht_sck 0; } void SHT_Reset(void) { unsigned char i; sht_sck 0; sht_data 1; for (i 0; i 10; i) { sht_sck 1; sht_sck 0; } SHT_Start(); }这段代码里的 SHT_Start 做了三件事先把数据线拉高再把时钟线拉高然后让数据线在时钟高电平期间完成一个下降沿。SHT10 靠这个时序识别一次通信的开始。SHT_Reset 则是把时钟线连续翻转 9 次以上让传感器回到一个已知状态避免通信卡死在半截。我一般会在系统上电延时之后调用一次 SHT_Reset这个习惯帮我避免了很多“第一次读数全零”的怪问题。SHT10 的常用命令码有三个测量温度是 0x03测量湿度是 0x05软复位是 0x1E。写状态寄存器是 0x06读状态寄存器是 0x07。这些命令都在 8 位传输后进入等待阶段单片机需要检测 DATA 线是否被传感器拉低拉低表示测量完成可以继续读数据。2.3 AT89S52 最小系统与外围基本约定AT89S52 是 51 系列里非常典型的增强型芯片内置 8K 字节 Flash 程序存储器256 字节 RAM和工业标准 80C51 的指令系统兼容。最大的好处是程序可以直接用 ISP 方式下载开发阶段不用频繁拔芯片。最小系统由三部分构成电源、晶振、复位。晶振我用 12MHz两个 30pF 电容分别接地。复位电路采用上电自动复位RST 引脚接一个 10μF 电解电容到 VCC再接一个 10kΩ 电阻到 GND。上电瞬间电容充电RST 维持高电平超过两个机器周期单片机正常复位。实际焊接时这个电阻电容位置很容易弄反错误接法会导致上电不启动或者不断复位。还有两点必须提醒。第一AT89S52 的 P0 口是漏极开路结构做输出时必须外接上拉电阻。LCD1602 的数据口如果直接挂在 P0 上没有上拉电阻就会显示乱码。第二EA/VPP 引脚要接高电平让单片机执行内部 Flash 程序。有些开发板上这个引脚悬空程序下载后完全跑不起来一查才发现是 EA 没接。3. 硬件电路从 SHT10 接口到继电器开关的接线细节3.1 SHT10 四线接口与 1602 液晶显示电路SHT10 的接线并不复杂但每个引脚都要交代清楚。VDD 接 3.3VGND 接系统地SCK 接单片机 P2.0DATA 接 P2.1。DATA 线是双向的单片机输出时主动拉高拉低读取时又要释放总线所以必须在 DATA 线上加一个 10kΩ 上拉电阻到 VDD。没有这个上拉电阻传感器拉低总线之后恢复不了高电平后续通信就会漂移。电路连接关系可以参考下面这张表SHT10 引脚功能接到哪里1 脚 GND地系统地2 脚 DATA串行数据单片机 P2.1并接 10kΩ 上拉3 脚 SCK串行时钟单片机 P2.04 脚 VDD电源3.3V 稳压输出NC 脚空脚悬空不接任何线LCD1602 的接线在文档里用的是字符型液晶共 16 个引脚。VSS 接地VDD 接 5VVL 对比度调节脚经过一个 10kΩ 电位器接到 GND。RS 接单片机一个 I/O 口RW 直接接地表示只写E 使能脚接另一个 I/O 口D0 到 D7 接 P0 口并加 4.7kΩ 上拉排阻。这样接好之后程序里只要控制 RS、E 和数据口就能显示内容。3.2 报警、按键与稳压电路的接法报警电路用蜂鸣器加一个 NPN 三极管驱动。单片机引脚输出高电平通过 1kΩ 电阻给三极管基极提供电流三极管导通后蜂鸣器发声。有个细节是蜂鸣器如果是 5V 有源蜂鸣器直接接在三极管集电极和 VCC 之间并且一定要在蜂鸣器两端反向并联一个二极管。这个二极管用来吸收关断瞬间的反电动势没有它单片机很容易被干扰复位。按键设定模块用来调整温湿度报警的上下限。常见的接法是每个按键一端接地另一端接单片机 I/O 口I/O 口内部上拉。按下按键引脚读到低电平程序在循环里对这个状态做一次消抖判断。四个按键可以分别承担温度上限、温度下限、湿度上限、湿度下限的调整也可以复用一个“设置”键进入调整模式。稳压电路部分如果系统用 5V 供电给 SHT10 供电时最好单独加一片 3.3V 低压差稳压器。SHT10 虽然允许最高 5.5V 供电但传感器自身发热会影响湿度测量3.3V 供电比 5V 供电的自身温升更小。常见做法是在 5V 输出后接 LDO 到 3.3V输出端加 0.1μF 和 10μF 两个滤波电容。3.3 加热/加湿/通风/降温开关电路继电器驱动与续流控制逻辑来看设计文档系统会有四个输出控制点温度超出上限启动制冷设备温度低于下限启动加热设备湿度高于上限启动通风设备湿度低于下限启动加湿设备。单片机引脚不能直接驱动交流接触器或者大功率风机所以中间要用继电器或者固态继电器隔离。我一般优先用 ULN2003 达林顿阵列它的好处是内部自带续流二极管引脚直接接继电器线圈不需要再外搭二极管。如果用单个 NPN 三极管驱动继电器则必须在线圈两端反向并联 1N4007 二极管。极性接反会导致继电器一吸合单片机就复位这是很多人在继电器电路上翻车的第一个坑。下面这段伪代码对应的是控制判断部分四个输出分别用四个 I/O 口表示sbit RELAY_COOL P1^2; sbit RELAY_HEAT P1^3; sbit RELAY_FAN P1^4; sbit RELAY_HUM P1^5; void Control_Check(unsigned int temp, unsigned int hum, unsigned char temp_high, unsigned char temp_low, unsigned char hum_high, unsigned char hum_low) { RELAY_COOL 0; RELAY_HEAT 0; RELAY_FAN 0; RELAY_HUM 0; if (temp temp_high) RELAY_COOL 1; if (temp temp_low) RELAY_HEAT 1; if (hum hum_high) RELAY_FAN 1; if (hum hum_low) RELAY_HUM 1; }这组判断用了典型的优先级策略如果同一个系统同时满足高温和高湿会先执行制冷和通风而不是让加热和加湿同时启动。这里我把所有输出默认清零再按条件置 1比连续 if-else 更容易排查问题。实际工程中还可以做十分钟最小间隔保护避免继电器频繁切换烧坏触点。3.4 稳压电路的供电顺序一个容易被忽略的地方是 3.3V 稳压器最好从 5V 输出取电而不是和单片机串在一起。如果 LDO 放在单片机前面负载变化会直接拉低单片机电压导致程序跑飞。合理的上电顺序是外部 5V 电源先进总开关一路给 LCD1602 和继电器一路进 LDO 给 SHT10。按键和单片机 I/O 单独走 5V传感器供电线不要和继电器供电线共用一根长导线否则继电器动作瞬间传感器会读到大电流冲击。4. 软件流程主程序、SHT10 读取、LCD 显示与阈值报警4.1 主程序结构与状态循环软件设计采用模块化思路主程序只需要完成系统初始化、读取传感器、判断报警和控制输出、刷新显示、扫描按键这几件事。这个架构很适合 51 单片机因为主循环不需要处理太多高实时性任务。主程序的初始化顺序必须是先关中断然后初始化定时器、串口、LCD再延时一段时间让 SHT10 上电稳定最后执行 SHT_Reset。如果先读传感器再初始化 LCD传感器可能因为电源刚上电还没稳定读回来一组无效数据。初始化顺序错了系统整个生命周期都会用错误数据判断报警。流程大致是void main(void) { unsigned int temp_raw, hum_raw; unsigned char temp_high 28; unsigned char temp_low 12; unsigned char hum_high 70; unsigned char hum_low 45; delay_ms(200); SHT_Reset(); LCD_Init(); LED_Init(); BEEP_Init(); while (1) { temp_raw SHT_ReadRaw(0x03); hum_raw SHT_ReadRaw(0x05); LCD_ShowValue(temp_raw, hum_raw); Control_Check(temp_raw, hum_raw, temp_high, temp_low, hum_high, hum_low); Key_Scan(); } }这个主循环里没有做延时传感器读取成功后会自然等待一段时间。如果读取失败程序会一直卡在等待 DATA 线拉低的循环里这时候按键也会失效。更好的结构是在读取函数里加一个超时退出机制比如用一个计数器循环 10000 次超时直接返回上一次的值避免整个系统因为一只传感器的时序异常而停摆。4.2 SHT10 初始化与读写命令在 4.1 主循环里用到的 SHT_ReadRaw 是整段软件的核心。它的流程是发送启动时序发送命令码等待测量完成连续读两个字节。SHT10 在读取过程中每一字节接收完后主机都要返回一个 ACK 信号最后一个字节不需要 ACK。下面的代码实现了完整的读取过程命令参数 cmd 选 0x03 表示温度选 0x05 表示湿度unsigned char SHT_WriteByte(unsigned char dat) { unsigned char i; for (i 0; i 8; i) { if (dat 0x80) sht_data 1; else sht_data 0; dat 1; sht_sck 1; sht_sck 0; } sht_data 1; sht_sck 1; if (sht_data 1) return 1; sht_sck 0; return 0; } unsigned int SHT_ReadRaw(unsigned char cmd) { unsigned char i; unsigned int val 0; SHT_Start(); SHT_WriteByte(cmd); sht_data 1; while (sht_data 1) ; for (i 0; i 16; i) { val 1; sht_sck 1; if (sht_data) val | 1; sht_sck 0; } sht_data 0; sht_sck 1; sht_sck 0; sht_data 1; return val; }这段代码里有几个参数值得单独说。SHT_WriteByte 在发送完 8 位数据之后把 DATA 释放并发送一个时钟脉冲来检测传感器的 ACK。如果传感器没有拉低 DATA说明命令没被正确接收返回值 1。实际调试时我会用一个 LED 灯显示这个错误状态不然很难区分是传感器没接线还是时序错了。SHT_ReadRaw 里的 while 循环用于等待测量完成。SHT10 在收到测量命令后如果 MILLISECONDS 还没有完成会把 DATA 拉低。温度测量最长时间大概是 320ms湿度测量最长 210ms这个循环不会一直空转太久。读出的 16 位原始值需要经过公式换算才变成实际温度值温度约为 d * 0.01 - 39.6湿度则要根据当前温度做线性补偿。4.3 LCD1602 初始化与阈值按键处理LCD1602 的初始化最关键的是延时。上电后必须等至少 15ms然后发送 0x38 设置 8 位数据接口、双行显示。再发送 0x0C 开显示不显示光标0x06 表示写入数据后地址自动加一最后 0x01 清屏。如果省略了第一个延时LCD 可能一直白屏。按键处理比较直接按下设置键进入阈值设定状态此时四个按键分别调整当前选中项的值。每次按键加一或者减一调整范围建议做限幅比如温度上限限制在 30℃ 以内湿度上限限制在 85%RH 以内防止误操作把阈值设置到不可能触发报警的极端值。显示部分在正常状态下显示当前温度和湿度在设置状态下显示阈值和修改光标。这种结构下代码量不大但每个函数单独调试会非常省事。我一般先测试 LCD 显示一行固定字符再测试 SHT10 读取最后才把按键和继电器接进去。5. 避坑清单上电不显示、湿度跳变、继电器误动的排查顺序5.1 LCD 白屏或乱码现象1602 背光亮但第一行全是方块或者显示几个固定字符不动。原因最常见的不是程序而是 VL 引脚对比度电压不对。VL 悬空时液晶模块显示模糊全部变方块。另外P0 口没接上拉电阻也会导致数据位漂移。解决VL 脚接一只 10kΩ 电位器中间抽头两端分别接 VCC 和 GND。上电后慢慢调节电位器到屏幕出现清晰字体。同时检查 P0 口上拉排阻是否焊好用万用表测 P0.0 到 P0.7 电压正常情况下应该接近 5V。5.2 湿度读数长期不变或固定为 0xFF现象整个系统能显示温度但湿度显示一直是 99%RH 或者 0不管环境怎么变化都不动。原因这个问题十有八九是 SHT10 的总线状态不对。SHT10 的 DATA 线如果没有上拉电阻读出来的数据会全是 1表现为湿度值最大。也可能是启动时序不对传感器进入不了测量状态。解决先查原理图确认 DATA 引脚有 10kΩ 上拉到 VDD。然后在初始化时强制调用一次 SHT_Reset把传感器状态恢复到一个干净的起点。最后用示波器或逻辑分析仪看 SCK 是否正常翻转如果 SCK 一直是高电平检查单片机引脚配置有没有被复用成其他功能。5.3 继电器吸合瞬间单片机重启现象风机或加热器一启动LCD 突然灭一下整个系统复位然后重新显示。原因这是电磁干扰和电源跌落叠加的结果。继电器线圈断电时会产生反向电动势没有续流二极管就会从驱动引脚反向串进单片机。同时继电器吸合瞬间电流很大如果电源线太细瞬间压降会把单片机电压拉到复位阈值以下。解决必须在继电器线圈两端反向并联 1N4007或者改用 ULN2003 这类自带续流的驱动芯片。单片机的电源入口加 100μF 电解电容和 0.1μF 瓷片电容继电器单独从 5V 总线上取电不要从单片机稳压输出后面取电。5.4 SHT10 测出来比环境湿度计偏高 2%RH 以上现象传感器放在空气中测得湿度 63%RH旁边一支标准湿度计只有 58%RH而且差值一直很稳定。原因SHT10 的湿度测量是相对湿度传感器自身发热会让芯片周围空气变热相对湿度偏小但如果不通风或者传感器离发热源太近读数又会偏高。还有一个原因是没有做温度补偿。解决把传感器放在粮仓检测点附近不要贴在单片机壳盖上。如果做验证可以将传感器和标准湿度计同时放入同一个密闭盒子里静置 10 分钟再读数。SHT10 数据手册里的湿度补偿公式可以处理大部分偏差常见做法是读取完成后用当前温度重新计算一次相对湿度值。5.5 工程编译提示 DATA 段溢出现象代码写完编译最后报 data 空间不足变量太多放不下。原因51 单片机的片上 RAM 只有 256 字节如果把显示缓存、传感器数组、按键标志全部定义成全局变量很容易超过 128 字节的内部低 128 字节空间。解决大数组和查表数据用 unsigned char code 放到程序 Flash 里不占 RAM。临时变量声明在函数内部让编译器复用栈空间。确实需要缓冲区时用 xdata 关键字放进外部 RAM但访问速度会慢一点。这个坑很隐蔽常常是写完了才发现改起来要动全局变量声明所以最好项目一开始就规划好内存布局。6. 进阶用法用串口把 SHT10 数据导出到 PC 做长时间标定如果你已经跑通上面的液晶显示和报警功能下一步不再是继续优化按钮而是先把数据导出到 PC做一整夜的温湿度标定。这样才能验证传感器和系统在长周期里是否稳定。AT89S52 自带的 UART 正好可以做这件事情。初始化时把串口设为模式 1波特率 9600用定时器 1 做波特率发生器。这样设置之后主循环里每隔 5 秒把读到的原始温度值、换算后的实际温度值、湿度值打包发送到上位机。串口发送函数可以这样写void UART_Init(void) { SCON 0x50; TMOD 0x0F; TMOD | 0x20; TH1 0xFD; TR1 1; } void SendByte(unsigned char ch) { SBUF ch; while (!TI) ; TI 0; } void SendFrame(unsigned int temp, unsigned int hum) { SendByte(0xAA); SendByte(temp 8); SendByte(temp 0xFF); SendByte(hum 8); SendByte(hum 0xFF); SendByte(0x55); }这里用的帧格式是起始字节 0xAA、两个字节温度、两个字节湿度、结束字节 0x55。PC 端用一个串口调试软件按十六进制接收再按同样的帧格式解析。帧头帧尾不能省否则没有串口工具的习惯下一旦丢一个字节后面所有数据就错位了。发送间隔可以用定时器或者主循环里软件计数控制串口本身速度够了。做标定时把传感器和标准温湿度计放进同一个密闭箱子先记录 10 组标准值再对比串口收到的换算值。如果偏差稳定在一个固定数值那不用急着改传感器可以直接在软件里加一个绝对偏差修正。如果偏差是变化的就要考虑温度补偿或者检查传感器是不是真的靠近粮堆的发热点。验证系统稳定性还有个习惯让继电器带一个 LED 灯模拟负载而不是直接接大功率设备先跑 24 小时看有没有误报警。继电器频繁吸合产生的温升会改变周围空气的温湿度传感器离继电器太近时这个偏差非常明显。把它当作黑匣子是行不通的必须让传感器暴露在实际安装位置的等效环境里。从那以后我每次拿到类似的项目资源都会先把串口调试通道加上再谈显示和控制。显示只能让你看见当前值串口数据才能告诉你系统真正稳不稳。这套粮仓温湿度控制项目里的硬件图纸、论文说明和完整 C 程序都是配套的如果只是想快速跑通一个最小可行系统直接照着本文第 2 章的选型和第 3 章的接线复现就够了。希望帮到你。本文还有配套的精品资源点击获取