本文讲解资料
已为本栏目单独生成 PPT 和短讲解视频,可直接播放或下载复用。
本文给出 ESP32 + DHT22 + SSD1306 OLED + MQTT 的接线表、依赖库、topic 设计、完整 Arduino 代码和排错清单。重点不是“又做一个温湿度计”,而是把采集、显示、上报、重连和数据质量做完整。
1. 物料清单与接线
物料:ESP32 DevKit、DHT22/AM2302、0.96 英寸 SSD1306 I2C OLED、面包板、杜邦线。接线建议:DHT22 VCC 接 3V3,GND 接 GND,DATA 接 GPIO4;OLED VCC 接 3V3,GND 接 GND,SDA 接 GPIO21,SCL 接 GPIO22。若 DHT22 模块无板载上拉,DATA 与 3V3 之间加 10k 电阻。
2. Arduino 依赖
安装 ESP32 Arduino core;库管理器安装 Adafruit DHT sensor library、Adafruit Unified Sensor、Adafruit SSD1306、Adafruit GFX、PubSubClient。Adafruit 的 DHT 库说明其支持 DHT11、DHT22 等低成本温湿度传感器,Espressif 文档说明 ESP32 Wi-Fi API 支持 STA 模式连接路由器。
3. MQTT Topic 设计
建议用清晰的层级:esp32/room1/temperature、esp32/room1/humidity、esp32/room1/status。温湿度使用 retain=true,状态使用 LWT:offline,连接后发布 online。这样 dashboard 重启后能立刻拿到最近值,也能看到节点是否掉线。
4. 完整 Arduino 代码
下方代码使用 PubSubClient,逻辑比演示项目略完整:Wi-Fi 与 MQTT 自动重连,DHT 读数失败时跳过发布,OLED 显示最新数值和连接状态。把 Wi-Fi 和 broker 地址换成你的环境即可。
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "DHT.h"
#define WIFI_SSID "YOUR_WIFI"
#define WIFI_PASS "YOUR_PASSWORD"
#define MQTT_HOST "192.168.1.10"
#define MQTT_PORT 1883
#define DHTPIN 4
#define DHTTYPE DHT22
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
DHT dht(DHTPIN, DHTTYPE);
WiFiClient wifiClient;
PubSubClient mqtt(wifiClient);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
const char* topicTemp = "esp32/room1/temperature";
const char* topicHum = "esp32/room1/humidity";
const char* topicStatus = "esp32/room1/status";
unsigned long lastPublish = 0;
const unsigned long publishInterval = 10000;
void drawStatus(float t, float h, const char* status) {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println("ESP32 Room Node");
display.setTextSize(2);
display.setCursor(0, 18);
display.printf("%.1f C", t);
display.setCursor(0, 42);
display.printf("%.1f %%", h);
display.setTextSize(1);
display.setCursor(84, 54);
display.print(status);
display.display();
}
void connectWiFi() {
if (WiFi.status() == WL_CONNECTED) return;
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void connectMqtt() {
while (!mqtt.connected()) {
String clientId = "esp32-room1-" + String((uint32_t)ESP.getEfuseMac(), HEX);
if (mqtt.connect(clientId.c_str(), topicStatus, 1, true, "offline")) {
mqtt.publish(topicStatus, "online", true);
} else {
delay(1000);
}
}
}
void setup() {
Serial.begin(115200);
dht.begin();
Wire.begin(21, 22);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.display();
connectWiFi();
mqtt.setServer(MQTT_HOST, MQTT_PORT);
}
void loop() {
connectWiFi();
connectMqtt();
mqtt.loop();
if (millis() - lastPublish < publishInterval) return;
lastPublish = millis();
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(t) || isnan(h)) {
Serial.println("DHT read failed");
drawStatus(0, 0, "DHT ERR");
return;
}
char tempPayload[12];
char humPayload[12];
dtostrf(t, 1, 2, tempPayload);
dtostrf(h, 1, 2, humPayload);
mqtt.publish(topicTemp, tempPayload, true);
mqtt.publish(topicHum, humPayload, true);
drawStatus(t, h, mqtt.connected() ? "MQTT OK" : "MQTT --");
}
5. 排错清单
OLED 黑屏:确认地址是否为 0x3C,SDA/SCL 是否接反。DHT 偶发 NaN:检查供电和上拉,降低读取频率。MQTT 连不上:先用电脑 mqtt client 连接 broker,再检查端口、防火墙和匿名登录策略。长期运行不稳定:优先排查电源和 Wi-Fi 信号。
结论
- ESP32 用 STA 模式连接家庭路由器;Wi-Fi 事件回调要保持轻量,复杂逻辑放回主循环。
- DHT22 采样不要太频繁,建议 2 秒以上;本文上报间隔默认 10 秒。
- MQTT topic 要稳定、可读、可扩展。温度、湿度和在线状态分开,比一条混乱字符串更好维护。
- 长期运行的关键是失败处理:读取 NaN 不发布,Wi-Fi/MQTT 断线要重连,OLED 要显示状态。