进阶:DHT22 温湿度传感器 + OLED 显示

知识库
知识库文档
/tech-stacks/arduino/examples/进阶:DHT22 温湿度传感器 + OLED 显示.md

文档

Arduino 外设综合:温湿度传感器 DHT22 + OLED 显示

目标

使用 DHT22 采集温湿度,在 SSD1306 OLED 上实时显示,并实现按键切换显示模式。

硬件清单

元件 引脚
Arduino Uno -
DHT22 温湿度传感器 DATA → D2
SSD1306 OLED (128×64 I²C) SDA → A4, SCL → A5
按键 D3(内部上拉)

完整代码

/*
 * 温湿度监测仪 — DHT22 + SSD1306 OLED
 * 库依赖:DHT sensor library by Adafruit (>=1.4.4)
 *         Adafruit SSD1306 (>=2.5.7)
 *         Adafruit GFX Library (>=1.11.9)
 */

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

// ── 引脚定义 ──
#define DHTPIN      2
#define DHTTYPE     DHT22
#define BTN_PIN     3
#define OLED_ADDR   0x3C
#define SCREEN_W    128
#define SCREEN_H    64

// ── 对象 ──
DHT dht(DHTPIN, DHTTYPE);
Adafruit_SSD1306 display(SCREEN_W, SCREEN_H, &Wire);

// ── 状态 ──
enum DisplayMode { MODE_NORMAL, MODE_LARGE_TEMP, MODE_LARGE_HUM, MODE_COUNT };
DisplayMode mode = MODE_NORMAL;

float temperature = 0.0;
float humidity = 0.0;
unsigned long lastRead = 0, lastBtnCheck = 0;
const unsigned long READ_INTERVAL = 2000;

// ── 初始化 ──
void setup() {
  Serial.begin(9600);
  pinMode(BTN_PIN, INPUT_PULLUP);

  dht.begin();

  // OLED 初始化
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    Serial.println(F("SSD1306 初始化失败!"));
    while (1) delay(10);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 25);
  display.println(F("DHT22 Monitor"));
  display.display();
  delay(1500);
}

// ── 读取传感器 ──
bool readSensor() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();

  if (isnan(t) || isnan(h)) {
    Serial.println(F("DHT22 读取失败!"));
    return false;
  }
  temperature = t;
  humidity = h;
  return true;
}

// ── 按键处理 ──
void checkButton() {
  static bool lastState = HIGH;
  bool now = digitalRead(BTN_PIN);

  if (lastState == HIGH && now == LOW) {  // 下降沿
    delay(30);  // 消抖
    if (digitalRead(BTN_PIN) == LOW) {
      mode = (DisplayMode)((mode + 1) % MODE_COUNT);
      Serial.print(F("切换模式: "));
      Serial.println(mode);
    }
  }
  lastState = now;
}

// ── OLED 渲染 ──
void renderDisplay() {
  display.clearDisplay();

  switch (mode) {
    case MODE_NORMAL:
      renderNormal();
      break;
    case MODE_LARGE_TEMP:
      renderLarge(0, "TEMPERATURE", temperature, "C");
      break;
    case MODE_LARGE_HUM:
      renderLarge(1, "HUMIDITY", humidity, "%");
      break;
  }

  display.display();
}

void renderNormal() {
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println(F("--- DHT22 Monitor ---"));

  display.drawLine(0, 12, 128, 12, SSD1306_WHITE);

  display.setTextSize(2);
  display.setCursor(5, 20);
  display.print(temperature, 1);
  display.print((char)247);  // °
  display.print(F("C"));

  display.setTextSize(2);
  display.setCursor(5, 42);
  display.print(humidity, 1);
  display.print(F("%"));

  // 模式指示
  display.setTextSize(1);
  display.setCursor(100, 56);
  display.print(mode + 1);
  display.print(F("/"));
  display.print(MODE_COUNT);
}

void renderLarge(int icon, const char* title, float value, const char* unit) {
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print(title);

  // 大字号数值
  display.setTextSize(4);
  int x = (value < 10) ? 30 : (value < 100) ? 18 : 5;
  display.setCursor(x, 18);
  display.print(value, 1);

  display.setTextSize(2);
  display.setCursor(x + 60, 38);
  display.print(unit);

  display.setTextSize(1);
  display.setCursor(0, 56);
  display.print(F("按键切换 ["));
  display.print(mode + 1);
  display.print(F("/"));
  display.print(MODE_COUNT);
  display.print(F("]"));
}

// ── 主循环 ──
void loop() {
  unsigned long now = millis();

  // 定时读取传感器(非阻塞)
  if (now - lastRead >= READ_INTERVAL) {
    lastRead = now;
    if (readSensor()) {
      Serial.print(F("温度: "));
      Serial.print(temperature);
      Serial.print(F("°C  湿度: "));
      Serial.print(humidity);
      Serial.println(F("%"));
    }
    renderDisplay();
  }

  // 按键扫描
  if (now - lastBtnCheck >= 50) {
    lastBtnCheck = now;
    checkButton();
  }
}

运行步骤

  1. 在 Arduino IDE 库管理器安装:DHT sensor libraryAdafruit SSD1306Adafruit GFX
  2. 按硬件表接线
  3. 编译上传,打开串口监视器(9600 波特率)
  4. 按按键切换显示模式

预期输出

  • OLED 实时显示温湿度(2 秒刷新)
  • 串口同步输出读数
  • 按键切换 4 种模式:双排紧凑 → 大字温度 → 大字湿度 → 循环

关键点

  • isnan() 检测 DHT22 读取失败(常见于刚上电)并优雅处理
  • 显示刷新放在定时器中避免频繁重绘导致闪烁
  • 按键用 INPUT_PULLUP 省外部上拉电阻

信息

路径
/tech-stacks/arduino/examples/进阶:DHT22 温湿度传感器 + OLED 显示.md
更新时间
2026/5/31