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

先分清 DHT11 和 DHT22
这两颗是 DHTxx 家族里最常见的型号,外观像、引脚定义一样,但能力差距不小。按 Last Minute Engineers 整理的规格表:
- 工作电压:两者都是 3~5V,最大工作电流约 2.5mA,接 ESP32 的 3.3V 引脚就能直接驱动;
- 温度量程:DHT11 为 0~50℃、误差约 ±2℃;DHT22 为 -40~80℃、误差约 ±0.5℃;
- 湿度量程:DHT11 只覆盖 20%~80%RH、误差约 ±5%RH;DHT22 覆盖 0~100%RH、误差约 ±2%~5%RH;
- 采样率:DHT11 每秒 1 次,DHT22 每 2 秒 1 次,代码里两次读数间隔要留够;
- 外壳尺寸: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 直接连线即可。

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

换 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 是最高频故障,多半不是代码问题:
- 查接线:VCC、GND 是否接反,Data 是否接在你 #define 的那个引脚上;
- 裸件没接 10KΩ 上拉电阻是最常见的根因,模块板可忽略这条;
- 供电不对:ESP32 上务必接 3.3V 那一路,接 5V(VIN)在部分板子上会把数据线电平抬到 5V,损伤 GPIO;
- 线太长:杜邦线超过 20cm 信号质量下降,DHT 的单总线时序很挑,先缩短再查;
- 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 那一档也不迟——先把这颗最便宜的传感器用明白,是玩环境感知最顺的第一步。


刚好上周接了一颗 DHT22 在 ESP32 上做鱼缸房的温湿度监控,照着官方 DHT tester 示例跑通的。补充一个实际经验:裸件那颗 10K 上拉电阻真的不能省,我一开始图省事没接,串口十次有八次 Failed to read,加了之后一次没失败过。另外 delay(2000) 我试过改成 1500,读数偶尔会跳回旧值,老老实实留 2 秒最稳。
受教了,我那颗 DHT11 读数一直 NaN,原来是 DHTTYPE 没换,选成 DHT22 的常数了
OLED 那段正需要,手边正好有块 0.96 寸 SSD1306,今晚就接线试试
校准那段说得实在,出厂标定放着不用确实会漂,我拿家里温湿度计并排比过,差 1 度多,代码里减掉完事