文档
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();
}
}
运行步骤
- 在 Arduino IDE 库管理器安装:
DHT sensor library、Adafruit SSD1306、Adafruit GFX - 按硬件表接线
- 编译上传,打开串口监视器(9600 波特率)
- 按按键切换显示模式
预期输出
- OLED 实时显示温湿度(2 秒刷新)
- 串口同步输出读数
- 按键切换 4 种模式:双排紧凑 → 大字温度 → 大字湿度 → 循环
关键点
isnan()检测 DHT22 读取失败(常见于刚上电)并优雅处理- 显示刷新放在定时器中避免频繁重绘导致闪烁
- 按键用
INPUT_PULLUP省外部上拉电阻