资讯动态

基于51单片机的仓库湿度监测系统Proteus仿真与Keil源程序设计

发布时间:2026/9/13 11:14:08 来源:尧图企业网站定制
简介基于51单片机的远程仓库湿度监测系统仿真设计资料是一套面向51单片机学习者和嵌入式初学者的完整项目包适用于课程设计、毕业设计及物联网环境监测入门。系统以51单片机为控制核心结合湿度传感器与无线通信模块实现仓库湿度采集、处理和远程上报覆盖硬件组成、软件逻辑与仿真验证并包含初始化、数据采集、数据处理、无线传输等核心功能的代码实现。压缩包共20个文件、约65KB主要包含C源文件、Keil工程文件uv2/plg/opt、编译生成文件hex/obj/lst/m51和Proteus仿真文件DSN/DBK另含启动与备份文件便于直接查看代码或运行仿真。目前已有163人学习下载借助源码与仿真可直观掌握湿度采集、无线通信及程序设计等关键环节节省搭建与排错时间便于扩展报警、显示等功能。1. 远程仓库湿度监测为何要用51单片机仿真闭环看到“仿真设计资料”这类标题很多人第一反应是“是不是只要打开Proteus跑一下就行”。实际做一遍会发现真正的价值不在那个 .DSN 文件而是源程序怎么组织、DHT11 时序怎么在仿真模型里对得上、串口输出和 LCD 显示怎么并行不冲突。基于51单片机的远程仓库湿度监测系统本质上不是“读湿度”这一个点而是“单总线时序读取 数据显示 超限处理”三件事的合体。仓库场景要求 7×24 小时工作芯片选 51 除了成本低更因为这类环境不需要复杂操作系统单片机裸机轮询就能稳定覆盖。适合谁一种是准备课程设计或电赛基础题的人需要一份能讲清楚原理的完整工程另一种是想把 Proteus 仿真当作上位机联调手段的工程师。仿真不是玩具它可以先把协议、时序、代码分支验证掉再移植到实物板子减少烧录次数。这篇直接围绕 Keil C51 编写源程序、Proteus 搭建仿真文件、两者联调排错展开整个过程不依赖特定开发板核心代码和仿真思路可以完整落地到 STC89C52、AT89C51 等常见芯片上。2. 系统拆解与传感器、采样链路选型2.1 DHT11在仿真里的角色不是模拟量而是单总线时序器件远程仓库湿度监测传感器是最先要定下来的部分。常见的湿度方案有电容式模拟输出HS1101、I2C 数字输出SHT30和单总线数字输出DHT11。在 51 单片机上I2C 和单总线都需要软件模拟而 DHT11 是其中结构最简单、Proteus 支持最成熟的器件绝大多数 Proteus 8 以上版本自带 DHT11 模型。很多第一次做仿真的人会走弯路以为 DHT11 输出的是 0~5V 模拟电压于是把它接到 ADC0809 前面。这是错误的。DHT11 内部是电阻式感湿元件加 8 位单片机输出的是 40 bit 数字帧低位先出。51 单片机读 DHT11不是读电平高低而是“测量引脚被拉低的持续时间长短”来区分 0 和 1。在 Proteus 里DHT11 模型已经封装好了这些时序行为你只要按照数据手册时序去操作引脚就能读回正确数据。如果某版本 Proteus 的 DHT11 模型表现异常常见处理方法是给数据引脚外接一个 10kΩ 上拉电阻并在程序中放宽拉高采样窗口。2.2 51单片机资源规划晶振、引脚、串口与显示选型不是只看传感器单片机的引脚资源和外设要一起算。做一个仓库湿度监测最少需要1 个普通 I/O 口读 DHT111 个串口TXD/RXD用于远程上报1 个 I/O 控制声光告警或排风扇可选LCD1602 占 11 个 I/O 口51 单片机共 32 个 I/O 口即使接上 LCD1602 和告警灯资源仍然充足。我一般用 STC89C52RC 做实物因为它的内部时钟可以掉电不丢失但在 Proteus 里更常用 AT89C51模型稳定且加载 HEX 后立即运行。晶振选 12MHz 还是 11.0592MHz如果只接 DHT11 和 LCD两个都可以。如果需要和上位机串口通信建议直接用 11.0592MHz这样串口波特率 9600 的误差接近零。DHT11 时序对微秒级延时敏感Keil 编译后汇编指令周期会因优化级别变化所以延时函数最好用_nop_()加循环实测调参不要裸等。2.3 仿真的边界哪些能仿真哪些不能仿真美化Proteus 说得再万能也是有边界的。仓库湿度监测系统里有三个方面仿真和实物明显不同必须在设计资料里提前标注出来避免移植到实物时出错。项目Protesu 仿真行为实物行为DHT11 数据模型立即返回固定湿度值通常不随时间变化随环境湿度缓慢变化响应时间约 2 秒上拉电阻缺失时可能仍能工作因为模型内部理想化必须接 10kΩ 上拉否则时序不稳定串口输出用 Virtual Terminal 显示无电气噪声需要 USB-TTL 模块注意共地超限告警GPIO 拉高/拉低直接可见继电器驱动需要三极管或 ULN2003记住这个边界不是让你放弃仿真而是要设计出“仿真和实物代码尽量一致”的工程结构。DHT11 的读取函数、串口发送函数、阈值判断逻辑这三部分在仿真和实物中应该完全复用。只有 I/O 口定义和延时参数可能不同。3. 源程序的结构与编写用Keil C51实现数据采集和超限处理3.1 Keil工程划分与HEX生成设置源程序不是把全部逻辑塞进一个 main.c。51 单片机项目虽然不大但结构化文件有利于仿真阶段单独调试某一部分。我建议工程至少包含四个文件仓库湿度监测/ ├── main.c // 主流程、初始化、循环 ├── dht11.c // 单总线时序读取 ├── dht11.h // 引脚定义和函数声明 ├── uart.c // 串口初始化与发送 ├── uart.h └── lcd1602.c // 显示驱动可选dht11.h 里用宏定义引脚这样换板子时只改一行。示例#ifndef __DHT11_H__ #define __DHT11_H__ #include reg52.h sbit DHT11_DATA P2^0; unsigned char dht11_read_byte(void); unsigned char dht11_read_data(unsigned char *humidity, unsigned char *temperature); #endif在 Keil 里建工程时芯片选 AT89C51 还是 STC89C52 取决于你的 Proteus 元件库。两者寄存器基本兼容但reg52.h比reg51.h多了一些 SFR 定义而且定时器 2 在 STC89C52 上有独立模式。我通常直接用 AT89C51 建工程编译出的 HEX 在 Proteus 里加载最快。生成 HEX 文件时有一个必改项点击 Options for Target在 Output 选项卡勾选 Create HEX File。ROM 大小选择默认即可不需要对 51 做分页。3.2 DHT11时序起始信号、响应信号和位解析DHT11 的读操作分为三步主机拉低总线发起始信号、DHT11 拉低响应、连续输出 40 bit 数据。用代码表示如下#include reg52.h #include intrins.h sbit DHT11_DATA P2^0; void delay_us(unsigned int t) { while (t--) { _nop_(); } } unsigned char dht11_read_byte(void) { unsigned char i, value 0; for (i 0; i 8; i) { while (!DHT11_DATA); // 等待低电平结束 delay_us(40); // 40us后判断信号电平 if (DHT11_DATA) { value | 0x80 i; // 高电平持续为1 } while (DHT11_DATA); // 等待高电平结束 } return value; }这段代码的关键在delay_us(40)。DHT11 协议里一位数据用高电平持续 26~28us 表示 0用 70us 表示 1。主机在读总线时先等低电平结束然后延迟 40us 采样。如果此刻引脚为高说明是 1如果恢复低电平说明是 0。这个延迟不能改得太小否则会把 1 误判成 0。完整读取函数还需要处理起始信号和应答超时unsigned char dht11_read_data(unsigned char *humidity_l, unsigned char *humidity_h, unsigned char *temp_l, unsigned char *temp_h) { unsigned char check, i; DHT11_DATA 0; delay_us(25000); // 主机拉低 25ms发送起始信号 DHT11_DATA 1; delay_us(30); // 拉高 30us 后释放总线 if (DHT11_DATA 0) { // DHT11 拉低响应 while (DHT11_DATA 0); // 等待响应低电平结束 while (DHT11_DATA 1); // 等待高电平结束 for (i 0; i 5; i) { *humidity_l dht11_read_byte(); *humidity_h dht11_read_byte(); *temp_l dht11_read_byte(); *temp_h dht11_read_byte(); check dht11_read_byte(); } if (check (*humidity_l *humidity_h *temp_l *temp_h)) { return 1; // 校验通过 } } return 0; }读取的数据顺序是湿度整数、湿度小数、温度整数、温度小数、校验和。湿度小数和温度小数在 DHT11 上固定为 0但代码里仍然要按位接收因为后续更换 DHT22 或 AM2302 时同样的时序可以复用。3.3 串口输出与LCD1602双路显示仓库监测不只是本地看还需要把数据远程传回。在仿真里串口输出用 Proteus 的 Virtual Terminal 显示。初始化串口的关键是正确计算波特率重载值。void uart_init(void) { SCON 0x50; // 串口模式18位UART允许接收 TMOD 0x20; // 定时器1工作在模式28位自动重装 TH1 0xFD; // 9600波特率晶振11.0592MHz TL1 0xFD; TR1 1; // 启动定时器1 ES 1; // 开串口中断 EA 1; // 开总中断 }TH1 0xFD对应 11.0592MHz 晶振下 9600 波特率。如果你的仿真文件用 12MHz 晶振且不改这个值串口输出会出现乱码。这是远程仓库监测系统仿真中最常见的坑之一。发送字符串可以写成简单轮询函数不用中断void uart_send_string(unsigned char *str) { while (*str) { SBUF *str; while (!TI); TI 0; } }LCD1602 显示则建议只显示两行第一行是 HUM: 65%RH第二行是 TEMP: 26C。在仿真文件里LCD 初始化时序比很多外围设备苛刻需要连续延时等待模块内部复位。如果 LCD 显示花屏优先检查 P0 口是否接上拉电阻Proteus 的 LCD 模型对 P0 开漏行为非常敏感。3.4 编译参数内存模型与优化级别Keil C51 的默认编译参数对小型 DHT11 项目不会出大问题但有两个参数需要主动确认。第一个是 Memory Model默认 Small 模式下变量默认放在 DATA 段51 的内部 RAM 只有 128 字节DHT11 的临时变量加上串口缓冲区很容易超过。我一般把串口缓冲区定义为unsigned char code存放到程序区或改为 Large 模式但 Large 模式下所有变量都走外部 RAM仿真速度会稍微变慢。第二个是优化级别。Keil 默认编译优化是 Level 8会重新调整指令顺序这种优化对 DHT11 这类微秒级延时函数影响极大。一个 40us 的延时在优化后可能只剩十几个微秒导致读到的数据全部为 0xFF。遇到这种情况把 dht11.c 文件的优化级别单独设为 Level 0同时勾选“在文件级别使用优化选项”。4. Proteus仿真文件的搭建与联调排错4.1 新建DSN并放置元件清单仿真文件的核心是 Proteus 的 DSN 工程。从零搭一个仓库湿度监测仿真需要放置的元件并不多但少了任何一个都会导致工作状态不对。我通常按下列清单摆放元件库中名称数量作用单片机AT89C511主控湿度传感器DHT111湿度数据源虚拟终端VIRTUAL TERMINAL1串口数据分析LCDLM016L1本地显示电阻RES3P0上拉、DHT11上拉、复位电容CAP2晶振负载电容晶振CRYSTAL111.0592MHz发光二极管LED-RED1超限告警放置元件后先连线再设置属性。AT89C51 的 XTAL1 和 XTAL2 接晶振两端每个引脚再接一个 30pF 电容到地。RST 引脚接 10uF 电容到 VCC再接 10kΩ 电阻到地这是 51 最常用的上电复位电路。DHT11 的 VCC 接 5VGND 接地DATA 引脚直接连 P2.0同时在 DATA 和 VCC 之间放一个 10kΩ 上拉电阻。Proteus 的 DHT11 模型内部有弱上拉但外部上拉更接近真实电路。4.2 加载HEX、设置时钟频率与运行HEX 文件是 Proteus 和 Keil 之间的连接点。双击 AT89C51 芯片在 Program File 一栏选择 Keil 编译输出的 .hex 文件。这里有一个细节如果 Keil 工程和 Proteus 工程不在同一目录加载后改过代码重新编译Proteus 里不会自动更新需要再次手动指定文件或点击 Load 按钮刷新。改变量设置时钟频率位置在同一个对话框里Edit Component 的 Clock Frequency 默认是 1MHz必须改成 11.0592MHz。很多人只改了晶振属性忘了改芯片的 Clock Frequency结果程序时序完全不对。正确做法是两者都改成 11.0592MHz。运行仿真前先按暂停键确认虚拟终端和 LCD 都处于激活状态。然后点击运行观察 DHT11 的引脚波形。如果 DHT11 正确响应P2.0 引脚上会出现明显的连续窄脉冲这个脉冲在示波器上可以清楚看到。4.3 仿真不出的几个典型原因仿真不出结果时不要急着改代码按照从硬件到软件的思路排查。第一个典型原因是“湿度显示全为 255”。这种情况基本是 DHT11 时序读取失败程序每次都走到超时分支。先检查 dht11_read_data 里的起始信号延时Proteus 模型对 25ms 拉低是严格要求的如果改成 18ms模型会不响应。另外确认单总线引脚定义和 Proteus 连线一致比如代码里是 P2.0连线却接到了 P2.1。第二个典型原因是“Virtual Terminal 不显示任何内容”。先看串口使能代码有没有加TR1 1再看晶振频率和波特率计算值是否匹配。如果晶振是 12MHzTH1 就应该是 0xE8 而不是 0xFD。可以用 IDE 的调试器查看串口发送函数的行号配合 Proteus 示波器观察 TXD 引脚波形。第三个典型原因是“LCD 亮但不显示字”。多半是 P0 口没有加上拉电阻。Proteus 的 LM016L 模型要求 P0 口有上拉否则高电平无法正确传输数据。在 P0.0~P0.7 各接一个 4.7kΩ 上拉电阻到 VCC 即可。还有一类问题是仿真速度实时性。Proteus 在 Debug 菜单里可选择 Run at Real Time如果你发现 Virtual Terminal 接收速度非常快且数据错乱可能是当前处于 Maximum Simulation Speed此时串口时序会被压缩。5. 让仿真更接近现场阈值告警与数据校验的进阶设置5.1 湿度超限控制继电器/风扇仓库湿度监测的分水岭在看阈值告警。只读湿度不算完要能在超过 70%RH 时自动拉高一个 I/O 口用来驱动继电器或风幕机。在源程序里加一个结构体保存湿度上下限每次读取成功后判断并留出回差防止继电器频繁抖动。#define HUMIDITY_ALARM_SETPOINT 70 void process_humidity(unsigned char humidity) { if (humidity HUMIDITY_ALARM_SETPOINT) { ALARM_PIN 1; // P3.3 拉高告警或开启排风扇 } else { ALARM_PIN 0; } }在 Proteus 里ALARM_PIN 连接一个 LED 和一个 1kΩ 限流电阻到 VCC用 LED 亮灭模拟排风扇启停。如果需要仿真完整的继电器动作可以加一个 RELAY 元件让单片机输出驱动继电器线圈再用继电器触点控制交流负载模型。5.2 用虚拟终端校验协议远程监测的核心是“数据出去要能对得上”。实物项目里上位机可能会发 Modbus-RTU 或自定义帧仿真阶段必须先用虚拟终端验证帧格式。DHT11 读到的湿度是一字节整数包装成 ASCII 帧更利于排错。unsigned char tx_buf[32]; sprintf(tx_buf, H:%02dRH T:%02dC\r\n, humidity, temperature); uart_send_string(tx_buf);sprintf 在 Keil C51 中默认会占用较多代码空间如果遇到L107函数未定义错误需要在工程设置里把 printf 重定向为输出到串口。更轻量的做法是手动拼帧tx_buf[0] H; tx_buf[1] R; tx_buf[2] (humidity / 10) 0; tx_buf[3] (humidity % 10) 0; tx_buf[4] %; tx_buf[5] \r; tx_buf[6] \n;建议连一个“帧尾校验”逻辑在发送内容后追加一个字节的异或校验值虚拟终端上能看到每帧最后一个字符会随数据内容变化。这样将来接真实上位机时只需把校验字节解析逻辑保留即可不用重写发送模块。5.3 快速验证清单验证项预期结果DHT11 初始读取虚拟终端显示固定湿度值无 FF 字符串口波特率终端每秒输出 1 帧无乱码LCD 显示第二行温度值与 DHT11 数值一致湿度阈值调整上限改为 50 后 LED 应立即点亮起始信号时序示波器可见约 25ms 的低电平脉冲上拉电阻移除DHT11 数据异常或温度显示全零把温度阈值也做成宏定义便于观察。仓库环境是季节变化很大的场景夏季 26℃、冬季可能低于 10℃仿真里虽然 DHT11 模型不温度波动但代码结构上要把温度数据同时传给上位机和显示缓冲区而不是只处理湿度。这一步做到后续扩展成“温湿度双告警”或者改用 SHT30 传感器都只需要修改底层读取函数。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价