DHT11/DHT22接ESP32实操:读温湿度、校准与显示

2026-11-08 13:10:44 43阅读 所属项目:ESP32 开发板

给桌面机械臂或小车加环境感知,最省事的起点就是一颗 DHT11 或 DHT22:单总线、三根线、几行代码就能读出温湿度。这篇按固定烧录玩家的路子,把接线、装库、读数、踩坑到校准一次讲透,主控以 ESP32 为例,Arduino UNO 同样适用。

DHT22 与 DHT11 温湿度传感器实拍

先分清 DHT11 和 DHT22

这两颗是 DHTxx 家族里最常见的型号,外观像、引脚定义一样,但能力差距不小。按 Last Minute Engineers 整理的规格表:

  1. 工作电压:两者都是 3~5V,最大工作电流约 2.5mA,接 ESP32 的 3.3V 引脚就能直接驱动;
  2. 温度量程:DHT11 为 0~50℃、误差约 ±2℃;DHT22 为 -40~80℃、误差约 ±0.5℃;
  3. 湿度量程:DHT11 只覆盖 20%~80%RH、误差约 ±5%RH;DHT22 覆盖 0~100%RH、误差约 ±2%~5%RH;
  4. 采样率:DHT11 每秒 1 次,DHT22 每 2 秒 1 次,代码里两次读数间隔要留够;
  5. 外壳尺寸:DHT11 约 15.5×12×5.5mm,DHT22 约 15.1×25×7.7mm,后者是白色网壳那颗。

简单说:室内桌面环境、预算压到两三块钱,DHT11 够用;要做温室、户外或需要精度,直接上 DHT22(也叫 AM2302)。文章封面那颗白色网壳的就是 DHT22,蓝色小方块是 DHT11。

引脚定义与接线

裸件(不带板)是 4 个引脚,面朝网壳、引脚朝下从左往右数:1 脚 VCC 接电源,2 脚 Data 接主控 GPIO,3 脚 NC 悬空不接,4 脚 GND 接地。常见的三针模块板已经内置了上拉电阻,Data 直接连线即可。

DHT11 与 DHT22 引脚定义图

接 ESP32 的典型接法:VCC 接 3V3,GND 接 GND,Data 接 GPIO4。如果用的是裸件而不是模块,要在 Data 和 VCC 之间加一颗 10KΩ 上拉电阻,否则信号线悬空会读不到数。Random Nerd Tutorials 的示例接线如下图。

DHT22 接 ESP32 面包板接线图

换 Arduino UNO 也一样,只是把 VCC 改接 5V、Data 随便挑一个数字引脚,代码里把 DHTPIN 改成对应编号即可。

装库:两个都要装

打开 Arduino IDE 的「工具 → 库管理器」,搜 DHT,装 Adafruit 的 DHT sensor library;装完它会提示缺依赖,再把 Adafruit Unified Sensor 库一并装上。漏装第二个是新手最常见的编译报错根因,报错关键词一般是 No such file or directory 加 Adafruit_Sensor.h。

示例代码:串口读温湿度

下面这段是 Adafruit 官方示例 DHT tester 的核心代码,原样搬运(头文件按站点兼容要求把尖括号写成了引号,两种写法在 Arduino 工具链下等价):

// Example testing sketch for various DHT humidity/temperature sensors written by ladyada
// REQUIRES the following Arduino libraries:
// - DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library
// - Adafruit Unified Sensor Lib: https://github.com/adafruit/Adafruit_Sensor

#include "DHT.h"

#define DHTPIN 4     // Digital pin connected to the DHT sensor

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

// Initialize DHT sensor.
DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600);
  Serial.println(F("DHTxx test!"));

  dht.begin();
}

void loop() {
  // Wait a few seconds between measurements.
  delay(2000);

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);

  Serial.print(F("Humidity: "));
  Serial.print(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(t);
  Serial.print(F("°C "));
  Serial.print(f);
  Serial.print(F("°F  Heat index: "));
  Serial.print(hic);
  Serial.print(F("°C "));
  Serial.print(hif);
  Serial.println(F("°F"));
}

要点就三处:DHTPIN 4 对应接线的 GPIO4;用 DHT11 就把 DHT22 那行注释换到 DHT11 那行;loop 里的 delay(2000) 不能删,DHT22 本来就是 2 秒一次的采样节奏,读太快只会拿到旧值。烧录后打开串口监视器,波特率 9600,效果如下。

串口监视器输出的温湿度读数

读不到数?按顺序排查

串口反复打印 Failed to read from DHT sensor 是最高频故障,多半不是代码问题:

  1. 查接线:VCC、GND 是否接反,Data 是否接在你 #define 的那个引脚上;
  2. 裸件没接 10KΩ 上拉电阻是最常见的根因,模块板可忽略这条;
  3. 供电不对:ESP32 上务必接 3.3V 那一路,接 5V(VIN)在部分板子上会把数据线电平抬到 5V,损伤 GPIO;
  4. 线太长:杜邦线超过 20cm 信号质量下降,DHT 的单总线时序很挑,先缩短再查;
  5. DHTTYPE 选错型号也会读失败,DHT11 板子选了 DHT22 常数就是一直 NaN。

另一个坑是库版本:老教程里 dht(DHTPIN, DHTTYPE, 15) 这种第三个参数在新版库里已经取消,新版算法自适应主频,照抄老代码反而编译不过。

校准与一个简单的显示应用

DHT 系列出厂已校准,日常不用动。但闲置过久或受潮后容易漂,实用做法是拿一个已知可靠的参考(家里的温湿度计或手机传感器)并排摆 10 分钟,取读数差。偏差不大就靠代码补偿:t = dht.readTemperature() 后面跟一行 t -= 1.5 这种固定修正即可,写死在代码里比调硬件省事。湿度偏差超过 ±5%RH 或持续读 NaN,基本可以判定器件受潮或老化,换一颗比修划算。

想让数据离开串口,最轻的方案是加一块 0.96 寸 OLED(SSD1306,I2C 接口)。只需把 SDA 接 GPIO21、SCL 接 GPIO22(ESP32 默认 I2C 引脚),在现有代码基础上引入 Adafruit_SSD1306 库,把 Serial.print 换成 display.print:屏幕上第一行显示温度、第二行显示湿度,delay 循环里每次读数后 display.display() 刷新一次。整套下来成本不到二十块钱,做一个桌面温湿度牌,或者塞进机械臂工作间监控焊接环境湿度,都够用。

DHT 单总线协议慢、精度一般,胜在便宜到可以到处撒。等你需要 ±0.3℃ 级别或压力数据时,再升级 BME280 那一档也不迟——先把这颗最便宜的传感器用明白,是玩环境感知最顺的第一步。


作者:固件烧录仔
链接:https://www.aiddithome.com/p/1abf05178bef96.html
本作版权归作者所有,未经允许请勿转载。若存在违规行为,您可以点击 “举报”。


登录 后发表评论
4条评论
触底反弹的Tony
1楼 · 10小时前

刚好上周接了一颗 DHT22 在 ESP32 上做鱼缸房的温湿度监控,照着官方 DHT tester 示例跑通的。补充一个实际经验:裸件那颗 10K 上拉电阻真的不能省,我一开始图省事没接,串口十次有八次 Failed to read,加了之后一次没失败过。另外 delay(2000) 我试过改成 1500,读数偶尔会跳回旧值,老老实实留 2 秒最稳。

板砖搬不动
2楼 · 10小时前

受教了,我那颗 DHT11 读数一直 NaN,原来是 DHTTYPE 没换,选成 DHT22 的常数了

拆开看看再说
3楼 · 10小时前

OLED 那段正需要,手边正好有块 0.96 寸 SSD1306,今晚就接线试试

周五下班搞一搞
4楼 · 10小时前

校准那段说得实在,出厂标定放着不用确实会漂,我拿家里温湿度计并排比过,差 1 度多,代码里减掉完事