ESP32 + DHT11 温湿度监测器:OLED 实时显示教程

Black ESP32 NodeMCU wired to a light-blue DHT11 sensor module and a blue 0.96-inch OLED display showing glowing white bars

把 DHT11 模块的信号脚接到 ESP32 的 GPIO4,OLED 的 SDA 和 SCL 分别接 GPIO21 和 GPIO22,两个模块都从 3V3 脚供电,再烧录一个用 Adafruit DHT 和 SSD1306 库的 sketch 就完成了。整个电路都跑 3.3V,不需要外加任何电阻——3 针版 DHT11 模块的上拉电阻(pull-up)已经做在板上。

这个 ESP32 温湿度监测器需要哪些零件?

NodeMCU-32S ESP32 开发板是整个项目的大脑:自带 WiFi、3.3V 逻辑电平,对第一次上手的人也很友好。它用的是 micro-USB 而不是 USB-C,所以请准备一条 micro-USB 数据线。板上的 USB 芯片是 CP2102,电脑要装 Silicon Labs CP210x 驱动——不是其他板子常用的 CH340 驱动。

如果装了驱动还是看不到 COM 口,先照我们的 ESP32 无法识别排查指南一步步检查,别急着怪代码。

DHT11 和 OLED 要怎么接到 ESP32?

0.96 寸 OLED 走 I2C,而 ESP32 在 Arduino 里的默认 I2C 引脚就是 GPIO21(SDA)和 GPIO22(SCL),不需要重新映射。DHT11 用自己的单总线协议,任何空闲 GPIO 都行;我们用 GPIO4。

模块引脚 ESP32 引脚 说明
OLED GND GND 这块屏的第一个 pin——认准丝印
OLED VCC 3V3 第二个 pin,不是第一个
OLED SCL GPIO22 Arduino 默认 I2C 时钟
OLED SDA GPIO21 Arduino 默认 I2C 数据
DHT11 S(信号) GPIO4 任何空闲 GPIO 都行;sketch 用 4
DHT11 VCC 3V3 模块支持 3.3–5.5V
DHT11 GND GND

插线之前先提醒一件事:这块 OLED 的排针从左到右是 GND、VCC、SCL、SDA——跟很多模块 VCC 排第一的顺序正好相反。凭习惯把红线插到第一个 pin,等于把电源反接到屏幕上,这正是这类 OLED 烧坏的经典死法。永远认板上的丝印,别照别人照片里的线色接。

卡通特写:蓝色 OLED 模块的四个排针,按顺序接着黑、红、黄、绿四条线
这块 OLED 的第一个 pin 是 GND、第二个才是 VCC——跟很多模块正好相反。认丝印,别凭习惯。

接下来是好消息:大多数 DHT11 教程叫你加的 10k 上拉电阻,这里直接省掉。那是给 4 针裸传感器的做法;我们卖的是 3 针模块版,上拉电阻已经做在那块小黑色 PCB 上。接好 S、VCC、GND 三条线,接线就完成了——而且全程 3.3V,也不需要任何电平转换。

要装哪些库、代码怎么写?

两个模块都由 Adafruit 的库来驱动,直接在 Arduino IDE 的 Library Manager(Sketch → Include Library → Manage Libraries)安装。搜 Adafruit 的 DHT sensor library,弹窗问要不要一并安装 Adafruit Unified Sensor 依赖时选同意,然后再装 Adafruit SSD1306,它会用同样方式带上 Adafruit GFX

Sketch 用 millis() 而不是 delay(),每两秒读一次,loop 不会被卡住。Aosong 的 DHT11 数据手册规定采样周期至少两秒,Adafruit 库内部也强制同样的两秒下限——读得再快,拿到的也只是缓存值或失败值。两秒本来就是这颗传感器自己的节奏——而且同一份 sketch 不用改就能跑 DHT22。

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C      // 屏幕一直黑就跑一次 I2C 扫描
#define DHTPIN 4            // DHT11 模块的 S 脚
#define DHTTYPE DHT11       // 买的是 DHT22 就改成 DHT22

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
DHT dht(DHTPIN, DHTTYPE);

const unsigned long READ_INTERVAL = 2000; // DHT11 两次读取之间至少隔 2 秒
unsigned long lastRead = 0;

void setup() {
  Serial.begin(115200);
  dht.begin();
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    Serial.println("SSD1306 not found - check wiring and address");
    while (true) delay(10);   // 卡在这里,没东西可显示
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("DHT11 monitor ready");
  display.display();
}

void loop() {
  if (millis() - lastRead < READ_INTERVAL) return; // 非阻塞等待
  lastRead = millis();

  float h = dht.readHumidity();
  float t = dht.readTemperature(); // 摄氏度

  display.clearDisplay();
  display.setCursor(0, 0);

  if (isnan(h) || isnan(t)) {
    display.setTextSize(1);
    display.println("Sensor read failed");
    display.println("Check DHT11 wiring");
  } else {
    display.setTextSize(1);
    display.println("Temperature:");
    display.setTextSize(2);
    display.print(t, 1);
    display.println(" C");
    display.setTextSize(1);
    display.println("Humidity:");
    display.setTextSize(2);
    display.print(h, 1);
    display.println(" %");
  }
  display.display();
}

OLED 地址是 0x3D 而不是 0x3C 怎么办?

SSD1306 这类屏幕只会落在两个 I2C 地址之一——0x3C 或 0x3D,由控制器的 SA0 地址位决定。0x3C 是最常见的默认值,sketch 里用的也是它。

屏幕不亮的话别猜——直接扫。ESP32 Arduino core 自带扫描器:File → Examples → Wire → WireScan,烧录后打开 Serial Monitor,它会把找到的每个 I2C 地址都打印出来。扫到什么就把什么填进 OLED_ADDR;一个都扫不到,那是接线问题,不是地址问题。

该买 DHT11 还是 DHT22?

DHT11 和 DHT22 是同一颗传感器的两个版本——我们的商品页两种都有——老实说各有各的用武之地。下表数据来自 Adafruit 的 DHT 指南;采样率则按 Aosong 官方 DHT11 数据手册,它比 Adafruit 写的 1 Hz 更严格。

规格 DHT11 DHT22
温度范围 0–50°C −40 到 80°C
温度精度 ±2°C ±0.5°C
湿度范围 20–80% RH 0–100% RH
湿度精度 ±5% ±2–5%
最高采样率 0.5 Hz(每 2 秒一次) 0.5 Hz(每 2 秒一次)

在马来西亚的房间、办公室或种植箱里,DHT11 的 0–50°C 量程和 ±2°C 精度完全够用。要测 0°C 以下(比如记录冰箱温度)、湿度超出 20–80%,或者像孵化箱那样需要更高精度,就选 DHT22。代码里唯一要改的是 #define DHTTYPE DHT22

为什么屏幕全黑或读数是 “nan”?

nan(not a number)表示 DHT 库去问了传感器,却没有得到回应。按顺序检查三样:S 线是不是真的接在 GPIO4 而且插紧了,DHTTYPE 是否跟手上的传感器一致(把 DHT11 当 DHT22 读一定失败),以及 VCC/GND 有没有接到 3V3 和 GND。抄来的代码也常常读得太快——两次读取之间至少留两秒。

传感器正常、OLED 却全黑,几乎都是 I2C 那边的问题:SDA 和 SCL 接反、OLED_ADDR 填错,或者在那个顺序反转的排针上把 GND/VCC 插反了。先跑 WireScan——十秒钟就能告诉你屏幕活不活、住在哪个地址。

卡通对比图:左边 OLED 全黑、DHT11 有一条线松脱,右边所有线都正确接到 ESP32、OLED 正常发亮
屏幕全黑或读数 nan,十有八九是一条线松了或插反了——重新插紧,再扫一次。

读数跟冷气遥控器差个 1–2°C 也不算故障——这在 DHT11 的 ±2°C 规格之内。

可以用 Arduino Uno 代替 ESP32 吗?

Arduino Uno 用同样三个库就能跑这个项目,只需改引脚:OLED 的 SDA 接 A4、SCL 接 A5,DHT11 信号接数字 pin 2(记得更新 DHTPIN)。两个模块都从 Uno 的 5V 脚供电——DHT11 模块支持 3.3–5.5V,而这块 OLED 模块板上自带稳压,所以经典的 Uno OLED 接法都是直接喂 5V。

你失去的是 WiFi:Uno 能在本地显示读数,但永远没办法把数据发到你的手机。如果最终目标是联网气象站,一开始就上 ESP32——我们的 ESP32、ESP8266 和 Uno 对比讲清楚了每块板各自适合什么场景。

真实客户最常犯的错误

代价最高的一种,是凭肌肉记忆把 OLED 的红线插到第一个 pin。在这块屏上,那等于把 VCC 接到 GND 脚,电源反接可以当场烧掉模块——这是整个项目里唯一一个硬件不会原谅你的错误。

其次是拿着 4 针裸传感器的接线图来接 3 针模块:到处找那个不存在的第四个 pin、加了根本不需要的上拉电阻,或者只认图里的线色、不认模块上印的 S、VCC、GND。永远以模块自己的丝印为准。

软件方面,最常见的坑是贴来的代码里留着 DHTTYPE DHT22,让一颗好好的 DHT11 永远返回 nan。还有不少人第一步就卡住:用了只能充电、不能传数据的 micro-USB 线,板子有电却怎么都上传不了。

卡通图:浅蓝色三针 DHT11 模块接着 ESP32,旁边一个四针裸传感器被打了叉
我们的 DHT11 是 3 针模块版,上拉电阻已经在黑色 PCB 上——别看 4 针裸传感器的接线图。

FAQ

DHT11 能测冰箱那样的零下温度吗?

不能。DHT11 的量程是 0–50°C,到冰点就到底了。要记录冰箱或冷冻室温度,请选 DHT22 版本,它可以测到 −40°C——接线和 sketch 都一样,只改一行代码。

DHT11 需要外加 10k 电阻吗?

用我们的模块不需要。3 针 DHT11 模块的上拉电阻已经做在 PCB 上,三条线直接接 ESP32 就行。只有 4 针裸传感器才需要外接上拉电阻。

代码上传成功了,为什么 OLED 什么都不显示?

通常是 I2C 地址或接线的问题。跑一次 ESP32 core 自带的 WireScan 例程:如果打印出 0x3D,就把 OLED_ADDR 改过来;如果什么都扫不到,就重新检查 SDA 在 GPIO21、SCL 在 GPIO22,以及 GND 和 VCC 有没有按这块屏 GND 在前的顺序接。

这个项目可以用 power bank 供电吗?

可以——整个电路耗电很小,power bank 插到 micro-USB 口就能随身带着走。有些 power bank 遇到轻负载会自动断电;我们的 ESP32 供电方案指南讲了这个问题和更长期的供电选择。

这个项目需要面包板吗?

不需要。ESP32 开发板、DHT11 模块和 OLED 都自带公排针,七条母对母 jumper 线就能全部接好。想装得更整齐、或以后打算加更多传感器,才需要考虑面包板。

最后更新:2026年8月。有问题?WhatsApp 联系我们

Leave a Reply

Your email address will not be published. Required fields are marked *