前言:讓 ESP32 開始感知環境
前面的 ESP32 教學中,我們已經學會:
GPIO Output
GPIO Input
PWM
ADC
Touch Sensor
這些功能讓 ESP32 可以:
控制 LED
讀取按鍵
調整亮度
讀取類比訊號
感應觸摸
接下來開始進入真正的:
Sensor 感測器應用
最適合入門的環境 Sensor 之一,就是:
DHT11
DHT22
它們可以同時測量:
Temperature
+
Humidity
也就是:
溫度 + 相對濕度
只需要一個 Data GPIO,就可以讓 ESP32 取得兩種環境資訊。
因此非常適合拿來製作:
數位溫溼度計
室內環境監測器
智慧家庭 Sensor
高溫警報器
溫室監控
機房監測
IoT 環境節點
風扇自動控制器
本章將從最基本的:
DHT11 / DHT22
↓
接線
↓
Library
↓
readTemperature()
↓
readHumidity()
↓
Sensor Error
↓
Serial Monitor
一路完成:
ESP32 數位溫溼度計
並進一步製作:
ESP32 高溫警報器
一、DHT11 是什麼?
DHT11 是非常常見的低成本:
Digital Temperature and Humidity Sensor
可以同時測量:
Temperature
Humidity
DHT11 的優點是:
價格低
接線簡單
只需要一條 Data
Arduino / ESP32 Library 很成熟
適合入門教材
Adafruit 提供的 DHT11 規格資料顯示,其典型應用範圍約為:
溫度:
0~50°C
精度約 ±2°C
濕度:
20~80% RH
精度約 ±5% RH
最大取樣頻率約:
1 Hz
也就是最快約每秒讀取一次。
所以 DHT11 很適合:
Arduino / ESP32 入門
一般室內環境監測
教育實驗
非高精度用途
二、DHT22 是什麼?
DHT22 也是:
Temperature + Humidity Sensor
常見型號也包括:
AM2302
和 DHT11 相比,DHT22:
量測範圍更大
解析度更高
溫度精度較好
濕度範圍更廣
Adafruit 提供的資料顯示,DHT22 / AM2302 大致可量測:
Temperature:
-40~80°C
約 ±0.5°C
Humidity:
0~100% RH
約 ±2~5% RH
最大取樣頻率約:
0.5 Hz
也就是:
約每 2 秒讀取一次
因此如果專案對量測範圍與精度要求較高:
DHT22 通常會比 DHT11 更適合。
三、DHT11 與 DHT22 比較
| 項目 | DHT11 | DHT22 / AM2302 |
|---|---|---|
| 溫度範圍 | 約 0~50°C | 約 -40~80°C |
| 溫度精度 | 約 ±2°C | 約 ±0.5°C |
| 濕度範圍 | 約 20~80% RH | 約 0~100% RH |
| 濕度精度 | 約 ±5% RH | 約 ±2~5% RH |
| 最大取樣頻率 | 約 1 Hz | 約 0.5 Hz |
| 成本 | 較低 | 較高 |
| 適合用途 | 教學、一般室內 | 較完整環境監測 |
如果只是:
ESP32 入門
+
室內溫溼度
DHT11 就可以。
如果希望:
範圍更廣
精度較好
負溫度量測
則建議選:
DHT22
四、DHT11 / DHT22 是數位感測器
這一點和上一章 ADC 很不一樣。
上一章 LDR 使用:
Analog Voltage
↓
ADC
↓
0~4095
DHT11 / DHT22 則是:
Sensor
↓
Digital Communication
↓
ESP32 GPIO
所以不需要:
analogRead();
而是利用 DHT Library 與 Sensor 通訊。
概念:
ESP32
│
GPIO
│
Data
│
DHT11 / DHT22
DHT Sensor 會把:
Humidity
Temperature
Checksum
經由單一 Data Line 傳回 ESP32。
五、DHT Sensor 為什麼不像普通 digitalRead()?
DHT 的 Data Pin 雖然也是:
HIGH / LOW
訊號,
但它並不是:
digitalRead(DHT_PIN);
一次就可以取得溫度。
DHT Sensor 使用特定的:
Timing Protocol
資料是透過一連串精確時間長度的脈波傳輸。
因此實際程式通常交給:
DHT Library
負責處理。
這也是為什麼初學者不需要自己分析數十個微秒級 Pulse。
Adafruit DHT Library 目前的底層程式會根據不同 DHT 型號產生啟動訊號,再分析 Sensor 回傳的脈波資料。
六、本章使用哪一套 DHT Library?
本章使用:
DHT sensor library by Adafruit
Arduino IDE 可以直接安裝。
Adafruit 官方目前的教學方式仍然是:
Arduino IDE
↓
Library Manager
↓
搜尋 DHT
↓
DHT sensor library by Adafruit
另外還需要:
Adafruit Unified Sensor
作為 Dependency。
七、Arduino IDE 安裝 DHT Library
在 Arduino IDE:
Sketch
↓
Include Library
↓
Manage Libraries
或者直接開啟:
Library Manager
搜尋:
DHT sensor library
找到:
DHT sensor library
by Adafruit
安裝。
接著搜尋:
Adafruit Unified Sensor
再安裝:
Adafruit Unified Sensor
目前 Adafruit 官方 DHT Library 仍明確列出:
Adafruit Unified Sensor Driver 為 Dependency。
八、DHT11 常見腳位
裸的 4 Pin DHT11 / DHT22 通常具有:
VCC
DATA
NC
GND
從 Sensor 正面看,常見排列概念為:
Pin 1
VCC
Pin 2
DATA
Pin 3
NC
Pin 4
GND
但正式接線仍應以:
你手上 Sensor 的 Datasheet / Module 標示
為準。
如果是三腳 Module,
常見標示:
VCC
DATA / OUT / S
GND
而且很多 DHT Module 已經內建 Data Pull-up 電阻。
九、裸 Sensor 為什麼要 Pull-up 電阻?
Adafruit 的 DHT 接線範例建議裸 Sensor 在:
DATA
與:
VCC
之間加入:
約 10KΩ Pull-up
例如:
3.3V
│
├──────── DHT VCC
│
10KΩ
│
└──────── DHT DATA
│
└──── ESP32 GPIO
如果使用現成三腳 DHT Module,
模組上通常可能已經有:
Pull-up Resistor
此時通常不用另外再裝一顆。
十、本章 DHT 接線
本章使用:
DHT DATA → GPIO4
ESP32:
3.3V
GPIO4
GND
DHT Module:
VCC
DATA
GND
接線表:
| ESP32 | DHT11 / DHT22 |
|---|---|
| 3.3V | VCC |
| GPIO4 | DATA |
| GND | GND |
如果使用裸 4 Pin Sensor:
DATA
↔
VCC
之間加入約:
10KΩ
Pull-up。
ESP32 是 3.3V Logic 系統,因此本教材使用:
3.3V
供電與 Data Pull-up,避免讓 ESP32 GPIO Data Line 被拉到 5V。
十一、第一個 DHT11 程式
程式首先需要:
#include <DHT.h>
然後定義:
#define DHTPIN 4
#define DHTTYPE DHT11
建立 Sensor:
DHT dht(
DHTPIN,
DHTTYPE
);
在:
setup()
執行:
dht.begin();
十二、ESP32 DHT11 基本程式
#include <DHT.h>
#define DHTPIN 4
#define DHTTYPE DHT11
DHT dht(
DHTPIN,
DHTTYPE
);
void setup()
{
Serial.begin(115200);
dht.begin();
Serial.println(
"ESP32 DHT11 Start"
);
}
void loop()
{
delay(2000);
float humidity =
dht.readHumidity();
float temperature =
dht.readTemperature();
Serial.print(
"Temperature = "
);
Serial.print(
temperature
);
Serial.println(
" °C"
);
Serial.print(
"Humidity = "
);
Serial.print(
humidity
);
Serial.println(
" %"
);
}
十三、readTemperature()
讀取 Celsius:
float temperature =
dht.readTemperature();
預設取得:
°C
例如:
Temperature = 27.3 °C
Adafruit DHT Library 目前 readTemperature() 預設以 Celsius 回傳;如果傳入 true 則可轉換成 Fahrenheit。
十四、讀取華氏溫度
也可以:
float fahrenheit =
dht.readTemperature(true);
例如:
Temperature = 81.1 °F
本系列教材以:
Celsius °C
為主。
十五、readHumidity()
讀取相對濕度:
float humidity =
dht.readHumidity();
例如:
Humidity = 63.2 %
這裡的 % 指:
Relative Humidity
也就是:
% RH
十六、什麼是 Relative Humidity?
Humidity 通常不是「空氣裡有多少克水」這麼單純。
DHT Sensor 回傳的是:
Relative Humidity
也就是:
相對濕度
例如:
50% RH
代表目前空氣中的水氣含量相對於該溫度下飽和水氣能力的比例約為 50%。
一般環境監控常會看到:
Temperature
27.5°C
Humidity
65%
這兩個值應一起觀察。
十七、DHT11 / DHT22 不能一直瘋狂讀取
這是非常常見的錯誤。
不要寫:
void loop()
{
float t =
dht.readTemperature();
float h =
dht.readHumidity();
}
讓 ESP32 每秒嘗試讀取成千上萬次。
因為 DHT 是:
Low Sampling Rate Sensor
DHT11 硬體最大約:
1 Hz
DHT22 最大約:
0.5 Hz
Adafruit 官方範例也採用約:
delay(2000);
再進行下一次讀取。
十八、本系列統一使用 2 秒讀取一次
本章不管使用:
DHT11
或:
DHT22
統一使用:
const unsigned long
READ_INTERVAL = 2000;
也就是:
2 秒
原因有兩個。
第一:
DHT22
本來就只適合約每 2 秒更新一次。
第二,目前 Adafruit DHT Library 本身:
MIN_INTERVAL
仍設定為:
2000 ms
用來避免過於頻繁地重新讀取 Sensor。
因此用:
2 seconds
最簡單,也能同時適用 DHT11 與 DHT22。
十九、DHT22 程式如何修改?
如果原本:
#define DHTTYPE DHT11
改成:
#define DHTTYPE DHT22
其他大部分程式可以保持不變。
例如:
#include <DHT.h>
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(
DHTPIN,
DHTTYPE
);
這就是使用 DHT Library 最大的優點之一。
同一套:
readTemperature();
readHumidity();
可以支援不同 DHT Sensor。
Adafruit 官方範例也是透過切換:
DHTTYPE
來選擇 DHT11 或 DHT22。
二十、什麼是 Sensor Error?
實際使用 DHT 時,可能會碰到:
Failed to read from DHT sensor
原因可能很多:
接線錯誤
Sensor 沒有供電
DATA Pin 錯誤
DHTTYPE 設錯
Pull-up 不正確
讀取 Timing 失敗
線路太長
Sensor 故障
電源不穩
這時:
dht.readTemperature();
或:
dht.readHumidity();
可能回傳:
NaN
二十一、NaN 是什麼?
NaN:
Not a Number
意思就是:
這次沒有取得有效的數值。
所以不能只寫:
Serial.println(
temperature
);
還要檢查:
isnan();
例如:
if (
isnan(temperature)
)
{
Serial.println(
"Temperature Error"
);
}
Adafruit 官方 DHT 範例同樣使用 isnan() 判斷 Temperature / Humidity 讀取是否失敗。
二十二、正確的 Sensor Error 判斷
推薦:
float humidity =
dht.readHumidity();
float temperature =
dht.readTemperature();
if (
isnan(humidity)
||
isnan(temperature)
)
{
Serial.println(
"Failed to read from DHT sensor!"
);
return;
}
如果任何一個:
Temperature
Humidity
無效,
本次資料就不要繼續處理。
二十三、為什麼不要用錯誤資料控制設備?
假設未檢查:
NaN
就直接:
Temperature
↓
Relay
↓
Fan
當 Sensor 失效時,
控制邏輯可能變得不可靠。
因此真正的 Sensor 系統應該是:
Read Sensor
↓
Validate Data
↓
Valid?
├── YES → Process
└── NO → Error Handling
這是非常重要的工程習慣。
二十四、實作一:ESP32 數位溫溼度計
第一個正式實作:
ESP32 Digital Thermometer & Hygrometer
雖然目前沒有 LCD,
但 Serial Monitor 就是第一個顯示介面。
流程:
ESP32
↓
DHT11 / DHT22
↓
Temperature
Humidity
↓
Sensor Error Check
↓
Serial Monitor
二十五、ESP32 數位溫溼度計完整程式
/*
第 8 章
ESP32 DHT11 / DHT22
實作:
ESP32 數位溫溼度計
DHT DATA:
GPIO4
Library:
DHT sensor library by Adafruit
Dependency:
Adafruit Unified Sensor
*/
#include <DHT.h>
// -----------------------------
// DHT
// -----------------------------
const uint8_t DHT_PIN = 4;
// DHT11
#define DHT_TYPE DHT11
// 如果使用 DHT22,改成:
// #define DHT_TYPE DHT22
DHT dht(
DHT_PIN,
DHT_TYPE
);
// -----------------------------
// Read Interval
// -----------------------------
const unsigned long
READ_INTERVAL = 2000;
unsigned long
lastReadTime = 0;
// -----------------------------
// setup()
// -----------------------------
void setup()
{
Serial.begin(
115200
);
delay(
500
);
Serial.println();
Serial.println(
"ESP32 DHT Temperature"
);
Serial.println(
"& Humidity Monitor"
);
dht.begin();
Serial.println(
"DHT Sensor Ready"
);
}
// -----------------------------
// loop()
// -----------------------------
void loop()
{
unsigned long
currentTime =
millis();
if (
currentTime
- lastReadTime
>= READ_INTERVAL
)
{
lastReadTime =
currentTime;
// -------------------------
// Read Sensor
// -------------------------
float humidity =
dht.readHumidity();
float temperature =
dht.readTemperature();
// -------------------------
// Sensor Error
// -------------------------
if (
isnan(humidity)
||
isnan(temperature)
)
{
Serial.println(
"DHT Sensor Error!"
);
return;
}
// -------------------------
// Display
// -------------------------
Serial.println(
"--------------------"
);
Serial.print(
"Temperature : "
);
Serial.print(
temperature,
1
);
Serial.println(
" °C"
);
Serial.print(
"Humidity : "
);
Serial.print(
humidity,
1
);
Serial.println(
" %RH"
);
}
}
readHumidity()、readTemperature() 與 isnan() 都是 Adafruit 官方 DHT 範例目前採用的基本讀取方式。
二十六、為什麼正式版不用 delay(2000)?
最簡單的範例可以:
delay(2000);
但是本章正式程式改成:
millis();
原因是:
delay(2000)
↓
ESP32 整段停住 2 秒
未來如果加入:
Button
Touch
Wi-Fi
MQTT
Web Server
LED Animation
Relay
就會受到影響。
使用:
millis();
則可以:
每 2 秒讀 DHT
同時:
loop()
仍然可以執行其他工作。
二十七、millis() 讀取架構
基本公式:
if (
currentTime
- lastReadTime
>= READ_INTERVAL
)
{
lastReadTime =
currentTime;
// Read Sensor
}
這種寫法非常重要。
因為後面的 IoT 程式通常變成:
loop()
├── 每 20ms 處理 Button
├── 每 100ms 更新 Display
├── 每 2s 讀 DHT
├── 每 5s 上傳 MQTT
└── 持續處理 Wi-Fi
而不是大量:
delay();
二十八、Serial Monitor 顯示格式
本章建議:
--------------------
Temperature : 27.4 °C
Humidity : 62.7 %RH
這比:
27.4
62.7
更容易 Debug。
真正工程專案的 Serial Output 最好帶:
名稱
數值
單位
錯誤
狀態
例如:
Temperature : 27.4 °C
Humidity : 62.7 %RH
Sensor : OK
二十九、如何顯示 Sensor Status?
可以增加:
Serial.println(
"Sensor : OK"
);
如果 Error:
Serial.println(
"Sensor : ERROR"
);
這樣未來做:
LCD
OLED
Web Dashboard
MQTT
就可以直接使用相同概念。
三十、DHT11 為什麼看起來數值變化很慢?
因為 DHT11 / DHT22 本來就是:
低速環境 Sensor
Adafruit 也直接形容這類 Sensor 的更新速度較慢,DHT11 約每秒一次,DHT22 約每兩秒一次。
所以它適合:
室內溫度
室內濕度
環境監控
不適合:
高速溫度變化
高速控制回授
快速資料擷取
如果專案要求高速,
應使用其他 Sensor。
三十一、DHT11 與 DHT22 怎麼選?
如果是:
ESP32 入門教材
選:
DHT11
原因:
便宜
容易取得
容易理解
如果是:
比較正式的環境監測
建議:
DHT22
因為:
量測範圍更廣
溫度精度較好
濕度範圍更完整
三十二、DHT Sensor 適合精密量測嗎?
不適合把 DHT11 視為:
實驗室精密溫溼度計
DHT11 本身就是:
Low Cost Sensor
如果專案需要:
高精度
高穩定性
長期校準
工業等級
應該選用更高階 Sensor。
DHT11 / DHT22 更適合:
教育
IoT Demo
一般環境監測
Threshold Control
趨勢觀察
三十三、進階實作:ESP32 高溫警報器
現在把 DHT Sensor 從:
只是顯示數字
升級成:
自動控制系統
加入:
LED
+
Passive Buzzer
流程:
DHT
↓
Temperature
↓
ESP32
↓
Threshold
↓
高溫?
├── NO → Normal
└── YES → LED + Buzzer
三十四、高溫警報器材料
| 元件 | 數量 |
|---|---|
| ESP32 | 1 |
| DHT11 或 DHT22 | 1 |
| LED | 1 |
| 220Ω~330Ω 電阻 | 1 |
| Passive Buzzer | 1 |
| 麵包板 | 1 |
| 杜邦線 | 若干 |
本章使用:
DHT DATA
→ GPIO4
Alarm LED
→ GPIO18
Passive Buzzer
→ GPIO23
三十五、高溫警報接線
DHT
ESP32 3.3V
→ DHT VCC
ESP32 GPIO4
→ DHT DATA
ESP32 GND
→ DHT GND
LED
GPIO18
│
220Ω
│
LED
│
GND
Passive Buzzer
概念:
GPIO23
│
Buzzer
│
GND
但實際 Buzzer 的:
工作電壓
驅動電流
要先查 Datasheet。
如果需要的電流超過 GPIO 適合直接驅動的範圍,
應改成:
GPIO23
↓
Transistor / Driver
↓
Buzzer
三十六、設定高溫 Threshold
例如:
const float
HIGH_TEMP_THRESHOLD =
30.0;
代表:
Temperature
>= 30.0°C
啟動警報。
實際應用當然可以改成:
28°C
35°C
40°C
50°C
依設備需求決定。
三十七、最簡單的高溫判斷
if (
temperature
>= HIGH_TEMP_THRESHOLD
)
{
// Alarm
}
else
{
// Normal
}
例如:
27°C
↓
Normal
30°C
↓
Alarm
35°C
↓
Alarm
三十八、為什麼最好加入 Hysteresis?
假設 Threshold:
30°C
Sensor 在附近變成:
29.9
30.1
29.8
30.2
29.9
那麼 Alarm 就會:
ON
OFF
ON
OFF
一直跳。
解決方式:
Hysteresis
例如:
30°C
→ Alarm ON
28.5°C
→ Alarm OFF
中間:
28.5~30°C
保持原來狀態。
三十九、高溫警報 Hysteresis
設定:
const float
ALARM_ON_TEMP = 30.0;
const float
ALARM_OFF_TEMP = 28.5;
邏輯:
if (
!alarmState
&&
temperature
>= ALARM_ON_TEMP
)
{
alarmState = true;
}
以及:
if (
alarmState
&&
temperature
<= ALARM_OFF_TEMP
)
{
alarmState = false;
}
這樣會穩定很多。
四十、進階實作:ESP32 高溫警報器完整程式
/*
第 8 章
ESP32 DHT11 / DHT22
進階實作:
ESP32 高溫警報器
功能:
1. DHT 溫度讀取
2. DHT 濕度讀取
3. Sensor Error Check
4. 2 秒非阻塞式讀取
5. Serial Monitor
6. LED 高溫警報
7. Passive Buzzer 警報
8. Temperature Hysteresis
GPIO:
DHT DATA -> GPIO4
LED -> GPIO18
Buzzer -> GPIO23
Arduino-ESP32:
3.x LEDC API
*/
#include <DHT.h>
// =====================================
// DHT
// =====================================
const uint8_t DHT_PIN =
4;
#define DHT_TYPE DHT11
// 使用 DHT22 時改成:
// #define DHT_TYPE DHT22
DHT dht(
DHT_PIN,
DHT_TYPE
);
// =====================================
// Alarm Output
// =====================================
const uint8_t LED_PIN =
18;
const uint8_t BUZZER_PIN =
23;
// =====================================
// Temperature Threshold
// =====================================
const float
ALARM_ON_TEMP =
30.0;
const float
ALARM_OFF_TEMP =
28.5;
bool alarmState =
false;
// =====================================
// Sensor Interval
// =====================================
const unsigned long
READ_INTERVAL =
2000;
unsigned long
lastReadTime =
0;
// =====================================
// Buzzer Frequency
// =====================================
const uint32_t
BUZZER_FREQ =
2000;
const uint8_t
BUZZER_RESOLUTION =
8;
// =====================================
// Alarm Output
// =====================================
void updateAlarm()
{
if (
alarmState
)
{
digitalWrite(
LED_PIN,
HIGH
);
ledcWriteTone(
BUZZER_PIN,
2000
);
}
else
{
digitalWrite(
LED_PIN,
LOW
);
ledcWriteTone(
BUZZER_PIN,
0
);
}
}
// =====================================
// setup()
// =====================================
void setup()
{
Serial.begin(
115200
);
delay(
500
);
Serial.println();
Serial.println(
"ESP32 DHT High"
);
Serial.println(
"Temperature Alarm"
);
// -----------------------------
// DHT
// -----------------------------
dht.begin();
// -----------------------------
// LED
// -----------------------------
pinMode(
LED_PIN,
OUTPUT
);
digitalWrite(
LED_PIN,
LOW
);
// -----------------------------
// Passive Buzzer
// -----------------------------
if (!ledcAttach(
BUZZER_PIN,
BUZZER_FREQ,
BUZZER_RESOLUTION))
{
Serial.println(
"Buzzer LEDC Error!"
);
}
ledcWriteTone(
BUZZER_PIN,
0
);
Serial.println(
"System Ready"
);
}
// =====================================
// loop()
// =====================================
void loop()
{
unsigned long
currentTime =
millis();
// -----------------------------
// Sensor Interval
// -----------------------------
if (
currentTime
- lastReadTime
< READ_INTERVAL
)
{
return;
}
lastReadTime =
currentTime;
// -----------------------------
// Read DHT
// -----------------------------
float humidity =
dht.readHumidity();
float temperature =
dht.readTemperature();
// -----------------------------
// Sensor Error
// -----------------------------
if (
isnan(humidity)
||
isnan(temperature)
)
{
Serial.println(
"DHT Sensor Error!"
);
/*
Sensor Error 時:
本例關閉 Alarm Output。
真正安全相關設備,
應依 Fail-safe 需求決定
Sensor Error 要採取什麼動作。
*/
alarmState =
false;
updateAlarm();
return;
}
// -----------------------------
// Alarm ON
// -----------------------------
if (
!alarmState
&&
temperature
>= ALARM_ON_TEMP
)
{
alarmState =
true;
}
// -----------------------------
// Alarm OFF
// -----------------------------
if (
alarmState
&&
temperature
<= ALARM_OFF_TEMP
)
{
alarmState =
false;
}
// -----------------------------
// Update Output
// -----------------------------
updateAlarm();
// -----------------------------
// Serial Monitor
// -----------------------------
Serial.println(
"-------------------------"
);
Serial.print(
"Temperature : "
);
Serial.print(
temperature,
1
);
Serial.println(
" °C"
);
Serial.print(
"Humidity : "
);
Serial.print(
humidity,
1
);
Serial.println(
" %RH"
);
Serial.print(
"Alarm : "
);
Serial.println(
alarmState
? "HIGH TEMPERATURE"
: "NORMAL"
);
}
四十一、高溫警報器執行流程
ESP32 開機:
setup()
↓
DHT begin()
↓
LED Output
↓
Buzzer LEDC
↓
System Ready
接著每:
2 seconds
執行:
DHT
↓
Temperature
Humidity
↓
Valid?
如果:
Sensor Error
則:
Error Handling
如果資料正常:
Temperature
↓
Threshold
四十二、Normal 狀態
例如:
Temperature
= 26.5°C
結果:
LED
OFF
Buzzer
OFF
Alarm
NORMAL
四十三、高溫狀態
例如:
Temperature
= 31.2°C
超過:
30.0°C
因此:
Alarm State
ON
輸出:
LED
ON
Buzzer
2000 Hz
Serial
HIGH TEMPERATURE
四十四、溫度下降時
Alarm 已經 ON,
不會在:
29.9°C
立即關閉。
而要等到:
Temperature
<= 28.5°C
才:
Alarm OFF
這就是:
Hysteresis(補充說明)
可以避免 Alarm 在臨界溫度附近快速切換。
四十五、Sensor Error 時到底應不應該關閉警報?
這取決於專案。
本章教育範例使用:
Sensor Error
↓
Alarm Output OFF
主要方便理解。
但如果是:
機房
鍋爐
工業設備
醫療
安全監控
Sensor Error 本身就可能應該:
觸發 Fault Alarm
例如:
Temperature Alarm
+
Sensor Fault Alarm
甚至:
Sensor Error
↓
進入 Fail-safe Mode
所以不要直接把教材中的 Error 行為套到安全關鍵系統。
四十六、如何把 Sensor Error 獨立成狀態?
更完整的系統可以定義:
STATE_NORMAL
STATE_HIGH_TEMP
STATE_SENSOR_ERROR
例如:
正常
→ Green
高溫
→ Red + Buzzer
Sensor Error
→ Yellow + Different Buzzer
這會比單純:
ON / OFF
更像真正產品。
四十七、常見錯誤:Failed to read from DHT sensor
如果看到:
DHT Sensor Error!
先依序檢查:
1. VCC
2. GND
3. DATA GPIO
4. DHTTYPE
5. Pull-up
6. Library
7. Sensor
8. 讀取間隔
不要第一時間就認為:
ESP32 壞掉。
四十八、常見錯誤:DHTTYPE 設錯
如果硬體是:
DHT11
程式卻:
#define DHT_TYPE DHT22
Sensor Data 解碼方式會不正確。
所以:
DHT11
要:
#define DHT_TYPE DHT11
DHT22:
#define DHT_TYPE DHT22
Adafruit 官方測試程式也是透過這個 Macro 選擇不同 Sensor。
四十九、常見錯誤:一直快速讀 DHT
不要:
loop()
↓
read
↓
read
↓
read
↓
read
Adafruit 目前官方範例仍然在兩次 Measurement 之間:
delay(2000);
而目前 Library 的讀取實作也具有 2000 ms Minimum Interval Cache。
本章建議:
READ_INTERVAL
=
2000 ms
五十、常見錯誤:三腳模組又另外亂加 Pull-up
如果使用:
DHT Module
很多模組 PCB 已經有:
Pull-up Resistor
通常不必另外再加。
如果使用:
裸 DHT Sensor
才應特別確認 Data Pull-up。
最可靠的方法:
看你手上模組的電路圖或 PCB。
五十一、常見錯誤:DHT Data Pull-up 到 5V
ESP32 GPIO 是:
3.3V Logic
因此不要把 DHT Data Line 透過 Pull-up:
拉到 5V
再直接接 ESP32 GPIO。
本章統一:
Sensor VCC
→ 3.3V
Data Pull-up
→ 3.3V
讓 GPIO 電壓保持在適合 ESP32 的邏輯範圍。
五十二、常見錯誤:溫度突然顯示 nan
例如:
Temperature = nan
這不是:
0°C
而是:
無效資料
程式應:
if (
isnan(temperature)
)
判斷。
不能把 NaN 當真正 Sensor Data。
Adafruit 官方範例同樣會在任一 DHT Read 為 NaN 時直接回報 Failure。
五十三、如何同時讀攝氏與華氏?
float celsius =
dht.readTemperature();
float fahrenheit =
dht.readTemperature(true);
然後:
27.5°C
81.5°F
如果你的網站未來要提供國際使用者,
可以同時顯示:
°C / °F
五十四、DHT Library 還能計算 Heat Index
Adafruit DHT Library 另外提供:
computeHeatIndex();
例如:
float heatIndex =
dht.computeHeatIndex(
temperature,
humidity,
false
);
其中:
false
代表使用 Celsius。
Adafruit 官方 DHTtester 範例目前也示範 Celsius / Fahrenheit Heat Index 計算。
這可以延伸做:
體感熱度
環境舒適度
高溫警告
但本章主軸仍然先放在:
Temperature
Humidity
Sensor Error
五十五、Serial Monitor 可以加入 Heat Index
例如:
Temperature : 30.5 °C
Humidity : 75.2 %RH
Heat Index : 34.7 °C
這比單純:
30.5°C
能提供更多環境資訊。
不過 Heat Index 是經公式計算的衍生數據,
不是 Sensor 直接量到第三個物理量。
五十六、ESP32 + DHT 可以加入 LCD1602 嗎?
可以。
架構:
DHT11 / DHT22
↓
ESP32
↓
Temperature + Humidity
↓
I²C
↓
LCD1602
顯示例如:
TEMP: 27.5 C
HUM : 63.2 %
這就會從:
Serial Monitor
正式變成:
獨立式數位溫溼度計
五十七、ESP32 + DHT + OLED
也可以使用:
SSD1306 OLED
顯示:
Temperature
Humidity
Trend
Alarm
Wi-Fi
例如:
TEMP
27.5 C
HUM
63.2 %
STATUS
NORMAL
五十八、ESP32 + DHT + Relay
前面高溫警報只是:
LED
Buzzer
再進一步:
Temperature
↓
Threshold
↓
Relay
↓
Fan
即可製作:
高溫自動風扇
例如:
>= 30°C
→ Fan ON
<= 28°C
→ Fan OFF
同樣使用:
Hysteresis(補充說明 2)
避免 Relay 一直跳。
五十九、注意 Relay 不要直接驅動大負載
ESP32 GPIO 只能輸出:
Control Signal
真正控制:
風扇
馬達
燈具
加熱器
應使用:
Relay Module
MOSFET
Driver
SSR
並依:
Voltage
Current
Isolation
Safety
正確設計。
六十、ESP32 + DHT + Wi-Fi
ESP32 相較 Arduino UNO 最大的優勢之一就是:
Wi-Fi
因此 DHT 專題下一步非常自然:
DHT11 / DHT22
↓
ESP32
↓
Wi-Fi
↓
Web Server / MQTT / Cloud
就可以建立:
IoT 溫溼度監控器
例如:
Room
↓
DHT22
↓
ESP32
↓
Wi-Fi
↓
MQTT
↓
Dashboard
六十一、ESP32 + DHT + Web Server
後續可以做:
ESP32 IP
↓
Browser
↓
Temperature
Humidity
例如:
ESP32 Environment Monitor
Temperature
27.4 °C
Humidity
62.5 %
Status
NORMAL
這樣手機直接用 Browser 就可以查看。
六十二、ESP32 + DHT + MQTT
進一步:
ESP32
↓
MQTT Broker
發布:
home/room1/temperature
home/room1/humidity
資料:
27.4
62.5
就能與:
Home Assistant
Node-RED
Server
Database
Dashboard
整合。
六十三、ESP32 + DHT + Database
資料流程:
DHT
↓
ESP32
↓
Wi-Fi
↓
API / MQTT
↓
Database
資料表:
Time
Temperature
Humidity
例如:
10:00 26.8 60.2
10:05 27.0 61.0
10:10 27.3 61.5
這樣就可以繪製:
Temperature Trend
Humidity Trend
六十四、ESP32 DHT 專案適合哪些用途?
室內環境監測
ESP32
+
DHT22
+
OLED
高溫警報器
DHT
↓
Threshold
↓
Buzzer
自動風扇
DHT
↓
Temperature
↓
Relay
↓
Fan
智慧溫室
Temperature
Humidity
↓
ESP32
↓
Fan
Pump
Cloud
機房環境監控
DHT22
↓
ESP32
↓
Wi-Fi
↓
Alert
不過正式機房或安全關鍵監測應選擇符合實際可靠度需求的工業級 Sensor,而不應把低成本 DHT 教學模組當唯一安全監控設備。
六十五、DHT11 / DHT22 不適合哪些場合?
不適合:
高精度實驗室量測
快速溫度回授
安全關鍵控制
極端環境
工業認證量測
DHT11 尤其屬於:
Low-cost Sensor
比較適合:
學習
IoT Prototype
一般環境趨勢
Threshold
DHT22 雖然精度較好,
但仍應依專案要求選擇 Sensor。
六十六、FAQ:ESP32 DHT11 / DHT22 常見問題
Q1:ESP32 可以使用 DHT11 嗎?
可以。
DHT11 使用單一 Digital Data Line,可以搭配 Adafruit DHT Library 由 ESP32 讀取 Temperature 與 Humidity。
Q2:ESP32 可以使用 DHT22 嗎?
可以。
程式只需要將:
#define DHT_TYPE DHT11
改成:
#define DHT_TYPE DHT22
即可使用相同的 readTemperature() 與 readHumidity() API。
Q3:DHT11 與 DHT22 哪個比較好?
DHT22:
溫度範圍更廣
濕度範圍更廣
溫度精度較佳
DHT11:
價格較低
適合基礎教學
Q4:ESP32 DHT 要多久讀一次?
本教材建議:
2000 ms
也就是:
2 秒
Adafruit 官方 DHTtester 目前也是等待約兩秒再進行下一次 Measurement,而目前 Library 內部的 Minimum Interval 也是 2000 ms。
Q5:為什麼 DHT 回傳 NaN?
NaN:
Not a Number
代表此次讀取失敗。
可能原因:
接線
供電
GPIO
Sensor Type
Pull-up
Timing
Sensor Error
應使用:
isnan();
檢查。
Q6:如何讀取溫度?
float temperature =
dht.readTemperature();
取得 Celsius。
Q7:如何讀取濕度?
float humidity =
dht.readHumidity();
取得 Relative Humidity。
Q8:DHT11 可以讀負溫度嗎?
DHT11 的一般額定溫度範圍約為:
0~50°C
若需要負溫度環境,
DHT22 的額定範圍約:
-40~80°C
更合適。
Q9:DHT11 精度是多少?
Adafruit 提供的規格整理約為:
Temperature
±2°C
Humidity
±5% RH
Q10:DHT22 精度是多少?
Adafruit 提供的資料約為:
Temperature
±0.5°C
Humidity
約 ±2~5% RH
Q11:DHT 可以做高溫警報嗎?
可以。
流程:
DHT
↓
Temperature
↓
Threshold
↓
LED / Buzzer
建議加入:
Hysteresis(補充說明 3)
避免溫度在 Threshold 附近波動造成警報不停切換。
Q12:DHT 可以和 Wi-Fi 同時使用嗎?
可以。
DHT 使用一般 Digital GPIO,
不像原始 ESP32 ADC2 存在 Wi-Fi 共用 ADC Hardware 的問題。
因此很適合製作:
DHT
+
ESP32 Wi-Fi
+
MQTT / Web Server
環境監控系統。
六十七、本章學習重點整理
第一個核心:
DHT11
DHT22
都是:
Digital Temperature + Humidity Sensor
第二個核心:
基本程式:
#include <DHT.h>
DHT dht(
DHT_PIN,
DHT_TYPE
);
初始化:
dht.begin();
第三個核心:
溫度:
dht.readTemperature();
濕度:
dht.readHumidity();
第四個核心:
DHT 是低速 Sensor
所以不要快速重複讀取。
本教材統一:
2 seconds
讀一次。
第五個核心:
每次 Sensor Data 都必須先:
isnan();
檢查。
架構:
Read
↓
Validate
↓
Process
而不是:
Read
↓
直接控制設備
第六個核心:
正式程式優先使用:
millis();
管理:
READ_INTERVAL
而不是整個程式一直:
delay(2000);
第七個核心:
高溫控制最好加入:
Hysteresis(補充說明 4)
例如:
30.0°C
→ Alarm ON
28.5°C
→ Alarm OFF
避免 Alarm 抖動。
六十八、本章總結
在第 8 章中,我們正式開始使用 ESP32 讀取:
數位環境感測器
首先比較:
DHT11
vs
DHT22
DHT11:
成本低
適合教學
0~50°C
20~80% RH
DHT22:
範圍較大
精度較佳
-40~80°C
0~100% RH
接著安裝:
DHT sensor library by Adafruit
+
Adafruit Unified Sensor
並使用:
dht.begin();
dht.readTemperature();
dht.readHumidity();
完成基本 Sensor Reading。
我們也特別學會一個非常重要的工程觀念:
Sensor Reading 不一定永遠成功
所以必須:
Sensor
↓
Read
↓
isnan()
↓
Valid?
├── YES → 使用資料
└── NO → Sensor Error
而 DHT11 / DHT22 都屬於低速 Sensor,
本系列正式程式統一:
2000 ms
讀一次,以兼顧 DHT22 的 0.5 Hz 取樣限制與目前 Adafruit Library 的 2 秒 Minimum Interval 行為。
本章第一個實作完成:
ESP32 數位溫溼度計(補充說明)
架構:
DHT11 / DHT22
↓
ESP32
↓
Temperature
+
Humidity
↓
Sensor Error Check
↓
Serial Monitor
進階則完成:
ESP32 高溫警報器(補充說明)
架構:
DHT Sensor
↓
Temperature
↓
Threshold
+
Hysteresis
↓
ESP32
↓
LED
+
Passive Buzzer
至此,我們已經從:
GPIO
PWM
ADC
Touch
正式進入:
Environmental Sensor
階段。
接下來只要加入:
LCD / OLED
Relay
Wi-Fi
MQTT
Web Server
Database
就可以把這一章的 DHT 溫溼度計逐步擴充成真正完整的: