简介:基于AT89C51单片机的大棚温湿度控制系统设计文档,面向电子工程、农业自动化及单片机应用开发方向的师生和爱好者,解决传统大棚人工监测效率低、精度差的问题。文档围绕AT89C51与SHT11传感器展开,完整涵盖硬件电路设计、温湿度数据采集与处理、LCD实时显示、键盘扫描参数设置以及执行机构控制逻辑,并给出C语言程序框架与抗干扰设计思路。系统可实现温湿度自动监测与调节,用户可设定上下限阈值,适应不同作物生长需求。资源为单个docx文件,大小1.11MB,内容结构清晰,包含中英文摘要、系统背景、硬件与软件设计等完整章节,可直接用于课程设计、毕业设计或实际项目参考。目前已有213人学习,适合需要快速掌握单片机温湿度控制系统完整设计流程的读者。
1. 大棚温湿度控制系统设计,为什么还选AT89C51
接手这个题目,很多人第一反应是上基于STM32的环境温湿度监测控制系统。但真去算物料成本,AT89C51、5V电源、LCD1602加继电器模块就能把主控部分压在二十元以内,而STM32的BOM和调试器成本都会翻倍。大棚不是桌面实验室,供电波动大,执行器件是加热器、风扇和水泵这些大功率负载,AT89C51外设少,反而让干扰入口少。这个系统的核心不是高精度闭环,而是把温湿度采进来、显示出来,再按设定阈值驱动对应执行机构。只要采集边界和控制逻辑定清楚,这颗老内核完全能扛住。
2. 大棚温湿度控制系统的传感器选型与驱动电路设计
2.1 传感器怎么选:DHT11、DHT22还是DS18B20加HS1101
传感器选型直接决定采集数据的质量。常见的温湿度传感器方案有三条路线:DHT11、DHT22,以及DS18B20加HS1101湿度敏感电容。大棚环境温度范围一般在0到50℃之间,湿度长期偏高,目标成本越低越好。DHT11的测量精度为±2℃和±5%RH,分辨率1℃,采样周期1s,足够判断加热和加湿的开关点。DHT22精度更高,但价格是DHT11的三倍左右。DS18B20只管温度,湿度需要另配HS1101,通过555振荡电路或运放把电容变化转成频率或电压,电路复杂度明显上升。
| 方案 | 接口 | 测温范围 | 精度(典型) | 成本 | 适用场景 |
|---|---|---|---|---|---|
| DHT11 | 单总线 | 0~50℃ | ±2℃ / ±5%RH | 低 | 普通大棚、烘干房 |
| DHT22 | 单总线 | -40~80℃ | ±0.5℃ / ±2%RH | 中 | 育苗棚、恒温房 |
| DS18B20+HS1101 | 单总线+模拟 | -55~125℃ | 湿度需标定 | 高 | 低温或强干扰环境 |
DHT11采用单总线协议,所有40位数据只靠一根线传输,位0和位1的时间宽度不同。读完一次要等1秒才能再读。下面这段读取单字节的代码是AT89C51上常见做法。
unsigned char read_byte_dht11(void) { unsigned char i, dat = 0; for (i = 0; i < 8; i++) { while (P3_3 == 0); /* 等数据线从低拉高,标记一位开始 */ delay_us(28); /* 延时28us后判断电平 */ if (P3_3 == 1) { dat |= (0x80 >> i); /* 数据位为1 */ while (P3_3 == 1); /* 等位结束,回到低电平 */ } } return dat; }这个函数依赖精确的延时,要求晶振12MHz,delay_us用四个NOP指令组保证大约28us。DHT11的数据位0高电平维持26到28us,位1高电平维持约70us,如果在28us后读到的仍是高,就判定为1。如果while(P3_3==0)那里卡死,通常是起始信号拉低时间不够18ms,或者数据线没加上拉电阻。
2.2 继电器驱动与光耦隔离:别让感性负载毁掉AT89C51
AT89C51的IO口高电平驱动能力很弱,P1口输出高电平时的拉电流不到1mA,不能直接驱动继电器。常见的做法是用S8050三极管做开关,基极串联1kΩ电阻接到51的引脚,继电器线圈接在三极管集电极到5V之间。线圈两端必须反向并联1N4148二极管,否则继电器断电瞬间会产生几十伏反电动势,打穿IO口。
更进一步,在强电侧和单片机侧之间加PC817光耦,把220V的加热器、水泵与51系统完全隔开。选择继电器时注意线圈电压5V,触点容量要按负载电流的1.5倍选,加热器用10A继电器,风扇和水泵用5A。
| 负载 | 继电器触点容量 | 驱动管 | 隔离器件 |
|---|---|---|---|
| 加热器(220V/500W) | 10A | S8050或ULN2003 | PC817 |
| 排风扇 | 5A | S8050 | PC817 |
| 水泵 | 5A | S8050或ULN2003 | PC817 |
MCU电源和继电器电源不要共用同一条PCB走线,即使共用5V,也要在继电器供电入口放一个100uF电解电容和一个104瓷片电容,给吸合瞬间的电流尖峰一个泄放通道。
2.3 LCD/按键/IO分配:51的引脚资源怎么安排
显示部分用1602液晶最省事,数据口接到P0,三根控制线接P2.0到P2.2。AT89C51的P0是开漏输出,必须外接10kΩ排阻上拉。按键用三个:设置、加、减,分别接P1.4到P1.6。DHT11数据线接P3.3,继电器控制接P3.4到P3.6。这样剩下P1口还能接低电平有效的蜂鸣器报警。
| 引脚 | 功能 | 备注 |
|---|---|---|
| P0.0~P0.7 | LCD1602 D0~D7 | 需要10k上拉 |
| P2.0~P2.2 | LCD RS、RW、EN | 无 |
| P1.4~P1.6 | 设置键/加/减 | 低电平有效 |
| P3.3 | DHT11数据 | 接4.7k上拉 |
| P3.4 | 加热器继电器 | 低电平吸合 |
| P3.5 | 排风扇继电器 | 低电平吸合 |
| P3.6 | 水泵继电器 | 低电平吸合 |
复位电路用10uF电解电容加10kΩ电阻,晶振用12MHz,两个30pF负载电容。如果使用USB供电,要把复位上电时间拉长一点,否则上电瞬间51有时不进主程序。
3. AT89C51大棚温湿度控制系统的核心逻辑:状态机、滞回控制与软看门狗
3.1 主循环状态机
总体程序可以写成一个简单的状态机:系统上电后先初始化LCD、定时器、EEPROM和IO,然后循环执行采集、显示、控制、喂狗。下面给出主函数的骨架。
void main(void) { unsigned char temp, humi; init_lcd1602(); init_timer0_wdt(); read_threshold_from_eeprom(); while (1) { if (read_dht11(&temp, &humi) == 0) { refresh_lcd(temp, humi); control_temp(temp); control_humi(humi); alarm_check(temp, humi); } feed_soft_wdt(); delay_ms(500); } }这里read_dht11成功返回0,失败返回1。如果传感器未响应就不刷新控制,避免在读到0xFF时直接把加热器关掉或打开。控制周期取500ms,和DHT11的采样速率匹配。不要在一个周期里连续多次读取,DHT11两次读之间必须间隔至少1秒。
3.2 滞回控制解决继电器频繁吸合
大棚控制系统最常见的故障是继电器在设定点附近频繁吸合。如果只做单阈值比较,温度在26度附近抖动,继电器会咔嗒响个不停,触点寿命很快耗尽。解决办法是在温度和湿度控制中加入滞回区间。
温度控制逻辑:当温度低于下限temp_low时打开加热,关闭排风扇;当温度高于上限temp_high时关闭加热,打开排风扇;在两个值之间时保持上次动作不变。这样实际控制的开启点在temp_low,关闭点在temp_high,中间形成滞回带。
sbit HEATER = P3^4; sbit FAN = P3^5; void control_temp(unsigned char t) { if (t <= temp_low) { HEATER = 0; /* 低电平驱动,表示吸合加热 */ FAN = 1; } else if (t >= temp_high) { HEATER = 1; FAN = 0; } /* 上下限之间保持现状,不改变输出 */ }temp_low和temp_high是用户设定的温度下限和上限。这个函数用低电平驱动,因为继电器板大多做成低电平触发。如果使用高电平触发模块,要把赋值反过来。湿度采用相似结构,湿度过低时打开水泵或加湿器,湿度过高时打开排风扇,控制目标通常是相对湿度60%到70%。
如果大棚里同时有温度风机和湿度风机,建议不要直接共用一个排风扇,否则夏天降温又会把湿度带低。可以加一个手动模式,通过按键切换自动/手动,这样维护人员可以在设备异常时强制启停。
3.3 阈值掉电保存与软看门狗
设定的温湿度上下限必须掉电保存,常见做法是外接一颗AT24C02。AT24C02是I2C接口,AT89C51用软件模拟SCL和SDA即可,不需要硬件I2C。写入时先发设备地址0xA0,再写目标地址和两个字节数据。注意每次写入后要等待5ms,期间不能发下一个写命令。
看门狗方面,AT89C51原片内部没有硬件WDT,可以用定时器0模拟软看门狗。做法是让定时器0每100ms触发一次中断,中断里对计数变量加1,主循环每次执行完把计数清零。如果计数超过5,说明程序跑飞,直接跳回main起始处重新初始化。
volatile unsigned char wdt_cnt = 0; void timer0_isr(void) interrupt 1 { wdt_cnt++; if (wdt_cnt >= 5) { wdt_cnt = 0; main(); /* 软复位到主程序,需要先清TR0 */ } } void feed_soft_wdt(void) { wdt_cnt = 0; }这种软看门狗只能处理死循环,不能处理低优先级中断被卡死的情况。更可靠的做法是把软看门狗和外部复位芯片配合,或者直接换AT89S51使用内置WDT。Keil C51里调用main()要小心,软复位前要把所有外设寄存器恢复到初值,简单起见用while(1)空转加外部复位芯片更省心。
4. 调试方法与典型坑:时序、电源、继电器和按键
4.1 DHT11时序不准导致读数卡死或报警
DHT11对延时函数非常敏感,用Keil优化等级过高时,delay_us会被优化掉,导致读取位一直为0或直接卡在while(P3_3==0)。先确认优化等级,再看晶振频率是否与实际一致。用12MHz晶振配合NOP延时是最容易复现的方案。
| 信号阶段 | 低电平时间 | 高电平时间 | 判定要点 |
|---|---|---|---|
| 主机起始信号 | >18ms | 20~40us | 拉低后要释放总线 |
| 传感器响应 | 80us | 80us | 先低后高 |
| 数据位0 | 50us | 26~28us | 高电平短 |
| 数据位1 | 50us | 70us | 高电平长 |
调试时可以用逻辑分析仪抓P3.3波形,数一下高电平宽度。位0的高电平宽度接近但不超过30us,位1的高电平宽度至少60us。另外读到的5字节数据应该是湿度整数部分、湿度小数部分、温度整数部分、温度小数部分、校验和。
给出一段用串口输出原始5字节的代码:
if (read_dht11_data(&buf[0]) == 0) { for (i = 0; i < 5; i++) { send_char(buf[i]); /* 用51串口把原始字节发到调试助手 */ } }如果在串口助手看到固定的0xFF或者前两个字节一直为0,先查上拉电阻和接线,再查起始信号延时是否满足1秒间隔。DHT11采样周期是1秒,读得太快会返回上次数据甚至不响应。
4.2 继电器吸合导致MCU复位、LCD乱码
继电器吸合瞬间电流脉冲会通过共用电源线干扰51,常见现象是每次加热器启动,LCD就闪一下,严重时整个系统重启。先检查继电器线圈有没有续流二极管,这是第一道防线。第二道防线是给继电器驱动端单独走线,不要在单片机地线上形成回路。第三道防线是在继电器供电端加一个100uF电解电容和104瓷片电容的组合,电容尽量靠近继电器。
| 现象 | 原因 | 对策 |
|---|---|---|
| MCU复位 | 线圈反电动势未泄放 | 并联1N4148或SS14 |
| LCD乱码 | 电源跌落 | 继电器电源加大电容 |
| IO口冒烟 | 驱动电流过大 | 改用ULN2003 |
| 控制偶尔失灵 | 强电干扰 | PC817光耦隔离 |
如果加热器是大功率220V设备,触点通断瞬间会产生火花干扰,单片机复位引脚线要尽量短,复位电容可以加大到22uF,让复位门限更迟钝一点。晶振引脚附近放置两个20pF电容,必要时在晶振下方铺地。
4.3 按键消抖和EEPROM阈值写入失败
按键扫描不要直接读一次就认为有效,机械触点按下过程会有10到20ms的抖动。常见做法是检测到低电平后延时20ms再读一次,确认还是低电平才算按下。松手时同样要检测到高电平后延时20ms,避免一次按下被当作多次。
AT24C02写失败的原因大多是总线时序不对,或者WP引脚被拉高了。写入前要把WP接地。另一个坑是AT89C51重启速度比EEPROM快,掉电后重新上电立即读阈值,可能读到0xFF,所以写阈值时先写入两个起始标志字节,例如0xAA55,读取时先校验标志,不通过就用默认值。
if (read_eeprom(0x00) == 0xAA && read_eeprom(0x01) == 0x55) { temp_low = read_eeprom(0x02); temp_high = read_eeprom(0x03); humi_low = read_eeprom(0x04); humi_high = read_eeprom(0x05); }读EEPROM时同样要模拟I2C的起始和停止条件,SCL高电平期间SDA跳变才是有效命令。这个细节容易被忽略,导致数据偏移一位。
5. 从Proteus仿真到实物移植,再谈要不要换成STM32
5.1 Proteus仿真快速验证控制逻辑
Proteus 8以上的版本自带AT89C51和DHT11仿真模型,可以先不焊板子把逻辑跑通。仿真时把晶振频率设成12MHz,DHT11模型要连一个上拉电阻到电源,否则数据线上没有高电平。另一个容易忽略的是,Proteus里的51默认没有加载程序,需要把Keil编译好的hex文件路径填进AT89C51属性页面,启动仿真后才能运行。仿真运行后添加LCD显示,也可以用虚拟终端看串口输出,方便确认传感器采集是否正常。
5.2 升级到STM32时要动哪些地方
如果后期大棚规模扩大,控制点增加到十几个,AT89C51的I/O资源和RAM开始吃紧。换成基于STM32的环境温湿度监测控制系统,保留LCD、继电器和DHT11外围电路,但要注意三点:第一,STM32的IO口是3.3V电平,继电器模块如果是5V触发,需要加电平转换或改选3.3V继电器;第二,DHT11时序在3.3V供电下可以工作,但代码里的延时函数要用SysTick,不能用51那种NOP方式;第三,P0上拉电阻不再需要,STM32的IO可以配置为开漏输出后使用内部上拉,但外部10k上拉仍然无害。
| 对比项 | AT89C51方案 | STM32方案 |
|---|---|---|
| 温度采集 | DHT11软件时序 | 定时器输入捕获 |
| 控制任务 | 单循环 | 可拆分任务 |
| 掉电保存 | AT24C02软件I2C | I2C外设/EEPROM |
| 成本 | 低 | 中高 |
STM32的优点是可以用一个定时器完成DHT11的输入捕获和校验,也可以用FreeRTOS把采集、控制、显示分开成任务。不过51内核还有一个硬件优势,就是IO翻转速度慢,误触发的概率低。对于大棚这个题目,初版直接用AT89C51把阈值控制跑通,后续再根据控制点数量决定是否迁移。
如果坚持用AT89C51做实物,一个值得保留的细节是:把三个继电器的公共端各自串联一只1A熔断器,成本增加几毛钱,但排查故障时能一眼看到哪个执行回路过流,比在程序里反复调阈值高效得多。
本文还有配套的精品资源,点击获取