☰
Arduino温湿度采集:DHT11/DHT21/DHT22库文件使用与避坑指南
2026/10/26 5:49:08 网站建设 项目流程

简介:这份库文件面向使用Arduino平台开展温湿度采集的开发者与电子DIY爱好者,解决DHT11、DHT21、DHT22三款传感器在Arduino IDE中快速接入与统一读取的问题。压缩包共10个文件,约15KB,以cpp与h源文件为核心实现传感器驱动与统一接口,另含ino示例程序、md说明文档、properties库描述文件及txt关键词表,示例覆盖基础读取与统一传感器封装两种用法,便于对照移植。已有1370人学习下载,说明其在入门环境监测项目中具备一定参考价值。读者可直接将库加入Arduino库目录,调用现成函数完成初始化、温湿度读取与数据格式化,无需深究单总线时序细节,同时可借助示例理解DHT11、DHT21与DHT22在精度和量程上的差异,为物联网与自动化项目中的环境监测模块提供可复用的代码基础。

1. 温湿度采集从这颗料开始:DHT11/DHT21/DHT22 库文件到底解决什么问题

手里攥着一块 DHT11 或 DHT22,接线就三根,代码却卡在编译报错上——这种场景在 Arduino 入门阶段太常见了。这个库文件包把 DHT11、DHT21(AM2301)、DHT22(AM2302)三种常见温湿度传感器的驱动逻辑收在一起,省掉自己啃单总线时序的功夫。它解决的核心问题很具体:让一块几块钱的温湿度传感器在 Arduino IDE 里稳定读出数据,而不是每次上电都靠运气。适合谁?做环境监测小项目、温室控制、机房温湿度看板、课程设计的从业者和学生,尤其是那些不想在时序延时上反复翻车的人。DHT 系列本身精度一般,但胜在便宜、单总线、接线简单,配合一个靠谱的库,能快速把数据采集这一环跑通。

2. 单总线时序与库的选型逻辑:为什么不能随手抓一个 DHT 库

DHT11、DHT21、DHT22 都是单总线(One-Wire 风格,但不是 Dallas 那套)器件,主机拉低总线至少 18ms 作为起始信号,然后释放,传感器回一串 40 位数据。每一位靠高电平持续时间区分 0 和 1:约 26-28μs 为 0,约 70μs 为 1。这个时序对微秒级延时敏感,Arduino 的delay()和delayMicroseconds()精度有限,加上中断干扰,读失败是常态。库的价值就在于把这套时序封装好,并且针对不同型号做量程和分辨率适配。

2.1 三种型号的差异决定了库必须做分支处理

DHT11 和 DHT22 虽然引脚兼容,但数据格式不一样。DHT11 湿度整数、温度整数,量程 20-90%RH、0-50℃,精度 ±5%RH/±2℃;DHT22 湿度温度都是 16 位,湿度分辨率 0.1%RH,温度分辨率 0.1℃,量程 0-100%RH、-40-80℃,精度 ±2%RH/±0.5℃;DHT21 参数接近 DHT22,封装不同。如果库不区分型号,读出来的湿度可能被当成温度解析,或者小数点位置错位。常见做法是库内部用宏或构造函数参数指定型号,解析时按型号走不同分支。

型号湿度量程温度量程湿度分辨率温度分辨率采样周期建议
DHT1120-90%RH0-50℃1%RH1℃≥1s
DHT210-100%RH-40-80℃0.1%RH0.1℃≥2s
DHT220-100%RH-40-80℃0.1%RH0.1℃≥2s

这张表是选型和排错的第一参照。很多人读出来数值跳变或者恒定不变,先对照量程——DHT11 在低于 20%RH 的环境里读数本来就没有意义,不是库坏了。

2.2 库文件放进 Arduino IDE 的正确姿势

拿到 zip 之后不要解压后随便丢。Arduino IDE 的库目录有固定结构,手动放错位置是最常见的“库找不到”原因。标准做法是通过 IDE 的“项目 → 加载库 → 添加 .ZIP 库”导入,或者解压后放到用户目录下的libraries文件夹,保证文件夹名和里面的.h文件名一致。

# 以 Linux/macOS 为例,Arduino 用户库目录通常在: # ~/Arduino/libraries/ # 解压后确认结构类似: # ~/Arduino/libraries/DHT_sensor_library/DHT.h # ~/Arduino/libraries/DHT_sensor_library/DHT.cpp # ~/Arduino/libraries/DHT_sensor_library/examples/DHTtester/DHTtester.ino unzip DHT11-DHT21-DHT22库文件.zip -d ~/Arduino/libraries/ ls ~/Arduino/libraries/DHT_sensor_library/

这段命令的关键点是解压目标必须是libraries根目录,而不是再套一层。解压完用ls确认.h、.cpp、examples在同一层。如果多套了一层文件夹,IDE 扫描时会找不到头文件,编译报DHT.h: No such file or directory。参数上唯一要改的是路径里的用户名,Windows 下对应C:\Users\你的用户名\Documents\Arduino\libraries。

2.3 最小可运行代码:先验证库能编译再谈精度

导入库之后不要急着改业务逻辑,先用库自带的示例跑通。下面这段是典型的读取骨架,型号通过宏切换,接线是 VCC 接 5V(DHT11/DHT22 都支持 3.3-5.5V)、GND 接地、DATA 接数字引脚并加 4.7k-10k 上拉电阻。

#include "DHT.h" // 型号宏:DHT11 / DHT21 / DHT22 三选一 #define DHTPIN 2 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); void setup() { Serial.begin(9600); dht.begin(); // 初始化总线,内部会做一次空读 } void loop() { delay(2000); // DHT22 采样周期不低于 2s,DHT11 不低于 1s float h = dht.readHumidity(); float t = dht.readTemperature(); // 摄氏度,传 true 则华氏 if (isnan(h) || isnan(t)) { // 读失败返回 NaN,必须判 Serial.println("读取失败,检查接线与上拉电阻"); return; } Serial.print("湿度: "); Serial.print(h); Serial.print(" % 温度: "); Serial.print(t); Serial.println(" C"); }

逻辑说明:dht.begin()里会配置引脚方向并做一次丢弃读,因为传感器上电后第一次读经常无效。readHumidity()和readTemperature()内部各自发起一次完整的单总线通信,所以连续调用两次等于读了两次,间隔不够就会失败。参数上delay(2000)不是随便写的,DHT22 数据手册要求两次采样间隔不小于 2 秒,DHT11 不小于 1 秒,低于这个值读出来 NaN 的概率陡增。isnan()判断是必须的,很多人省略这步,结果串口里打印出nan还以为是传感器坏了。

3. 接线、上拉与供电:三个让读数稳定的硬件前提

库再稳,硬件不对照样翻车。DHT 系列对供电和总线负载比想象中敏感,尤其是长导线和多个传感器并联的场景。

3.1 上拉电阻不是可选项

单总线是开漏结构,DATA 线必须有一个上拉到 VCC 的电阻,典型 4.7kΩ,导线长于 1 米时用 10kΩ 更稳。很多模块板载已经带了上拉,裸传感器则必须自己加。现象是读数偶尔成功偶尔 NaN,原因就是总线释放后电平爬升太慢,被误判成 0。解决方法是万用表量 DATA 对 VCC 的阻值,确认在 4.7k-10k 之间。

3.2 供电电压与线长

DHT11 标称 3.3-5.5V,DHT22 标称 3.3-6V,但实际在 3.3V 供电、长导线情况下,高电平幅度可能不够,Arduino 的数字输入阈值约 0.6×VCC,勉强能识别但余量小。常见做法是 5V 供电、DATA 串一个 1kΩ 限流电阻再到引脚,避免热插拔时电流冲击。导线超过 2 米建议缩短或者加屏蔽,单总线对分布电容很敏感。

3.3 多传感器并联的地址问题

DHT 系列没有地址概念,一条 DATA 线只能挂一个传感器。想接多个必须每个占一个数字引脚,库实例也要分开建。有人试图把三个 DHT22 并在同一根线上,读出来全是乱码,这不是库的锅,是总线冲突。正确做法是每个传感器一个DHT对象、一个引脚,循环里依次读,中间留足间隔。

DHT dht1(2, DHT22); DHT dht2(3, DHT22); void loop() { delay(2000); float h1 = dht1.readHumidity(); delay(100); // 两个器件之间留一点总线空闲 float h2 = dht2.readHumidity(); // 各自判 isnan 后使用 }

这段的关键是每个对象独立引脚,且两次读之间留 100ms 以上空闲,避免前一次通信的尾部干扰下一次起始信号。

4. 避坑与排查:五条血泪经验

4.1 编译报 DHT.h 找不到

现象:IDE 提示fatal error: DHT.h: No such file or directory。原因:库文件夹多套了一层,或者文件夹名和头文件名不一致。解决:进libraries目录确认DHT.h直接在库文件夹根层,文件夹名建议与头文件同名,重启 IDE 让它重新扫描。

4.2 读数恒为 NaN

现象:串口一直打印nan。原因按概率排:没加上拉电阻、采样间隔太短、引脚号写错、供电不足。解决:先量上拉阻值,再把delay加到 2500ms 试,最后换一个引脚排除接触问题。DHT11 在湿度低于 20%RH 时也可能返回异常值,属于器件边界。

4.3 温度正常湿度乱跳

现象:温度稳定,湿度在 0 和 99 之间跳。原因:型号宏写错,比如实际是 DHT22 却用了 DHT11 的解析分支,16 位数据被按 8 位截断。解决:核对传感器丝印,DHT22 通常标 AM2302,DHT21 标 AM2301,改DHTTYPE后重新烧录。

4.4 上电第一次读必失败

现象:每次复位后第一轮读 NaN,之后正常。原因:传感器上电需要约 1 秒稳定时间,库的begin()只做了一次丢弃读,不够。解决:在setup()里dht.begin()之后加delay(1500),或者业务层对第一次读做重试。

4.5 长导线导致偶发校验错

现象:短导线正常,换成 3 米杜邦线后成功率降到一半。原因:分布电容拉长上升沿,40 位数据里某一位被误判。解决:缩短导线、降低上拉阻值到 4.7k、或者在 DATA 与引脚间串 100Ω 电阻抑制振铃。这类问题没有后悔药,只能从布线上治。

5. 进阶:把原始读数做成可用的环境数据

库给的是瞬时值,直接拿去控制继电器会抖。我一般会在库外面包一层滑动平均,并且做量程裁剪,把明显越界的值丢掉再参与平均。下面这段是常用的处理骨架,窗口取 5 次,DHT22 两秒一采,十秒出一个稳定值。

const int N = 5; float buf[N]; int idx = 0; float smooth(float v) { buf[idx] = v; idx = (idx + 1) % N; float sum = 0; for (int i = 0; i < N; i++) sum += buf[i]; return sum / N; } // 调用处 float h = dht.readHumidity(); if (!isnan(h) && h >= 0 && h <= 100) { float hs = smooth(h); // hs 用于显示或控制 }

窗口大小 N 是核心参数:N 太小滤波效果弱,N 太大响应迟滞,环境监测场景 5-10 比较合适。量程裁剪那一步不能省,DHT 偶发会吐出 255 之类的越界值,不裁掉会把平均值带偏。验证方法很直接:用手捂住传感器看湿度爬升是否平滑,松开后回落是否单调,如果出现反向跳变,说明窗口里混进了坏值,回头查isnan和量程判断有没有漏。

另一个常被忽略的点是温度补偿。DHT 的湿度读数在温度剧烈变化时有滞后,做高精度场景要在库外按温度查表修正,但多数小项目用不上,知道有这个边界就行。从那以后我每次接 DHT 都先把上拉电阻和采样间隔这两项固定死,再谈代码,省下大量排查时间。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询