简介:这是一套面向51单片机学习者的环境监测系统完整资料,涵盖温度、湿度、光照强度、硫化氢浓度和模拟量采集。系统使用液晶屏实时显示监测数值,支持按键切换四类参数、修改上下限阈值,一旦越限便发出不同声音并点亮对应LED,同时通过继电器控制中央空调、电动窗帘、空气净化器等模型设备实现自动调节,具备报警自动停止等细节设计,适合课程设计、毕业设计或电子竞赛项目参考。压缩包共56个文件,大小约1.4MB,以C语言源代码、Proteus仿真工程、原理图、流程图、物料清单和设计说明文档为主,还包含可直接烧录的Hex文件,便于在Keil与Proteus中快速打开运行、对照学习。目前已有602人学习使用。整套资料从传感器采样、数据处理到继电器控制均有完整呈现,能帮助读者掌握多参数环境监测系统的总体框架与代码实现,尤其是阈值设定、报警联动、按键交互等模块的编写技巧,有效节省方案设计与调试时间。
1. 先拆需求:这套51单片机环境监测系统到底在测什么
拿到“基于51单片机的环境监测(温湿度、光照、硫化氢、气净化器)”这类课设题,不少人第一反应是“传感器采集+显示+超限报警”。但看完整串交付物——proteus、原理图、流程图、物料清单、仿真图、源代码,就知道要求的是“一整套能闭环的工程包”。这套系统的测点并不少:温湿度用DHT11,光照用光敏电阻转模拟量,硫化氢用MQ系列气体传感器输出电信号,两路模拟量通过ADC0832送给51单片机,最后按浓度阈值驱动继电器控制净化器启停。常见Proteus仿真51单片机课程设计的坑,也从“代码能不能跑”转移到了“采集电路和时序对不对”。文章按选型、采集、仿真、代码、实物验证的顺序展开,适合课设、毕设或第一次用Proteus做完整仿真的人照着搭。
2. 温湿度与光照采集电路:DHT11和光敏电阻在Proteus里怎么接
2.1 DHT11单总线数据格式与上拉电阻
DHT11走的是单总线,数据脚一根线既要输出又要读入,空闲时靠4.7kΩ上拉电阻维持高电平。51单片机把数据线拉低至少18ms再释放,传感器会回一个80us低电平和80us高电平,随后输出40位数据:湿度整数、湿度小数、温度整数、温度小数、校验和。只有当湿度整数+湿度小数+温度整数+温度小数的低8位等于校验字节时,这次读取才算成功,否则直接丢弃比显示一个错误值更安全。DHT11供电范围虽然从3.3V到5.5V都能工作,但在51系统里建议直接统一5V供电,避免数据线上的高电平低于51的输入门限,仿真里也尽量照实物的5V来画。
提示:DHT11连续两次读取之间至少隔500ms,实物上隔1s更稳。仿真里延时不严格,但实物拉低时间低于10ms常常读不到响应。
2.2 光敏电阻分压和ADC0832的CH0
光照检测不推荐直接读引脚电平,因为“亮/暗”在连续环境里是渐变过程。常见做法是用光敏电阻和一个10kΩ电阻串联分压,分压点接ADC0832的CH0。光敏电阻在暗处阻值变大,分压点电压升高,ADC数字量变大;光照增强后阻值下降,电压变小。所以显示光照度时要么直接显示电压,要么用255 - adc_value把量程反过来,代码里统一方向就行。ADC0832只有8位分辨率,对应0~5V量程时每一步约19.6mV,对光照这种缓慢变化量完全够用,没必要上12位的ADC0809或者STC12内置ADC。
Proteus里搜LDR可以找到光敏电阻模型,也可以直接用一个POT电位器模拟分压:用手动调节电位器来等效光照变化。这个技巧在验证ADC时序时比找光照模型更省时间,因为它不依赖仿真器是否真的改变照度。
2.3 Proteus接线表与引脚定义
下表是采集部分的信号分配,也可以当作原理图连线清单直接用。
| 信号 | 接51单片机的引脚 | Proteus元件名 | 说明 |
|---|---|---|---|
| DHT11 DATA | P2.0 | DHT11 | 数据线上加4.7kΩ上拉到VCC |
| ADC0832 CS | P2.1 | ADC0832 | 片选,低有效 |
| ADC0832 CLK | P2.2 | ADC0832 | 时钟输入 |
| ADC0832 DIO | P2.3 | ADC0832 | 发送配置位后转为读取数据 |
| 光敏电阻输出 | ADC0832 CH0 | LDR / POT | 与10kΩ分压后接入 |
| MQ系列AO输出 | ADC0832 CH1 | MQ-135 / POT | 传感器的模拟电压输出 |
对应的引脚定义在代码里写成这样:
// 传感器与ADC引脚定义(Proteus仿真与实物共用) sbit DHT_DATA = P2^0; // DHT11数据线,默认带上拉 sbit ADC_CS = P2^1; // ADC0832片选,低有效 sbit ADC_CLK = P2^2; // ADC0832时钟 sbit ADC_DIO = P2^3; // ADC0832数据口,发送配置和读取数据共用ADC_DIO在51的准双向口模式下,读数据前要先把引脚写1,否则外部低电平拉不进去。这句话在后面ADC0832的读取函数里会再次用到,接线时不要把DI和DO分成两个引脚接,除非你在Proteus里用的是带独立DO引脚的模型。接好线后先别急着写代码,把一个电压表接到光敏电阻分压点,手动调LDR属性或电位器,看电压是否在0~5V之间变化。如果电压不动,说明接地和VCC网络没连上,或者分压电阻的一端悬空,这一步能在写代码前提前暴露原理图连线问题。
3. 硫化氢检测与净化器联动:MQ-135模拟量输入和继电器输出
3.1 MQ系列气体传感器的输出与负载电阻选择
MQ系列传感器输出的是“气敏电阻”变化,不是标准电压信号。传感器内部有加热丝和敏感层,通电后表面电导率随被测气体浓度变化,对应输出端的电阻Rs改变。气体浓度越高,Rs越小,负载电阻RL两端的电压越高。硫化氢检测可以选MQ-136,但Proteus元件库中该模型不一定齐全,课设里用MQ-135做室内空气污染度演示很常见,能体现“有害气体→模拟量→阈值报警→净化器启动”这条闭环链路。RL取10kΩ比较稳,想提高低浓度灵敏度可以换成20kΩ,代价是浓度高时更容易饱和,ADC读满量程后就看不出梯度了。
3.2 用ULN2003驱动净化器继电器,加回差判断
净化器这类执行器用一个继电器控制最直接,但51单片机的IO驱动能力远不够直接吸合继电器线圈。常见做法是IO先给ULN2003,ULN2003内部达林顿管把电流放大后再驱动继电器,继电器线圈两端并联续流二极管,防止断电瞬间反电动势打坏IO。判断逻辑上要加回差,不然气敏电压停在阈值附近时,继电器会反复吸合断开,轻则噪音,重则烧触点。常见的写法是:
#define H2S_ON_V 2.0 // 启动净化器的电压阈值 #define H2S_OFF_V 1.8 // 关闭净化器的电压阈值 float h2s_volt; // 硫化氢传感器经ADC换算后的电压 if (h2s_volt >= H2S_ON_V) { RELAY = 1; // 浓度高,打开净化器 } else if (h2s_volt <= H2S_OFF_V) { RELAY = 0; // 浓度回落后关闭 }H2S_ON_V和H2S_OFF_V之间留出0.2V的回差,作用是让继电器在2.0V才吸合、降到1.8V才释放,中间区间只保持当前状态。如果传感器接法是“浓度高反而电压低”,就把两个比较方向反过来,判断核心是“电压和浓度之间的单调关系必须和代码里的比较方向一致”。
3.3 Proteus里模拟气体浓度变化与联动验证
仿真里没有真实气体瓶,用一个电位器从1V到3V慢慢调,就能骗过整个控制链路。把电位器抽头接ADC0832的CH1,程序跑起来后从1.5V往上拧,超过2.0V时继电器模型应该吸合;往回拧到低于1.8V才释放。如果继电器反应和阈值不一致,先查ADC0832读到的数字量是不是随电位器线性变化,再用电压表直接量电位器抽头电压核对。下面是传感器与执行器的信号对照表,画原理图时可以直接照抄:
| 对象 | 传感器/器件 | 输出/输入 | 接到哪里 | 信号含义 |
|---|---|---|---|---|
| 温湿度 | DHT11 | 单总线数字量 | P2.0 | 40bit数据帧 |
| 光照 | 光敏电阻分压 | 0~5V模拟量 | ADC0832 CH0 | 电压随光照反向变化 |
| 有害气体 | MQ-135 / MQ-136 | 0~5V模拟量 | ADC0832 CH1 | 浓度越高电压越高 |
| 净化器 | 继电器+风扇 | 开关量 | P1.7经ULN2003驱动 | 高电平吸合 |
P1.7这个控制引脚在代码里用sbit RELAY = P1^7;定义,接线顺序、原理图网络标号和代码定义三处必须一致。仿真里用直流小风扇模型就行,不需要真的接220V负载,安全上也更合适。净化器本身不是传感器,程序里只做继电器翻转,不关心风扇转速,这也是这套系统里最省钱、最容易验证的执行机构。
4. 仿真图与原理图落地:最小系统、LCD1602和物料清单
4.1 最小系统与LCD1602接线
51单片机最小系统由AT89C52、12MHz晶振、两个30pF负载电容和复位电路构成。EA脚(31脚)接VCC,否则单片机内部ROM不工作,加载的hex代码不会执行。这个问题在Proteus里不报错、不提示,很多人把时间耗在了排查“为什么LCD不亮”。显示部分在Proteus里搜LM016L,就是LCD1602模型,引脚和实物完全一致。数据线D0~D7接P0口,P0口必须外接10kΩ排阻上拉,RS接P3.5、RW接P3.6、E接P3.4。仿真图上如果不加上拉电阻,LM016L也能正常显示,因为Proteus对P0开漏模拟得不够严格;但实物打样时少了这8个上拉电阻,LCD显示会满屏方块或者直接白屏。
4.2 在Proteus 8里加载hex文件并跑仿真图
Proteus仿真的核心操作是给单片机加载程序文件。双击AT89C52元件,在Program File一栏选择Keil生成的hex文件,Crystal Frequency填12MHz,然后点运行。这个步骤每次重新生成hex后都要重复一遍,Proteus不会自动追踪Keil的输出文件。Proteus 8的主运行程序是pds.exe,如果桌面上双击图标没反应,可以到安装目录下用命令行启动项目文件:
pds.exe 51_env_monitor.pdsprj前提是安装目录已经加入PATH,否则用完整路径运行。路径里不要带中文或空格较多的目录名,否则Proteus偶尔会加载不出元件库。跑起来之后,用Voltage Probe点选模拟量节点,可以边调电位器边看电压变化,比用LCD显示中间量更直观。原理图层面不建议一开始就把所有元件堆在一起,先分区域排布,电源和地统一用+5V、GND网络标号,最后导出PDF时把图纸设置成一张A4就能交。
4.3 物料清单和引脚分配表
交付课设时,物料清单直接给表格就行:
| 编号 | 物料 | 规格 | 数量 | 用途 |
|---|---|---|---|---|
| 1 | 单片机 | AT89C52 / STC89C52 | 1 | 主控 |
| 2 | 晶振 | 12MHz | 1 | 时钟 |
| 3 | 瓷片电容 | 30pF | 2 | 晶振负载 |
| 4 | 电解电容 | 10uF/16V | 1 | 复位电路 |
| 5 | 电阻 | 10kΩ | 若干 | 复位、分压 |
| 6 | 电阻 | 4.7kΩ | 1 | DHT11上拉 |
| 7 | 排阻 | 10kΩ×8 | 1 | P0上拉 |
| 8 | 温湿度传感器 | DHT11 | 1 | 温湿度采集 |
| 9 | 光敏电阻 | LDR | 1 | 光照采集 |
| 10 | ADC芯片 | ADC0832 | 1 | 两路模拟量采集 |
| 11 | 气体传感器 | MQ-135或MQ-136 | 1 | 有害气体/硫化氢检测 |
| 12 | LCD | LM016L/1602 | 1 | 数据显示 |
| 13 | 驱动芯片 | ULN2003 | 1 | 继电器驱动 |
| 14 | 继电器 | 5V继电器模块 | 1 | 净化器开关 |
| 15 | 风扇 | 5V直流风扇 | 1 | 模拟净化器 |
引脚分配建议再单独列一页:P0给LCD数据,P3.4/P3.5/P3.6给LCD控制,P2.0给DHT11,P2.1/P2.2/P2.3给ADC0832,P1.7给继电器。这样原理图、源码、BOM三份材料一一对应,评审问起来不会现场乱翻。
5. 程序流程图与源代码结构:DHT11时序、ADC0832读数与阈值控制
5.1 主循环骨架:采集、显示、控制三件事
程序不建议把每个传感器都塞到同一个大循环里写,而是拆成“读DHT11、读两路ADC、换算显示、控制继电器”四个独立函数。主循环只负责调用和延时,方便在Proteus里单步调试。
void main(void) { unsigned char humi = 0, temp = 0; // DHT11读数 unsigned char err_cnt = 0; // DHT11连续失败计数 unsigned char light = 0, h2s = 0; // 两路ADC原始值 float h2s_volt = 0; // 硫化氢传感器电压 sys_init(); // 关闭看门狗、配置定时器等 lcd_init(); // LCD1602初始化 RELAY = 0; // 开机默认关闭净化器 while (1) { if (!dht11_read(&humi, &temp)) { err_cnt++; // 连续读取失败时保留上次显示值 } else { err_cnt = 0; } light = read_adc0832(0); // CH0:光照分压 h2s = read_adc0832(1); // CH1:硫化氢传感器 h2s_volt = h2s * 5.0 / 255.0; // 数字量转电压 if (h2s_volt >= H2S_ON_V) { RELAY = 1; } else if (h2s_volt <= H2S_OFF_V) { RELAY = 0; } lcd_display(humi, temp, light, h2s_volt); delay_ms(200); } }主循环每200ms刷新一次,DHT11本身响应周期接近秒级,200ms轮询完全够。err_cnt在这里只做标记,更稳的做法是连续失败3次后显示--,而不是一直保留旧数据,看你答辩时想强调哪方面的健壮性。
5.2 DHT11读取时报文的时序关键点
DHT11的时序窗口在微秒级,代码里最容易出问题的是主机起始信号拉低时间和数据位采样点:
bit dht11_read(unsigned char *humi, unsigned char *temp) { unsigned char i, j, buf[5] = {0}; DHT_DATA = 0; delay_ms(20); // 起始信号:拉低至少18ms DHT_DATA = 1; delay_us(30); // 释放后维持高电平20~40us if (DHT_DATA == 0) // 传感器应答 { while (DHT_DATA == 0); // 跳过80us应答低电平 while (DHT_DATA == 1); // 跳过80us应答高电平 for (i = 0; i < 5; i++) { for (j = 0; j < 8; j++) { while (DHT_DATA == 0); // 等待数据位开始 delay_us(40); // 延时后采样 buf[i] <<= 1; if (DHT_DATA == 1) { buf[i] |= 0x01; // 高电平>50us视为逻辑1 } while (DHT_DATA == 1); } } if (buf[4] == ((buf[0] + buf[1] + buf[2] + buf[3]) & 0xFF)) { *humi = buf[0]; *temp = buf[2]; return 1; } } return 0; }delay_us(40)的时间精度直接影响数据位判断。数据位的高电平持续26~70us,在40us处如果还是高电平,说明这是一位长高电平的数据“1”,否则是“0”。单片机C语言编译出来的软延时会有几条指令误差,仿真能跑不一定实物能跑,建议实物阶段用逻辑分析仪看一下数据线上的电平宽度。
5.3 ADC0832双通道读数和净化器回差控制代码
ADC0832用软件模拟时序读取,CH0和CH1的选择完全靠发送的配置位决定:
unsigned char read_adc0832(unsigned char ch) { unsigned char i, dat = 0; ADC_CS = 0; // 片选拉低,启动一次转换 ADC_CLK = 0; ADC_DIO = 1; // 起始位 ADC_CLK = 1; ADC_CLK = 0; ADC_DIO = 1; // 选择单端模式 ADC_CLK = 1; ADC_CLK = 0; ADC_DIO = (ch & 0x01); // 0选择CH0,1选择CH1 ADC_CLK = 1; ADC_CLK = 0; ADC_DIO = 1; // 释放数据线,准备读 for (i = 0; i < 8; i++) { ADC_CLK = 1; ADC_CLK = 0; dat = (dat << 1) | ADC_DIO; // 每个时钟下降沿读一位 } ADC_CS = 1; return dat; }ADC0832是8位ADC,满量程255,对应0~5V,电压换算公式就是dat * 5.0 / 255.0。如果Proteus里发现CH1读到的数值和CH0一样,基本是配置位顺序错了,重点检查第二次ADC_DIO之后写的通道选择位有没有被时钟沿冲掉。
5.4 交付流程图时画到哪个粒度
流程图不用画到每条语句,但分支条件必须画清楚。常见的主流程节点是:系统初始化 → 读取DHT11(失败则跳过该次刷新) → 读取ADC0光照 → 读取ADC1气体 → 电压换算 → 回差判断控制继电器 → 刷新LCD → 延时200ms → 回到读取DHT11。回差判断处画两个菱形框:电压 >= 2.0V 开继电器,另一个是电压 <= 1.8V 关继电器,中间状态画一条回归线,评审看到这两个阈值就知道程序不会在临界点抖动。源码注释里的阈值常量最好和流程图上的数字一致,避免答辩时“图和代码对不上”这种低分问题。
6. 从仿真图转到实物的3类坑和验证方法
6.1 仿真能跑实物不亮的3个原因
Proteus仿真图能跑通,实物一上电就白屏或没反应,优先查三个点:第一,晶振和复位电路是否完整,EA是否接VCC;第二,P0口排阻上拉是否虚焊,LCD数据线如果飞线,多根线长度不一致也会出现乱码;第三,DHT11的数据线是否真的接了4.7kΩ上拉,仿真模型对浮空输入不敏感,实物CMOS输入悬空时电平会随机漂移,DHT11会一直不出应答。
6.2 上电误报处理与继电器保护
MQ系列气体传感器刚上电时内部加热丝温度还没稳定,模拟量输出会先冲高一两秒再回落。净化器直接按电压阈值控制,开机瞬间继电器就吸合,之后又释放,看起来像“自检”,实际上容易让评委误判逻辑。软件上可以在主循环加入开机屏蔽:上电前10秒只采不判,或者要求ADC值连续两次超过阈值才吸合。硬件上继电器驱动必须用ULN2003或三极管加续流二极管,测试时用5V直流风扇代替220V负载,防止裸露触点碰到实验板。
6.3 三步闭环验证技巧
打完样后按“传感器单测 → 执行器单测 → 闭环联调”的顺序验证。先不断开净化器,在程序里写一个临时循环,手动给继电器引脚电平翻转,听风扇有没有吸合声;再单独读一路ADC,把读到的原始值通过LCD显示出来,用手挡住光敏电阻看数值是否上升;最后才把回差控制打开,用酒精棉球靠近气体传感器制造挥发气体,观察风扇启动和停止的电压点是否和设定值一致。全流程最后用万用表量一下ADC输入引脚的对地电压,如果电压确实随环境变化但LCD读数不动,问题集中在ADC时序或通道切换上;如果电压本身不动,就回头查传感器供电和分压电阻,这个顺序能帮你把“仿真通了但实物不亮”缩小到某一根线上。
本文还有配套的精品资源,点击获取