给机器人加环境感知,温湿度是最便宜也最直观的一路信号。DHT11 和 DHT22 这两颗传感器在创客圈用了十几年,一颗几块钱,一根数据线就能出读数,配 ESP32 正合适——32 位双核、WiFi 现成,读到的温湿度既能走串口看,也能顺手推到 OLED 屏上做个桌面环境站。这篇把接线、装库、代码和常见的"读不出来"一次讲完,规格数值以 Aosong(ASAIR)器件手册和 Adafruit 库文档为准。

先分清 DHT11 和 DHT22
两颗外形几乎一样,内部都是一颗电阻式湿敏元件加一个 NTC 测温元件,芯片在传感器内部完成模数转换,直接输出数字信号,所以任何单片机都能接,不占 ADC。差别全在指标上:
| 指标 | DHT11 | DHT22 |
|---|---|---|
| 温度范围 | 0~50℃,±2℃ | -40~80℃,±0.5℃ |
| 湿度范围 | 20~90%RH,±5% | 0~100%RH,±2% |
| 分辨率 | 湿度1%、温度1℃ | 湿度0.1%、温度0.1℃ |
| 工作电压 | 3~5.5V | 3~6V |
| 供电电流 | 0.5~2.5mA | 1~1.5mA |
| 采样周期 | 1秒 | 2秒 |
| 价格 | 约1~5美元 | 约4~10美元 |
一句话选型:室内看个大概、做玩具,DHT11 够用还便宜;要记录温差变化、做数据,多花几块钱上 DHT22,精度和量程都不是一个档次。两颗读取方式完全相同,代码里改一行宏就能互换。白色外壳带孔的是 DHT22(丝印 AM2302),蓝色小方块是 DHT11,拿到手一眼就能认出来。

引脚定义与接线
裸传感器是 4 个引脚,正面对着你、从左往右数:
1 脚接电源(3.3V 或 5V);
2 脚是数据脚,接任意数字 GPIO,并且要在这脚和电源之间加一个 10kΩ 上拉电阻;
3 脚悬空不接;
4 脚接地。
如果买的是三脚的模块版,板上已经焊好上拉电阻,直接 VCC、GND、DATA 三根线接走即可,不用再外接电阻。这篇示例把数据脚接在 GPIO 4 上,其他能用的 GPIO 也行,改代码里的宏定义即可。

接线上有个细节值得留意:ESP32 的 IO 是 3.3V 逻辑,传感器 3.3V 供电时读数最稳;有些板子用 5V 供电也没问题,但要确认开发板该引脚是 5V 容忍的。面包板上把上拉电阻跨在数据脚和电源轨之间,别接成数据脚对地,那是新手最常见的翻车点。
装两个库,缺一不可
读取逻辑(单总线时序)不用自己写,Adafruit 的 DHT 库全包了。打开 Arduino IDE,进 Sketch → Include Library → Manage Libraries,搜"DHT"装 DHT sensor library(Adafruit 出品)。它还依赖 Adafruit Unified Sensor 库,继续搜"Adafruit Unified Sensor"装上,少这个编译会直接报 Adafruit_Sensor.h 找不到。

完整示例代码
下面是完整的测试程序,把传感器类型宏换成你手上的型号就能跑。用 DHT11 就把 DHTTYPE 那行换成 #define DHTTYPE DHT11(把注释换到另一行):
// 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
// Feather HUZZAH ESP8266 note: use pins 3, 4, 5, 12, 13 or 14 --
// Pin 15 can work but DHT must be disconnected during program upload.
// 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.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors. This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
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"));
}程序结构很简单:setup 里 Serial.begin(9600) 起串口、dht.begin() 初始化;loop 里每 2 秒读一次。readHumidity() 出湿度,readTemperature() 默认出摄氏度,传 true 出华氏度。库还会用温湿度算体感温度(heat index), hic 是摄氏、hif 是华氏,都直接给你了。
看读数与排错
烧录后打开串口监视器,波特率 9600,正常输出长这样:Humidity: 42.30% Temperature: 25.60°C 77.08°F Heat index: 25.30°C 77.54°F。数字有小数点说明你接的是 DHT22;DHT11 的读数永远是整数,这也能反过来帮你确认宏定义没写错。
最常见的报错就是串口一直刷 Failed to read from DHT sensor!,按命中率排查:先查数据脚的宏 DHTPIN 是不是和你实际插的 GPIO 一致;再查上拉电阻有没有接、接没接成对地;然后看供电,接触不良和电压不对都出这个错;最后注意采样间隔,DHT22 两次读取至少隔 2 秒,读太勤也会失败。DHT 本身是慢传感器,读数可能有最多 2 秒的滞后,属于正常现象。
把读数送上 OLED
串口只是第一步,拿到 h 和 t 两个浮点数之后,显示就是纯输出问题。接一块 0.96 寸 SSD1306 OLED,I2C 两根线(SCL、SDA)接到 ESP32 对应引脚,用 Adafruit 的 SSD1306 和 GFX 库初始化后,在 loop 里把 Serial.print 换成 display.print 就能把温湿度刷到屏上——之前发过的 SSD1306 OLED 配 ESP32 那篇把 I2C 接线和库的用法讲得很细,两篇拼起来就是一个完整的桌面温湿度计。要更省事,直接用这次读数喂给行空板或机械臂的状态屏也一样。
整套下来成本不到二十块,是给任何桌面设备加环境感知的最短路径。先在串口把读数调稳,再考虑上屏、上云,一步一个坑地排,比一上来就堆功能靠谱得多。


上周刚踩过上拉电阻这个坑,数据脚和地之间接了个10k,串口一直刷Failed to read,折腾一晚上才反应过来方向接反了。文里那句“别接成数据脚对地”真是血泪总结,新手一定记牢。另外补一句,DHT22用5V供电读数偶尔跳变的话,降到3.3V试试,我这边稳多了。
DHT11读出来永远是整数这个细节讲得好,我以前就是靠这个判断宏定义写没写错的。
两块钱的传感器配ESP32做个桌面温湿度计,确实是成本最低的环境感知方案了,适合给刚入门的练手。
请问串口监视器乱码一般是哪里的问题?波特率9600我确认没选错,烧录也能过,就是显示的全是问号。