资讯详情

资讯详情

基于STC89C51的双通道DHT11温湿度采集与LCD1602显示系统

简介这是一套基于STC89C51单片机的双通道DHT11实时温湿度显示系统项目包面向单片机初学者、电子设计与嵌入式系统爱好者适合用于课程设计或毕业设计参考。项目以STC89C51为控制核心通过单总线读取两路DHT11传感器数据并借助LCD1602液晶实时显示温度和湿度覆盖了传感器驱动、单总线时序、液晶显示、按键交互与硬件电路等关键知识点。双通道设计支持同时监测两个位置的温湿度状态便于数据对比与联动控制。压缩包中共有22个文件大小仅68KB包含C语言与头文件源码、Keil工程文件、编译生成的十六进制烧录文件、目标文件、列表文件及编译日志等结构清晰便于直接打开工程查看或烧录验证。目前已有1370人学习下载对于想快速上手单片机温湿度采集与显示设计的读者这套资源提供了从硬件选型、接口设计到软件调试的完整闭环能有效帮助理解DHT11单总线时序控制和LCD1602液晶驱动的实际应用。1. 项目整体设计与方案选型1.1 双通道采集从单点测温到冗余校验刚开始想做温湿度显示的时候我第一反应也是用一个DHT11加一块LCD1602程序跑通、屏幕亮起来就完事。但真正往实际场景里一放就会发现单点采集的问题特别多传感器放在电路板边上发热元件一烤数据明显偏高换个位置又因为通风不好导致湿度数值老是飘。你很难判断到底是环境本身就那样还是传感器出了问题。后来我把方案改成双通道DHT11同时采集一块LCD1602分成两行显示第一行显示通道1的温湿度第二行显示通道2的温湿度一屏看全两路数据这才算是把问题解决了。双通道真正的价值不只是多了一个测量点而是多了一个互相校验的依据。DHT11这传感器的精度本来就不算高温度误差±2℃湿度误差±5%RH如果两个通道放在同一个环境里读数差得离谱那基本可以断定有一颗传感器已经不行了。而且在实际做毕业设计或者课程设计的时候把“为什么用双通道”讲清楚比如冗余设计、点位对比、故障预警比单纯做一个单点的温度计不知道高到哪里去了。代码量不过多了几十行硬件也就多了一个传感器和几根杜邦线性价比极高。1.2 为什么用STC89C51这颗“老将”STC89C51是一颗非常经典的51内核单片机很多人觉得它性能弱、资源小但我个人认为做这种小系统它反而是最稳的选择。它内部集成4KB的Flash程序存储器和128字节RAM外接12MHz晶振时单周期指令其实很快对付DHT11这种低速通信和LCD1602显示完全够用。更重要的是它的IO口是准双向口输出高电平的能力虽然不算强但驱动LCD1602的数据线和控制线基本无压力不需要额外加总线缓冲器极大简化了电路。另一个我看中的点是资料生态。STC89C51的指令系统跟经典8051完全兼容从开发环境到烧录工具再到各种例程中文互联网上的资源多得看不完。对于新手来说遇到问题搜一下就能找到答案这对学习氛围和调试效率非常友好。很多人喜欢一上来就追STM32但如果你连51的IO配置、定时器、外部中断这些基础都还没吃透直接上HAL库反而容易迷路。先用51把一个完整的温湿度显示系统跑通底层逻辑清楚之后再往更高性能的平台迁移路子会顺很多。2. 硬件电路搭建与引脚分配实战2.1 DHT11上拉和时序最容易翻车的地方DHT11是一个单总线数字传感器引脚只有四个VCC、DATA、GND和一个悬空的NC脚。供电范围很宽3.3V也能跑5V也没问题所以我这里直接接系统的5V和GND。但数据线DATA必须接一个上拉电阻到VCC阻值选4.7kΩ到10kΩ都行。这个电阻是很多人第一次做的时候漏掉的关键器件没有上拉电阻的话数据线只能被传感器拉低却没办法拉高读回来的数据要么全是0要么直接是乱码。我建议直接在面包板上用排阻或者贴片电阻焊一个小转接板别图省事悬空处理。再说通信时序。主机先拉低数据线至少18ms再释放并延时大约20到40us这一组操作就是起始信号。DHT11收到以后会拉低总线80us左右再拉高80us左右表示“收到准备发数据”。紧接着是40位数据8位湿度整数、8位湿度小数、8位温度整数、8位温度小数、最后8位校验和。每一位的编码规则是先有50us的低电平然后如果高电平持续26到28us就表示这一位是0如果高电平持续70us左右就表示这一位是1。所以读位的核心就是测量高电平持续的时间而不是机械地去数电平跳变。这里必须提醒一下DHT11的时序参数有一定公差不同批次、不同温度下高低电平的宽度都会有波动。如果代码里用死循环加空指令来卡延时一旦晶振频率偏差、编译器优化级别不同、或者中断突然插进来读出的数据就会隔三差五出错。更可靠的做法是开启一个定时器在高电平期间记录计数值然后和阈值比较。我在这个项目里就是使用定时器0作为us级计时基准把测到的高电平时间阈值设在40us左右大于40判1小于40判0实测稳定了很多。2.2 LCD1602四线模式接线与电平匹配LCD1602背后用的驱动芯片大多是HD44780可以显示两行、每行16个字符自带ASCII字库往DDRAM地址写字符编码就能直接显示。它支持8位和4位两种数据模式8位模式需要占用8根数据线加3根控制线一共11个IO口对于引脚本来就不多的STC89C51来说压力有点大。所以我这里选择了4位模式只接高4位数据线DB4到DB7控制线接RS、RW、EN三根总共7个IO口就能跑起来省出来的引脚正好留给两个DHT11。接线方式我整理一下LCD的RS接单片机的P2.5RW接P2.6EN接P2.7DB4到DB7依次接P1.4到P1.7。显示器的VDD接5VVSS接地V0接一个10k电位器的中间抽头用来调节对比度不调的话屏幕可能黑底一片或者完全看不清字。背光A通过一个100Ω限流电阻接5VK接地。这里有个细节STC89C51的IO口在输出高电平时的驱动能力其实不强但LCD1602的输入阻抗很高所以不会有什么问题倒是V0引脚的对比度电压一定要调好不然后期写再多代码屏幕上都是空的。2.3 完整引脚分配表和最小系统搭建我把整个系统的引脚分配固定下来方便后面写程序的时候一一对应。两个DHT11分别用P2.0和P2.1作为数据引脚VCC和GND都并接在一起。LCD1602用前面说的那7个IO口。剩下的引脚暂时空着以后如果还要加按键、报警器或者串口通信可以直接扩展。器件引脚接单片机IO备注DHT11通道1DATAP2.0接4.7k~10k上拉电阻到VCCDHT11通道2DATAP2.1接4.7k~10k上拉电阻到VCCLCD1602RSP2.5寄存器选择LCD1602RWP2.6读写选择LCD1602ENP2.7使能信号LCD1602DB4~DB7P1.4~P1.7高四位数据线晶振电路XTAL1/XTAL2引脚18/1912MHz晶振两个20pF负载电容复位电路RST引脚910uF电容加10k电阻组成上电复位这里要重点说说最小系统。STC89C51并不是所有开发板都自带了可靠的上电复位电路如果是自己焊板子复位引脚RST接一个10uF电解电容到VCC再接一个10k电阻到GND上电瞬间RST会短暂维持高电平让单片机完成内部复位。晶振电路也别忘了两个20pF左右的对地电容它们能帮助晶振起振并稳定频率。如果晶振不起振现象是程序烧录成功但屏幕不亮、IO口完全没反应这是很多自焊板子最容易碰到的问题之一。3. 软件驱动与数据流程拆解3.1 DHT11驱动框架状态机比延时更靠谱写DHT11驱动最直观的思路是拉低、延时、拉高、再延时、读数据。但我实际写下来发现把整个读过程写成一个大函数中间全是延时代码一旦遇到外部中断就会很脆弱。更稳妥的写法是把通信过程拆成几个步骤用状态机的思路去跑先发起始信号然后等待响应再依次读取40位数据最后做校验。每一步之间只需要根据当前状态判断下一步该干什么即使中途被中断打断恢复之后也能回到正确的状态继续跑。核心读取代码大概长这样我简化成关键部分方便说明unsigned char dht11_read_bit(void) { unsigned char cnt 0; while(!DHT1_DATA); // 等待高电平 while(DHT1_DATA cnt 100) { cnt; DelayUs(1); } // 统计高电平时间 if(cnt 40) return 1; // 高电平宽度超过阈值判定为1 return 0; // 否则判定为0 }上面这段代码的思路就是前面说的阈值判断法把高电平持续的时间通过循环次数近似测量出来。这里有一点要提醒while(!DHT1_DATA)如果传感器没有正确响应可能陷入死等所以实际项目里我会在循环外面再加一个超时保护变量比如超过一定循环次数就退出并返回错误标志这样即使传感器拔掉了程序也不会卡死。另一个容易被忽略的点是两次读取DHT11之间必须间隔至少1秒。因为DHT11本身就是这样设计的传感器每次采样转换需要一定时间如果你读得太频繁它会一直不响应或者返回错误数据。我在主循环里用一个定时器加标志位做调度每1.2秒左右触发一次双通道采集既满足了传感器要求也让LCD显示刷新显得足够流畅。3.2 双通道数据读取与显示刷新策略两个DHT11共用一套读取协议只是数据引脚不同所以我在驱动层写了两个入口函数DHT11_Read_Data(通道号)内部根据传入参数选择操作P2.0还是P2.1。这样可以避免复制粘贴两份几乎一样的代码也方便以后扩展到三个、四个通道。每次采集完成之后把温度和湿度数据放在一个结构体数组里显示模块再去读取数组内容刷新LCD。LCD1602显示的时候要注意DDRAM地址的规律。第一行起始地址是0x80第二行是0xC0。在4线模式下往DDRAM写数据之前要先发送地址指令然后再写入字符数据。我在刷新画面时是先清屏再打印这个做法简单但会有轻微闪烁后来改成了只更新变化区域也就是直接修改对应位置的字符不清屏。对于这个项目来说温湿度每秒变化幅度不大所以刷新频率不需要太高我设置成每1秒刷一次屏幕显示稳定且没有闪动。代码里我用了一个小技巧把数字转成字符串之后先补空格再写LCD避免上一次数字较长时留下残留字符。比如温度从99变成9的时候如果不对齐屏幕上会多出一个9的残影。这个问题很常见很多新手会遇到“数字短了后面多出来了一截”的怪现象其实就是在写字符之前没有清掉旧的显示位。用printf配合格式化输出到LCD不太方便我一般定义一个LCD_PrintVal函数手动把整数拆成字符并填充定宽字段。3.3 数据校验与异常保护DHT11传回来的40位数据里面前32位是有效数据最后8位是校验和规则是湿度整数加湿度小数加温度整数加温度小数之和的末8位应该等于校验字节。如果对不上说明这次通讯有干扰数据不能采用最好直接丢弃并等待下一次采样。这个校验看似简单但能挡掉大部分因为杜邦线松动、触点氧化引起的偶发错误。我在程序里做了三级异常处理。第一级是读时序超时比如传感器没响应直接返回失败。第二级是校验和不匹配返回错误标志不更新显示。第三级是数据合理性判断比如温度大于60℃或者小于-40℃湿度大于99%RH这类值明显超出DHT11的正常量程也当作异常处理。只有三个环节都通过才更新LCD上的数值。连续多次失败后我会在对应通道的位置显示“Err”提醒用户去检查接线这个对后续调试帮助特别大。实际跑起来以后我发现加上异常处理之后程序的“抗造”能力提升了很多。以前数据线稍微碰一下屏幕就乱跳现在最多丢一帧数据下一轮重试又恢复正常。做嵌入式系统数据可信度有时候比数据实时性还重要这一点在温湿度采集这种低速应用里体现得特别明显。4. 调试实录与常见翻车点排查4.1 读回0xFF或全0的典型原因我第一次接好硬件烧完程序LCD上两个通道的温度都是0湿度也是0第一反应是传感器坏了。后来用示波器挂上数据线才发现主机压根没测到任何低电平响应。翻来覆去找原因最后发现是DHT11的数据引脚接错了接到了NC脚上。这个NC脚在模块上通常标注得不明显很多人会把它当成数据脚给接上结果当然读不到任何信号。如果你用的是那种三引脚封装的DHT11模块没有NC脚那就不存在这个问题但独立封装的小模块要特别留意。另一个常见现象是读回来全是0xFF。这种通常是因为上拉电阻没有接或者接得太大导致电平抬不上去。DHT11数据线必须有上拉4.7k到10k比较适合阻值太小会加重传感器驱动负担阻值太大则沿太缓容易误判电平。我后来用了一个稍微讲究的做法把LCD1602和DHT11的上拉电阻放在了一起统一在5V端子上做星型接地和星型供电减小公共阻抗带来的干扰读数的稳定性明显好了不少。4.2 LCD1602显示乱码或花屏怎么办如果你发现LCD上出现满屏方块或者字符错位第一件事不是怀疑代码而是检查对比度调节电位器。V0引脚电压如果不在合适范围屏可能显示出一堆“雪花”一样的方块也就是常说的花屏。把电位器慢慢旋到合适位置能明显看到字符从块状变成可识别的字母和数字。另一个常见原因是初始化时序不对尤其是4线模式下的初始化序列必须严格按HD44780手册里的步骤来先延时、再写功能设置、再开关显示、再清屏顺序错了屏幕就会一团糟。还有一种很隐蔽的问题就是LCD1602和单片机之间地线接触不良。杜邦线插在面包板上看着挺牢固实际上氧化或者松动以后地阻抗变大数据线的信号参考点飘了屏幕就开始间歇性乱码。排查方法很简单用万用表量一下LCD的VSS和单片机GND之间电阻如果明显大于0.1Ω就重新插一遍线顺便换几根新的杜邦线这个问题大部分人遇到却很难想到。4.3 温湿度数值跳变或偏差大的处理双通道在同一个环境下读数本来应该有较高的一致性如果两边温度差了2℃以上那就要考虑是不是某一颗传感器受到了局部热源影响。我之前把两个传感器都放在单片机旁边结果一个通道读数比另一个高了将近3℃后来测了一下才知道那个位置正好对着电源稳压芯片的散热面。把它稍微挪开几厘米两边数据就贴近了。所以传感器安装位置要在设计阶段就想清楚别等着数据出来再猜。数值跳变还有可能是数据线过长或者干扰太强造成的。DHT11的数据线最好不要超过20cm如果必须延长使用双绞线或者屏蔽线数据线远离电源线。我试过把数据线从面包板这边拉到另一边绕了一圈经过电源模块结果湿度数据在30%和60%之间疯狂横跳把线理直缩短之后就好了。另外ADC供电的纹波也会影响读数如果系统里还同时驱动了电机或者继电器一定要隔离好电源这个项目虽然简单但在复杂一点的环境里就得认真对待。5. 扩展思路与我的最终心得5.1 从LCD1602到上位机、WiFi和存储这套系统的核心框架做好以后要继续往上加功能非常顺。最直接的扩展是加一个串口模块把双通道温湿度数据通过UART每隔几秒发送到电脑上位机画一条实时曲线。STC89C51的UART是经典51的串口配合蓝牙模块或者CH340G上位机用串口调试助手或者Python的pyserial就能轻松接收数据。对于毕业设计来说加上“上位机实时监测”这一项整个项目的画面感就完全不一样了。如果想做远程监测可以考虑换成带WiFi功能的芯片比如ESP8266或者ESP32思路依然可以复用这套驱动逻辑只是把LCD显示部分替换成网络上报。存储扩展也很简单外挂一个AT24C02或者FM24C02定时记录温湿度数据掉电不丢失配上时间戳就能做一个简单的环境记录仪。其实你会发现51单片机上验证过的驱动方式和数据校验逻辑挪到其他平台只是更换底层API的问题核心思路是完全通用的。5.2 这套架构对新手最大的价值我经常跟刚开始学单片机的人说DHT11是一个被低估的学习载体。它的通信协议既不是标准I2C也不是标准SPI你必须去读数据手册、理解时序图、调延时、做故障排查这一整套流程下来你对单片机的基本功会有质的提升。LCD1602虽然老但它让你接触到初始化序列、寄存器地址、控制时序这些嵌入式开发里的基础概念比那些点几个LED灯有意思得多。双通道的设计也不是为了花哨它逼着你学会用结构体管理多路数据、处理多个外设的调度关系同时还要考虑数据异常的时候系统怎么表现。这些能力在你以后去做更复杂的项目、参加电赛或者工作以后写正式固件时都是实实在在的核心竞争力。如果你正打算做课程设计或者毕业设计我建议别只停留在“让它显示出来”试着把每个环节都问一遍为什么然后把异常处理和代码结构再打磨一下收获会完全不一样。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →