第11章 Raspberry Pi 感測器入門:DHT11 / DHT22 溫溼度監測

發布日期: |更新日期:
文章主圖:第11章 Raspberry Pi 感測器入門:DHT11 / DHT22 溫溼度監測

前面幾章,我們已經讓 Raspberry Pi 具備:

GPIO Input
+
Digital Output
+
PWM Output

可以做到:

Button
   ↓
Python
   ↓
LED / Buzzer

不過目前 Raspberry Pi 所取得的輸入,大多仍然來自:

人
↓
Push Button

或:

Keyboard
↓
input()

真正的自動控制系統還缺少一個重要能力:

Sensor

也就是:

感測器。

本章開始,Raspberry Pi 將第一次真正取得環境資料:

Environment
    │
    ├── Temperature
    └── Humidity
           ↓
       DHT Sensor
           ↓
     Raspberry Pi
           ↓
         Python

這代表系統正式進入:

Sense → Decide → Act

也就是:

感知
 ↓
判斷
 ↓
動作

的完整自動控制架構。

1. Sensor 是什麼?

Sensor:

感測器

是一種將現實世界物理量轉換成電氣或數位資料的裝置。

例如:

Temperature Sensor
→ 溫度

Humidity Sensor
→ 濕度

Light Sensor
→ 光線

Pressure Sensor
→ 壓力

Motion Sensor
→ 人體移動

Distance Sensor
→ 距離

Raspberry Pi 再透過 GPIO、I²C、SPI、UART 等介面取得這些資訊。

2. Analog Sensor 與 Digital Sensor

Sensor 可以先簡單分成:

Sensor
│
├── Analog
└── Digital

Analog Sensor

輸出連續電壓,例如:

0.4V
1.2V
2.6V

需要 ADC:

Analog Sensor
     ↓
ADC
     ↓
Raspberry Pi

因為 Raspberry Pi 40-pin Header 沒有 Arduino UNO 式的一般用途 Analog Input。

Digital Sensor

Sensor 本身已經完成:

Sensing
+
Analog Processing
+
ADC
+
Digital Encoding

然後直接輸出數位資料。

DHT11 / DHT22 就屬於這一類。

3. DHT11 / DHT22 是什麼?

DHT11 與 DHT22 是很常見的低成本:

Temperature + Humidity Sensor

內部包含:

  • Humidity sensing element
  • Temperature sensing element
  • 基本 A/D conversion
  • Digital communication logic

因此 Raspberry Pi 不需要自己做 ADC,就能讀取溫度與相對濕度。Adafruit 將 DHT 系列定位為基本、速度較慢,但很適合初學與簡單資料記錄的數位溫溼度感測器。

4. DHT11 和 DHT22 外觀很像

兩者通常都是帶孔塑膠外殼。

常見:

DHT11
→ 藍色

DHT22
→ 白色

但不要只靠顏色辨識。

真正應該確認:

Part Number
+
Module Label
+
Datasheet

5. DHT11 規格

Adafruit 目前整理的 DHT11 典型能力包括:

  • 工作電源約 3~5V
  • 濕度範圍約 20~80% RH
  • 濕度精度約 ±5%
  • 溫度範圍約 0~50°C
  • 溫度精度約 ±2°C
  • 最快約每秒讀取一次。

所以 DHT11 的定位比較偏:

低成本入門。

6. DHT22 規格

DHT22 / AM2302 的能力較高:

  • 工作電源約 3~5V
  • 濕度範圍約 0~100% RH
  • 濕度精度約 2~5%
  • 溫度範圍約 -40~80°C
  • 溫度精度約 ±0.5°C
  • 最快大約每 2 秒讀取一次。

7. DHT11 與 DHT22 比較

DHT11 與 DHT22 規格比較
項目 DHT11 DHT22
成本 較低 較高
溫度範圍 約 0~50°C 約 -40~80°C
溫度精度 約 ±2°C 約 ±0.5°C
濕度範圍 約 20~80% 約 0~100%
濕度精度 約 ±5% 約 2~5%
最快取樣 約 1 秒一次 約 2 秒一次
適合 基礎教學 較好的環境監測

官方教學也明確指出 DHT22 的量測範圍與精度優於 DHT11,但兩者都屬於速度較慢的基本 Sensor。

8. 本系列比較建議使用哪一個?

如果只是第一次學 Sensor:

DHT11

就可以。

如果希望後面的:

  • IoT
  • SQLite
  • MQTT
  • Web Dashboard

使用比較合理的環境資料,本系列更推薦:

DHT22

因為:

Range 更大
+
Accuracy 較好

9. DHT 是高精度工業 Sensor 嗎?

不是。

DHT11 / DHT22 比較適合:

  • 學習
  • Maker Project
  • 家庭環境監測
  • 基本資料記錄

如果是:

  • 校正設備
  • 工業量測
  • 醫療
  • 高精度控制

應選擇更適合的 Sensor。

Adafruit 目前甚至明確把 DHT11 / DHT22 稱為較基本、較慢的裝置,並在目前 Python Package 文件中建議有更高需求時評估較新的感測器。

10. DHT 有兩種常見外型

市面常看到:

4-pin Raw Sensor

以及:

3-pin Module

兩者不能完全當成相同 PCB 直接照搬接線。

11. 4-pin DHT Raw Sensor

感測器正面朝向自己時,一般腳位排列為:

Pin 1
VCC

Pin 2
DATA

Pin 3
NC

Pin 4
GND

Adafruit 的 DHT 接線文件也是:

  1. Power
  2. Data
  3. 不接
  4. Ground。

12. 3-pin DHT Module

市售模組常把 Raw Sensor 裝在一片 PCB 上。

可能只剩:

VCC
DATA
GND

而 PCB 上可能已經包含:

Pull-up Resistor

有些甚至還有:

  • LED
  • Capacitor
  • Protection Components

但是:

不能假設所有三腳模組內部完全一樣。

要查看:

  • 模組絲印
  • PCB
  • 商品規格
  • Schematic

13. VCC、DATA、GND 是什麼?

VCC

Sensor Power。

DATA

DHT 數位資料線。

GND

Ground Reference。

基本架構:

Raspberry Pi
│
├── 3.3V ───── DHT VCC
├── GPIO4 ──── DHT DATA
└── GND ────── DHT GND

14. Raspberry Pi 最重要的電壓安全

Raspberry Pi 一般 GPIO 使用:

3.3V Logic

官方 GPIO 文件說明 Output HIGH 會嘗試驅動到 3.3V Rail。

所以 DATA Signal 必須保持:

3.3V-safe

不要直接把:

5V Digital Signal

送進 Raspberry Pi GPIO。

15. DHT Sensor 可以用 3.3V 嗎?

DHT11 與 DHT22 官方教學資料列出的工作電源大致為:

3~5V

因此教學電路可以優先使用 Raspberry Pi:

3.3V

供電。

這樣 DATA Pull-up 也能直接以:

3.3V

作為邏輯 HIGH。

16. 為什麼本系列優先使用 3.3V?

因為 Raspberry Pi GPIO 是 3.3V Logic。

所以本章的 Raw DHT Sensor 採:

VCC
→ 3.3V

DATA Pull-up
→ 3.3V

這樣整個 Sensor Logic Domain 都維持:

3.3V。

17. 網路文章為什麼有人把 DHT VCC 接 5V?

DHT Sensor 本體的確通常能在 5V Power 下工作,而 Adafruit 一些通用 DHT 教學也提到某些環境下 5V 供電可能較穩定;不過 DATA Pull-up 仍應維持對 3.3V Logic 安全。

對 Raspberry Pi 初學者來說,最單純且安全的方案仍是:

先使用 3.3V。

18. 三腳 Module 更要小心 5V

某些 Module 的:

DATA Pull-up Resistor

可能直接拉到:

VCC

如果你給 Module:

5V

DATA HIGH 就可能與 Raspberry Pi 3.3V GPIO 不相容。

所以不知道 Module Schematic 時:

不要直接假設 VCC=5V 一定安全。

19. DATA 為什麼需要 Pull-up?

DHT DATA Line 需要 Pull-up,讓 Bus 在沒有被主動拉低時保持明確 HIGH。

Adafruit CircuitPython DHT 文件明確指出 DHT11 與 DHT22 的 Data Signal 都需要 Pull Resistor。

概念:

3.3V
 │
Pull-up
 │
 ├──── DATA
 │
DHT

20. Pull-up 電阻使用多少?

Adafruit CircuitPython DHT 文件目前建議依 Datasheet 選擇,並指出約:

1kΩ ~ 5kΩ

的範圍。

本系列 Raw Sensor 實驗使用很常見的:

4.7kΩ

因為它位於這個建議範圍內。

21. 為什麼有些 DHT 教學使用 10kΩ?

不同製造商與 Module 設計可能使用不同 Pull-up 值,Adafruit 的另一份一般 DHT 接線教學也示範過 10kΩ Pull-up。

因此真正工程做法應該是:

先看 Datasheet
+
模組電路

而不是認為世界上只有一個固定 Resistance。

本系列為 Raw DHT11 / DHT22 統一採:

4.7kΩ

方便教學。

22. 3-pin Module 還要加 4.7kΩ 嗎?

如果 Module 已經內建:

Pull-up Resistor

通常不需要再額外增加。

如果不確定:

  1. 查看 PCB 上是否有 Resistor。
  2. 查看 Module Datasheet。
  3. 查看 Schematic。
  4. 用 Multimeter 分析。

不要盲目一直疊加 Pull-up。

23. 本章使用 GPIO4

DHT DATA 使用:

BCM GPIO4
=
Physical Pin 7

原因:

  • 容易辨識
  • 不占用 I²C GPIO2 / GPIO3
  • 不占用 SPI0
  • 很適合單線 Sensor Lab

Python Blinka 寫法:

board.D4

表示 BCM GPIO4。

24. 4-pin DHT22 接線

本章推薦:

Raspberry Pi 5              DHT22

3.3V / Pin 1 ────────────── VCC / Pin 1

                    ┌─4.7kΩ─ 3.3V
                    │
GPIO4 / Pin 7 ──────┴────── DATA / Pin 2

                             Pin 3
                             NC

GND / Pin 6 ─────────────── GND / Pin 4

25. DHT11 接線相同嗎?

一般 Raw DHT11 與 DHT22 Pinout 相同:

1 VCC
2 DATA
3 NC
4 GND

Adafruit 目前也將兩者描述為相同 Pinout。

因此硬體可以相同。

程式只需要改:

DHT22

成:

DHT11

26. 接線前仍然先關機

執行:

sudo poweroff

然後:

拔除 USB-C
    ↓
確認 DHT 方向
    ↓
接 VCC
    ↓
接 DATA
    ↓
接 Pull-up
    ↓
接 GND
    ↓
重新確認
    ↓
Power On

不要拿著 DHT 在通電中的 40-pin Header 上試位置。

27. 接反 VCC / GND 可能損壞 Sensor

DHT 外觀看起來簡單,但:

VCC
GND

接反並不是合理測試方法。

所以在插線前:

先確認 Sensor 正面方向與 Pin 1。

尤其三腳 Module 的 VCC/GND 排列不是所有品牌都相同。

28. 本章 Python Library

本章使用:

Adafruit CircuitPython DHT

目前 PyPI 的 Adafruit CircuitPython DHT 最新版本為 4.0.12,發布於 2026 年 4 月 23 日,支援 DHT11 與 DHT22。

Linux Raspberry Pi 上透過:

Regular Python
+
Adafruit Blinka
+
CircuitPython Driver

存取 Sensor。

29. Blinka 是什麼?

Blinka 是讓一般 Linux Python 可以使用 CircuitPython Hardware API 的 Compatibility Layer。

例如程式可以寫:

import board

以及:

board.D4

在 Raspberry Pi 上操作實際 GPIO。

Adafruit 目前明確說明 Blinka 支援包括 Raspberry Pi 5 在內的 Raspberry Pi 系列。

30. 不使用舊 Adafruit_DHT Library

搜尋老文章時可能看到:

import Adafruit_DHT

那是很舊的 Python DHT Library 世代。

本系列使用目前維護中的:

import adafruit_dht

也就是:

Adafruit CircuitPython DHT

目前 PyPI 版本仍持續更新至 2026 年。

31. Raspberry Pi OS 要使用 Virtual Environment

從 Raspberry Pi OS Bookworm 開始,Raspberry Pi 官方要求第三方 pip Package 使用:

Python Virtual Environment

避免直接修改 System Python;作業系統提供的 Package 則優先使用 APT。

所以本章不使用:

sudo pip install ...

32. 建立 Chapter 11 Project

cd ~

建立:

mkdir -p raspberrypi-course/chapter11

進入:

cd raspberrypi-course/chapter11

33. 安裝必要 System Package

先:

sudo apt update

安裝:

sudo apt install -y \
  python3-venv \
  python3-pip \
  libgpiod-dev \
  python3-libgpiod

Adafruit 的目前 Raspberry Pi Blinka 安裝文件列出 libgpiod-dev 與 python3-libgpiod 等 Linux GPIO Dependency;Bookworm 之後則建議在 Virtual Environment 內安裝 Python Module。

34. 建立 .venv

python3 -m venv \
  .venv \
  --system-site-packages

使用 --system-site-packages 可以讓 Virtual Environment 同時看到部分由 APT 安裝的 System Python Package,這也是 Raspberry Pi 與 Adafruit 在硬體 Python Library 情境中提供的做法。

35. 啟動 .venv

source .venv/bin/activate

看到:

(.venv)

代表已進入 Virtual Environment。

確認:

which python

應該指向:

chapter11/.venv/bin/python

36. 安裝 Blinka 與 DHT Library

在:

(.venv)

裡執行:

python -m pip install \
  --upgrade \
  adafruit-blinka \
  adafruit-circuitpython-dht

Adafruit CircuitPython DHT 官方文件支援在 Raspberry Pi 這類 GNU/Linux 系統透過 PyPI 與 Virtual Environment 安裝。

37. 確認 Library

執行:

python -c \
"import board, adafruit_dht; print('DHT library OK')"

如果得到:

DHT library OK

代表:

board
+
adafruit_dht

至少可以正常 Import。

38. 第一支 DHT22 程式

建立:

nano dht22_test.py

內容:

import time

import adafruit_dht
import board


dht = adafruit_dht.DHT22(
    board.D4,
    use_pulseio=False
)


try:
    while True:
        try:
            temperature = dht.temperature
            humidity = dht.humidity

            print(
                f"Temperature: "
                f"{temperature:.1f} C"
            )

            print(
                f"Humidity: "
                f"{humidity:.1f} %"
            )

            print("-" * 30)

        except RuntimeError as error:
            print(
                "DHT read failed:",
                error
            )

        time.sleep(2)

except KeyboardInterrupt:
    print(
        "\nProgram stopped."
    )

finally:
    dht.exit()

39. 為什麼 Raspberry Pi 使用 use_pulseio=False?

Adafruit DHT 的目前官方 Example 特別指出,在 Raspberry Pi 這類 Linux Single Board Computer 上,可以使用:

use_pulseio=False

避免使用 CircuitPython pulseio 路徑。

因此本系列 Raspberry Pi 5 範例明確使用:

DHT22(
    board.D4,
    use_pulseio=False
)

40. 執行 DHT22 程式

確認:

(.venv)

仍然存在。

執行:

python dht22_test.py

可能看到:

Temperature: 27.4 C
Humidity: 63.2 %
------------------------------
Temperature: 27.5 C
Humidity: 63.1 %
------------------------------

這就是 Raspberry Pi 第一個真正 Sensor Reading。

41. 使用 DHT11 時只改一行

把:

dht = adafruit_dht.DHT22(
    board.D4,
    use_pulseio=False
)

改成:

dht = adafruit_dht.DHT11(
    board.D4,
    use_pulseio=False
)

Adafruit 官方文件也是以 DHT11 與 DHT22 兩個 Class 分別建立 Sensor Object。

42. dht.temperature 是什麼?

temperature = dht.temperature

取得:

Temperature

單位:

°C

Adafruit DHT API 的基本使用方式就是讀取 temperature Property。

43. dht.humidity 是什麼?

humidity = dht.humidity

取得:

Relative Humidity

一般表示成:

%

例如:

65%

代表:

相對濕度約 65%。

44. 為什麼每 2 秒才讀一次?

DHT22 本身最多大約:

0.5Hz

也就是約 2 秒一次。

而目前 Adafruit CircuitPython DHT Package 也明確建議發生讀取問題時至少等待 2 秒後再 Retry;短時間再次存取時 Library 可能回傳 Cache 值。

因此本系列統一:

time.sleep(2)

對 DHT11 / DHT22 都比較簡單。

45. 不要每 10ms 狂讀 DHT

例如:

while True:
    temperature = dht.temperature

沒有 Delay。

這不是好的 DHT 使用方式。

DHT 本來就是:

Low Sampling Rate Sensor。

如果需要:

  • 10Hz
  • 100Hz
  • Fast Control Loop

DHT11 / DHT22 就不是合適選擇。

46. DHT 偶爾讀取失敗正常嗎?

是。

Adafruit 官方 DHT Guide 明確指出,因為訊號受 Noise 或 Timing 影響,偶爾可能發生讀取 Exception;正確程式設計應:

Catch Error
↓
Retry Later

而不是第一次失敗就整個程式退出。

47. RuntimeError

例如:

except RuntimeError as error:

處理:

Sensor Read Failure

可能訊息包含:

Checksum did not validate

或:

A full buffer was not returned

這類讀取錯誤不一定代表 Sensor 已經壞掉。

48. Retry 的正確觀念

比較好的:

Read
 ↓
Success?
 ├─ Yes → Process Data
 └─ No  → Wait → Retry

而不是:

Read Fail
 ↓
Program Crash

IoT Program 尤其需要這種容錯思維。

49. 更完整的 Retry Function

可以寫:

import time


def read_dht(
    sensor,
    retries=3,
    delay=2
):
    for attempt in range(
        1,
        retries + 1
    ):
        try:
            temperature = (
                sensor.temperature
            )

            humidity = (
                sensor.humidity
            )

            return (
                temperature,
                humidity
            )

        except RuntimeError as error:
            print(
                f"Read attempt "
                f"{attempt} failed: "
                f"{error}"
            )

            time.sleep(delay)

    return None

50. 使用 Retry Function

result = read_dht(dht)

if result is None:
    print(
        "Sensor read failed."
    )
else:
    temperature, humidity = (
        result
    )

    print(
        temperature,
        humidity
    )

這樣 Sensor Driver 和應用邏輯就開始分離。

51. 不要把所有 Exception 都當 RuntimeError 忽略

DHT Timing Error 可以 Retry。

但是如果出現:

SyntaxError
ModuleNotFoundError
Permission Error
Wrong Library

不能只:

except Exception:
    pass

把所有錯誤吃掉。

否則真正問題會被隱藏。

52. 對未知 Exception 應該讓程式顯示

例如:

except RuntimeError as error:
    print(
        "Temporary DHT error:",
        error
    )

except Exception:
    dht.exit()
    raise

這和 Adafruit 官方 DHT Example 的處理方向一致:預期中的 DHT RuntimeError Retry,其他 Exception 則清理 Sensor 後重新拋出。

53. 溫度轉 Fahrenheit

如果需要 Fahrenheit:

temperature_f = (
    temperature * 9 / 5
    + 32
)

例如:

25°C
=
77°F

Adafruit 官方 DHT Example 也同時示範 Celsius 與 Fahrenheit。

本系列主要使用:

°C

因為台灣一般環境監測使用攝氏比較自然。

54. 建立漂亮的 Terminal 監測畫面

print(
    f"Temperature : "
    f"{temperature:.1f} °C"
)

print(
    f"Humidity    : "
    f"{humidity:.1f} %RH"
)

輸出:

Temperature : 27.8 °C
Humidity    : 65.3 %RH

55. 加入時間

Python:

from datetime import datetime

然後:

now = datetime.now()

輸出:

print(
    now.strftime(
        "%Y-%m-%d %H:%M:%S"
    )
)

就能得到:

2026-08-17 23:10:00

之後第 19 章存 SQLite 時,Timestamp 會非常重要。

56. 即時 Monitor 完整版

import time
from datetime import datetime

import adafruit_dht
import board


dht = adafruit_dht.DHT22(
    board.D4,
    use_pulseio=False
)


try:
    while True:
        try:
            temperature = dht.temperature
            humidity = dht.humidity

            now = datetime.now()

            print(
                now.strftime(
                    "%Y-%m-%d %H:%M:%S"
                )
            )

            print(
                f"Temperature : "
                f"{temperature:.1f} °C"
            )

            print(
                f"Humidity    : "
                f"{humidity:.1f} %RH"
            )

            print(
                "-" * 35
            )

        except RuntimeError as error:
            print(
                "Temporary read error:",
                error
            )

        time.sleep(2)

except KeyboardInterrupt:
    print(
        "\nMonitor stopped."
    )

finally:
    dht.exit()

57. 如何判斷 Normal / Warning / Danger?

例如定義:

Temperature < 30°C
→ Normal

30~34.9°C
→ Warning

>= 35°C
→ Danger

這只是教學 Threshold。

實際設備應依:

  • 使用環境
  • 設備規格
  • 安全要求

制定。

58. Status Function

def get_status(
    temperature
):
    if temperature >= 35:
        return "DANGER"

    if temperature >= 30:
        return "WARNING"

    return "NORMAL"

接著:

status = get_status(
    temperature
)

59. 加入濕度狀態

也可以:

def get_humidity_status(
    humidity
):
    if humidity >= 80:
        return "HIGH"

    if humidity <= 30:
        return "LOW"

    return "NORMAL"

注意這些值是:

教學範例 Threshold

不是醫療、工業或建築環控的通用安全標準。

60. 完整文字狀態

Temperature : 32.4 °C
Humidity    : 68.5 %RH

Temperature Status:
WARNING

Humidity Status:
NORMAL

到這裡,Sensor 已經完成:

Sense
↓
Decision

下一步是:

Act

61. 加入第 10 章 PWM LED

LED 使用:

GPIO18
=
Physical Pin 12

Sensor:

GPIO4
=
Physical Pin 7

兩者不衝突。

架構:

DHT22
  │
GPIO4
  │
  ▼
Python
  │
  ▼
PWMLED
GPIO18

62. 用 LED 亮度表示溫度狀態

例如:

NORMAL
→ 30%

WARNING
→ 70%

DANGER
→ 100%

程式:

def update_led(
    led,
    status
):
    if status == "DANGER":
        led.value = 1.0

    elif status == "WARNING":
        led.value = 0.7

    else:
        led.value = 0.3

63. 加入 TonalBuzzer

沿用:

GPIO23
=
Physical Pin 16

架構:

DHT22
   ↓
Temperature
   ↓
Python
   ↓
Status
  /    \
LED    Buzzer

64. 警報邏輯

例如:

NORMAL
→ Buzzer OFF

WARNING
→ 短促提示音

DANGER
→ 高音警報

注意實際 Buzzer 電壓與電流仍要符合第 10 章的安全原則。

65. 完整 DHT + PWM LED + Buzzer 程式

import time
from datetime import datetime

import adafruit_dht
import board

from gpiozero import PWMLED
from gpiozero import TonalBuzzer


DHT_PIN = board.D4

LED_PIN = 18
BUZZER_PIN = 23

NORMAL_LED = 0.3
WARNING_LED = 0.7
DANGER_LED = 1.0

READ_INTERVAL = 2


dht = adafruit_dht.DHT22(
    DHT_PIN,
    use_pulseio=False
)

led = PWMLED(
    LED_PIN
)

buzzer = TonalBuzzer(
    BUZZER_PIN
)


def get_status(
    temperature
):
    if temperature >= 35:
        return "DANGER"

    if temperature >= 30:
        return "WARNING"

    return "NORMAL"


def update_outputs(
    status
):
    if status == "DANGER":
        led.value = DANGER_LED

        buzzer.play(
            "A5"
        )

    elif status == "WARNING":
        led.value = WARNING_LED

        buzzer.play(
            "A4"
        )

        time.sleep(0.15)

        buzzer.stop()

    else:
        led.value = NORMAL_LED

        buzzer.stop()


def display_data(
    temperature,
    humidity,
    status
):
    now = datetime.now()

    print(
        now.strftime(
            "%Y-%m-%d %H:%M:%S"
        )
    )

    print(
        f"Temperature : "
        f"{temperature:.1f} °C"
    )

    print(
        f"Humidity    : "
        f"{humidity:.1f} %RH"
    )

    print(
        f"Status      : "
        f"{status}"
    )

    print(
        "-" * 35
    )


try:
    while True:
        try:
            temperature = (
                dht.temperature
            )

            humidity = (
                dht.humidity
            )

            status = get_status(
                temperature
            )

            display_data(
                temperature,
                humidity,
                status
            )

            update_outputs(
                status
            )

        except RuntimeError as error:
            print(
                "Temporary DHT error:",
                error
            )

        time.sleep(
            READ_INTERVAL
        )

except KeyboardInterrupt:
    print(
        "\nMonitor stopped."
    )

finally:
    led.off()
    buzzer.stop()

    led.close()
    buzzer.close()

    dht.exit()

66. 這個完整系統在做什麼?

流程:

DHT22
 │
 ├── Temperature
 └── Humidity
        ↓
      Python
        ↓
  Temperature Status
   /       |       \
Normal  Warning   Danger
  │         │         │
30% LED   70% LED   100% LED
  │         │         │
Silent    A4 Beep    A5 Alarm

這就是完整:

Sensor Monitoring + Alarm System

67. 為什麼 Danger Buzzer 一直響?

程式:

buzzer.play("A5")

會讓 TonalBuzzer 持續播放。

下一次正常/警告狀態才會:

buzzer.stop()

所以 Danger 狀態會維持持續警報。

68. 如果不想 Danger 持續響

可以改成:

buzzer.play(
    "A5"
)

time.sleep(
    0.3
)

buzzer.stop()

這樣每次 Sensor Update 只響一下。

69. Sensor Data Filtering 是什麼?

真實 Sensor 可能看到:

27.4
27.5
27.4
27.7
27.5

小幅變動是正常的。

不要因為:

27.4 → 27.5

就認為 Sensor 壞掉。

後續可以使用:

  • Moving Average
  • Median
  • Hysteresis
  • Range Check

降低 Noise 對控制的影響。

70. 為什麼控制系統需要 Hysteresis?

假設 Threshold:

30°C

Sensor 在:

29.9
30.1
29.9
30.1

變動。

如果直接控制 Fan:

ON
OFF
ON
OFF

就會不斷切換。

比較好的方法:

>= 30°C
→ ON

<= 29°C
→ OFF

建立:

1°C Hysteresis

這會在後面 Relay / Fan 控制章節再次使用。

71. DHT11 / DHT22 適合控制高速設備嗎?

不適合。

因為它們的 Sampling Rate 本身就很低:

DHT11
約 1Hz

DHT22
約 0.5Hz

所以它們適合:

Room Temperature
Humidity Monitoring
Environmental Logging

而不是:

High-speed Control
Real-time Motor Loop

72. DHT 完全讀不到:第一步檢查 Wiring

確認:

VCC
→ 3.3V

DATA
→ GPIO4 / Pin 7

GND
→ GND

DATA Pull-up
→ 3.3V

以及:

Pin 3
→ NC

73. DHT 一直 RuntimeError

先檢查:

  1. VCC 是否穩定。
  2. DATA 是否 GPIO4。
  3. Pull-up 是否存在。
  4. DHT Pin Direction 是否看反。
  5. Breadboard 是否插錯 Row。
  6. Sensor 是否真的 DHT11 / DHT22。
  7. 程式 Class 是否正確。
  8. Read Interval 是否至少約 2 秒。

DHT 本來就偶爾可能讀失敗;但如果完全沒有一次成功讀值,就應優先查 Hardware。

74. ModuleNotFoundError: adafruit_dht

如果:

No module named 'adafruit_dht'

先:

source .venv/bin/activate

再:

python -m pip list

確認 Package 是否真的存在。

75. 確認你現在使用哪個 Python

which python

應該:

.../chapter11/.venv/bin/python

不是:

/usr/bin/python

否則你很可能:

Library 安裝在 venv
程式卻用 System Python

76. 確認 Package

python -m pip show \
  adafruit-circuitpython-dht

應該顯示:

  • Name
  • Version
  • Location

目前 PyPI 的最新 DHT Driver 為 4.0.12。

77. board.D4 找不到怎麼辦?

先測:

python -c \
"import board; print(board.D4)"

如果連:

import board

都失敗,就應先檢查:

Adafruit Blinka

而不是 Sensor。

Adafruit 目前說明 Blinka 支援 Raspberry Pi 5。

78. Blinka 安裝問題

確認:

python -m pip show \
  adafruit-blinka

以及 Linux Dependency:

dpkg -l | grep gpiod

Adafruit Raspberry Pi Blinka Guide 目前依賴 libgpiod-dev 與 python3-libgpiod 等 Linux Package。

79. Raspberry Pi 5 和老版 GPIO 教學不同

Pi 5 使用:

RP1

管理大量外部 Peripheral。

這使一些早期直接針對 BCM283x Hardware 的 Library 或技巧不再適合直接照搬。

Adafruit 目前也特別說明 Pi 5 的 RP1 架構迫使原本某些 GPIO 實作改採新的 Linux GPIO Backend。

80. 為什麼本章使用 CircuitPython Driver 而 GPIO Output 用 GPIO Zero?

因為 Library 的選擇應依:

Device
+
成熟 Driver
+
API

而不是要求整個 Project 所有硬體都只能使用同一套 Library。

本系列:

Button / LED / Buzzer
→ GPIO Zero

DHT Sensor
→ Adafruit CircuitPython DHT

兩者都屬高階 Python Hardware API。

81. 可以把 DHT DATA 接 GPIO18 嗎?

技術上可以選其他合適 GPIO。

但是本章 GPIO18 已經給:

PWM LED

所以不應兩個 Device 同時搶同一 Pin。

本章分配:

第 11 章 GPIO Pin Assignment
功能 BCM GPIO Physical
DHT DATA GPIO4 Pin 7
PWM LED GPIO18 Pin 12
Buzzer GPIO23 Pin 16
3.3V — Pin 1
GND — Pin 6

82. 建立 Pin Assignment Table 的好處

Project 越大,越應該先寫:

Sensor
→ GPIO4

LED
→ GPIO18

Buzzer
→ GPIO23

避免:

GPIO18
同時接 Sensor
又接 LED

造成 Resource Conflict。

83. DHT Sensor 發熱會影響讀值嗎?

Sensor 如果:

  • 靠近 Raspberry Pi SoC
  • 靠近 Active Cooler 排風
  • 靠近 Power Supply
  • 放在密閉熱源旁

量到的溫度可能不代表真正室內環境。

所以環境 Sensor 應該:

遠離主要熱源
+
保持空氣流通

84. 不要把 DHT 貼在 Raspberry Pi 5 CPU 上

如果 Sensor 就在:

BCM2712
Active Cooler
USB-C PSU

旁邊,

你量到的可能更接近:

主機附近微環境溫度

而不是:

室溫

這是 Sensor Installation 的基本觀念。

85. 濕度讀值為什麼變化很慢?

DHT 本身就是:

Slow Sensor

而濕度感測材料也有一定反應時間。

因此:

吹一口氣

之後數值可能需要一些時間變化與恢復。

Adafruit 也明確將 DHT11/DHT22 描述為速度較慢的環境 Sensor。

86. 不要對 Sensor 直接吹很濕的氣體當校正

人體呼氣可以用來觀察:

Humidity 是否會變化

但這不是:

Calibration

真正校正需要:

  • Reference Instrument
  • Known Humidity Environment
  • Calibration Procedure

87. DHT 數值要不要儲存?

這正是後面課程要做的事。

目前:

Sensor
↓
Terminal

後面:

Sensor
↓
SQLite
↓
Historical Data
↓
Chart

再:

MQTT
↓
Remote Monitoring

這就是 IoT 架構逐步形成。

88. 現在已經完成第一個完整 Sensor Loop

DHT
 ↓
Read
 ↓
Validate
 ↓
Display
 ↓
Decision
 ↓
LED / Buzzer
 ↓
Wait 2 sec
 ↓
Repeat

這個 Pattern 後面幾乎所有 Sensor 都會再看到。

89. 本章常用安裝指令

sudo apt update
sudo apt install -y \
  python3-venv \
  python3-pip \
  libgpiod-dev \
  python3-libgpiod
python3 -m venv \
  .venv \
  --system-site-packages
source .venv/bin/activate
python -m pip install \
  --upgrade \
  adafruit-blinka \
  adafruit-circuitpython-dht

Raspberry Pi OS Bookworm 之後使用 venv 安裝 pip Library,是 Raspberry Pi 官方目前建議的套件管理方式。

90. 本章 DHT Python API 速查

DHT Python API 速查表
Python 用途
import board Blinka Board Pin
import adafruit_dht DHT Driver
board.D4 BCM GPIO4
DHT11() 建立 DHT11
DHT22() 建立 DHT22
temperature 取得溫度
humidity 取得濕度
use_pulseio=False Linux SBC 常用模式
exit() 關閉 DHT Resource

Adafruit 的目前 Raspberry Pi / Linux Example 明確示範 DHT22、temperature、humidity、RuntimeError、2 秒 Delay 與 use_pulseio=False。

91. DHT11 / DHT22 快速比較

DHT11
│
├── 便宜
├── 0~50°C
├── ±2°C
├── 20~80% RH
└── 約 1 秒一次


DHT22
│
├── 較準
├── -40~80°C
├── ±0.5°C
├── 0~100% RH
└── 約 2 秒一次

92. 本章硬體安全整理

  1. Raspberry Pi GPIO 是 3.3V Logic。
  2. 不把 5V DATA 直接送進 GPIO。
  3. Raw DHT 本章使用 3.3V Power。
  4. DATA Pull-up 拉到 3.3V。
  5. Raw Sensor 要確認 Pin 1~4。
  6. 3-pin Module 要確認實際 Pinout。
  7. 不假設所有 Module 都內建相同 Pull-up。
  8. 接線前先關機。
  9. 不要反接 VCC / GND。
  10. Sensor 應遠離 Raspberry Pi 主要熱源。

93. 本章軟體安全整理

  1. 使用 Python 3。
  2. Bookworm 之後 pip 使用 venv。
  3. 不使用 sudo pip install 當標準流程。
  4. DHT 使用 adafruit_dht。
  5. Raspberry Pi Linux 使用 use_pulseio=False。
  6. DHT22 至少約每 2 秒讀一次。
  7. RuntimeError 可以 Retry。
  8. 未知 Exception 不要全部忽略。
  9. 程式退出要 dht.exit()。
  10. GPIO Output 同時做 Cleanup。

94. 本章重點整理

完成本章後,應掌握:

  1. Sensor 是將物理世界資訊轉換成電氣/數位資料的裝置。
  2. DHT11 / DHT22 可以同時量 Temperature 與 Humidity。
  3. DHT 是 Digital Sensor,不需要 Raspberry Pi 外接 ADC。
  4. DHT11 成本較低,但量測範圍與精度較有限。
  5. DHT22 溫度與濕度範圍較廣,精度也較高。
  6. DHT11 最快約每秒讀一次。
  7. DHT22 最快約每兩秒讀一次。
  8. Raw DHT 通常有 VCC、DATA、NC、GND 四 Pin。
  9. 3-pin Module 常將 NC 與 Pull-up 電路整合掉。
  10. 不能假設所有 DHT Module Pinout 都相同。
  11. Raspberry Pi GPIO 使用 3.3V Logic。
  12. 本系列 Raw DHT 使用 3.3V Power。
  13. DATA Line 需要 Pull-up。
  14. 本系列使用 4.7kΩ DATA Pull-up。
  15. DHT DATA 使用 GPIO4 / Physical Pin 7。
  16. Pull-up 接到 3.3V。
  17. Unknown 5V DHT Module 應先檢查 DATA Logic。
  18. 現代 Python DHT Library 使用 adafruit_dht。
  19. 目前 Adafruit CircuitPython DHT 仍有持續維護。
  20. Blinka 讓普通 Linux Python 使用 CircuitPython Hardware API。
  21. Adafruit Blinka 支援 Raspberry Pi 5。
  22. Raspberry Pi OS Bookworm 之後 pip Package 應使用 Virtual Environment。
  23. .venv 可以隔離 Project Dependency。
  24. --system-site-packages 可存取部分 APT System Package。
  25. Blinka Raspberry Pi 安裝會使用 libgpiod 相關 Dependency。
  26. board.D4 代表 GPIO4。
  27. adafruit_dht.DHT22() 建立 DHT22 Object。
  28. DHT11 則使用 adafruit_dht.DHT11()。
  29. Linux Raspberry Pi 可使用 use_pulseio=False。
  30. dht.temperature 取得攝氏溫度。
  31. dht.humidity 取得相對濕度。
  32. DHT 偶爾 RuntimeError 並不罕見。
  33. Sensor Program 應該具有 Retry。
  34. RuntimeError 可以捕捉後再次讀取。
  35. 其他未知 Exception 不應全部靜默忽略。
  36. 每兩秒更新一次適合 DHT22。
  37. Terminal 可以做即時 Environment Monitor。
  38. Timestamp 能為之後 Database 做準備。
  39. Sensor Data 可以建立 Normal / Warning / Danger 狀態。
  40. PWM LED 可以表示警報程度。
  41. TonalBuzzer 可以產生高溫聲音警報。
  42. GPIO4、GPIO18、GPIO23 可以分別安排 Sensor、LED、Buzzer。
  43. Project 應建立 Pin Assignment Table。
  44. Sensor 不應太靠近 Raspberry Pi CPU 等熱源。
  45. Sensor 小幅浮動不一定代表故障。
  46. Threshold 附近控制最好考慮 Hysteresis。
  47. DHT 不適合高速 Control Loop。
  48. DHT 適合初學、環境監測與基本 Logging。
  49. 完整 Sensor Program 應該有 Cleanup。
  50. 本章已完成真正的 Sense → Decide → Act 控制系統。

FAQ:Raspberry Pi DHT11 / DHT22 常見問題

Q1:DHT11 和 DHT22 哪個比較適合 Raspberry Pi?

兩個都可以。

如果只是學習:

DHT11

已經足夠。

如果之後要做:

  • MQTT
  • Database
  • Web Environment Monitor

比較推薦:

DHT22

因為它具有較廣量測範圍與較好的精度。

Q2:DHT11 / DHT22 是 Analog Sensor 嗎?

不是一般 Analog Output Sensor。

它內部會輸出 Digital Data,因此 Raspberry Pi 不需要外加 ADC 才能取得溫度與濕度。

Q3:DHT22 可以接 Raspberry Pi 3.3V 嗎?

可以。

DHT11 / DHT22 一般工作範圍約為 3~5V。

本系列為了保持 Raspberry Pi DATA Logic 為 3.3V,Raw Sensor 優先使用:

3.3V

供電。

Q4:可以把 DHT Module 接 5V 嗎?

Sensor 本體可能支援 5V,但未知 Module 的 DATA Pull-up 可能直接連到 VCC。

因此如果 Module 供 5V,有可能讓 DATA HIGH 超過 Raspberry Pi 3.3V Logic。

所以:

先查 Module Schematic。

不要直接假設安全。

Q5:DHT DATA 一定需要 Pull-up 嗎?

對 Raw DHT11 / DHT22 應提供 DATA Pull-up。Adafruit CircuitPython DHT 文件目前也明確要求 Data Line 使用 Pull Resistor。

Q6:Pull-up 要多少 Ω?

本系列使用:

4.7kΩ

Adafruit CircuitPython DHT 文件指出可依 Datasheet 使用約 1kΩ~5kΩ 範圍;其他模組/文件也可能看到不同數值。

Q7:三腳 DHT Module 還需要 Pull-up 嗎?

不一定。

很多 Module 已經內建 Pull-up。

請先查看:

  • PCB
  • Schematic
  • Module Specification

Q8:DHT DATA 接哪個 Raspberry Pi Pin?

本章:

BCM GPIO4
=
Physical Pin 7

程式:

board.D4

Q9:Python 要安裝哪個 DHT Library?

本系列使用:

adafruit-circuitpython-dht

Python Import:

import adafruit_dht

目前 PyPI 版本仍持續維護。

Q10:為什麼不使用 Adafruit_DHT?

Adafruit_DHT 是舊世代 Library。

目前本系列改採維護中的:

Adafruit CircuitPython DHT
+
Blinka

Q11:為什麼需要 Blinka?

因為 CircuitPython Library 原本使用:

board

等 Hardware API。

Blinka 讓 Raspberry Pi OS 的 Regular Python 可以使用這些 API 控制 Raspberry Pi Hardware。

Q12:Blinka 支援 Raspberry Pi 5 嗎?

目前 Adafruit 明確說明 Blinka 支援 Raspberry Pi 5。

Q13:為什麼要用 Python Virtual Environment?

因為 Raspberry Pi OS Bookworm 開始,不建議 pip 直接修改 System Python。

Raspberry Pi 官方建議:

APT
→ System Packages

venv + pip
→ Project Packages

Q14:為什麼出現 externally-managed-environment?

代表你正在嘗試用 pip 修改 Raspberry Pi OS 管理的 System Python。

正確做法是:

python3 -m venv .venv
source .venv/bin/activate

再用 pip 安裝 Project Package。

Q15:為什麼 Raspberry Pi 範例使用 use_pulseio=False?

Adafruit 的目前 DHT Linux Example 說明,Linux Single Board Computer,例如 Raspberry Pi,可能需要:

use_pulseio=False

模式。

Q16:DHT 為什麼偶爾讀取錯誤?

DHT 的 Timing、Noise 或訊號品質可能讓某次讀取失敗。

官方教學也說明這類 Sensor 偶爾讀不到並不罕見,因此應用程式應 Catch RuntimeError 並 Retry。

Q17:多久讀一次 DHT22?

建議至少約:

2 秒

DHT22 本身最快約 0.5Hz,而目前 Adafruit Library 也建議 Retry 時等待至少兩秒。

Q18:DHT11 可以每兩秒讀一次嗎?

可以。

DHT11 最快約每秒一次,因此每兩秒讀一次屬於更保守的更新速度。

Q19:可以用 DHT22 控制風扇嗎?

可以把 DHT22 當:

Temperature Input

但風扇本身不應直接由 GPIO 供電。

應使用:

DHT22
↓
Python
↓
GPIO
↓
MOSFET / Driver
↓
Fan

並依 Fan 電壓與電流設計。

Q20:DHT11 / DHT22 適合長期產品嗎?

可以用於低成本非關鍵環境監測,但它們本身屬於基本、速度較慢的 Sensor,Adafruit 目前也建議有更高可靠度需求時評估較新的感測器方案。

結語

完成第 11 章後,我們已經跨過 Raspberry Pi 課程另一個重要里程碑。

以前:

Human
  ↓
Button
  ↓
Raspberry Pi

現在:

Physical Environment
       ↓
    DHT22
       ↓
Temperature + Humidity
       ↓
Raspberry Pi
       ↓
     Python
       ↓
    Decision
       ↓
 LED + Buzzer

也就是:

Raspberry Pi 已經真正開始「感知環境」。

目前我們已經具備:

GPIO Input
+
Digital Output
+
PWM
+
Sensor

並且完成:

Sense
 ↓
Validate
 ↓
Retry
 ↓
Decision
 ↓
Alarm

這已經是一個真正 IoT Device 的核心。

不過 DHT 的通訊方式屬於:

單一 Sensor
+
單一 Data Line

下一章,我們會進入 Raspberry Pi 最重要的標準感測器 Bus 之一:

I²C

I²C 最大的差異是:

一組 SDA / SCL
        ↓
可以連接多個不同 Address Device

接下來我們會使用:

  • raspi-config
  • /dev/i2c-*
  • i2cdetect
  • I²C Address
  • LCD1602 I²C

正式學習 Raspberry Pi 標準周邊通訊。

下一章

第 12 章 Raspberry Pi I²C 通訊完整教學:I²C Scanner 與 LCD1602 顯示器

下一章將完整學習:

  • I²C 是什麼
  • Master / Controller
  • Peripheral / Device
  • SDA
  • SCL
  • GPIO2 / Physical Pin 3
  • GPIO3 / Physical Pin 5
  • 3.3V Logic
  • Open-drain
  • Pull-up
  • I²C Address
  • 7-bit Address
  • 多設備共用 Bus
  • Raspberry Pi 5 I²C
  • 開啟 I²C
  • raspi-config
  • /dev/i2c-1
  • i2c-tools
  • i2cdetect
  • I²C Scanner
  • 找出裝置 Address
  • LCD1602
  • PCF8574 I²C Backpack
  • LCD Address 0x27 / 0x3F 的判斷
  • LCD 5V 與 Raspberry Pi 3.3V Logic 安全
  • I²C Level Shifter
  • Python LCD Library
  • 顯示 Hello Raspberry Pi
  • 顯示 DHT22 Temperature
  • 顯示 DHT22 Humidity
  • Terminal + LCD 雙重顯示
  • I²C Device Not Found 排查
  • Remote I/O error
  • Address 錯誤
  • SDA / SCL 接反
  • I²C Bus Conflict
  • 建立 Raspberry Pi 第一個 Sensor + Display 系統

完成第 12 章後,就可以把本章:

DHT22
↓
Temperature / Humidity

直接顯示在:

LCD1602

讓 Raspberry Pi 從只有 Terminal 的 Sensor Monitor,進一步變成真正具有獨立顯示介面的環境監測設備。

下一步學習

不要停在這一篇,接著把內容做成自己的實作

目前主題:ESP32 / IoT。從完整學習路線、免費資源、會員下載,再接到實作所需材料。

同系列:Raspberry-Pi |  已是會員?直接前往 Getfile
相關資源與會員文章下載
文章可免費閱讀;下載完整 DOCX 或 PDF 需登入免費基本會員。
會員免費下載 DOCX 會員免費 PDF/列印

← 回文章列表