National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 09

溫溼度感測與 OLED 顯示

DHT22 讀溫溼度,顯示在 OLED 螢幕
Interaction 25 minute(s)

Learning Objectives

  • 用 dht.DHT22 讀取溫度與溼度,並說明為什麼兩次量測要間隔 2 秒
  • 用 try/except 處理感測器讀取失敗,讓程式不會停掉
  • 用 ssd1306 在 OLED 上畫文字、線與方框,並理解 show() 的作用
  • 用字串格式化把數值整理成固定格式,做出顯示溫溼度的小氣象站

讓開發板感覺環境,也讓人看得到結果

前幾課的輸入是按鈕與可變電阻,輸出是 LED 與燈條。這一課把兩個常用的模組接在一起:

  • DHT22:溫溼度感測器,告訴程式現在幾度、溼度多少
  • OLED 顯示器:128 × 64 像素的小螢幕,不用接電腦也能看到數值

這一課要回答:

  1. 怎麼從 DHT22 讀到溫度與溼度?讀不到的時候怎麼辦?
  2. 怎麼在 OLED 上顯示文字與圖形?
  3. 怎麼把數字整理成好讀的格式,做成一個小氣象站?

DHT22 與 DHT11

DHT 系列感測器只用一條資料線和開發板溝通(另外兩條是電源與 GND),用的是它自己的序列協定。 MicroPython 的 dht 模組已經幫你處理好協定的細節,而且可以接在任何一支 GPIO 上。 兩種常見型號的差別(依 Adafruit 的說明文件):

DHT11 DHT22(AM2302)
溫度範圍 0~50°C -40~80°C
溫度準確度 ±2°C ±0.5°C
溼度範圍 20~80% 0~100%
最快量測頻率 每秒 1 次 每 2 秒 1 次
讀值 整數 有一位小數

兩種的用法一樣,只差在建立物件時寫 dht.DHT11 或 dht.DHT22。

逐步看:每 2 秒讀一次溫溼度

讀取分成兩步:先 measure() 請感測器量一次,再用 temperature()、humidity() 取出這次量到的值。 上方 DHT22 的讀值會隨時間慢慢上升(模擬房間變暖),注意每次 sleep(2) 之後讀到的數字。

讀不到的時候

感測器沒接好、線太長、電源不穩,measure() 都可能失敗,這時 MicroPython 會發生 OSError (常見的訊息是 ETIMEDOUT,表示等不到感測器的回應)。如果沒有處理,整個程式會停下來,螢幕也不再更新。

放在牆上的氣象站不應該因為一次讀取失敗就停擺,所以把讀取包在 try/except 裡:

try:
    sensor.measure()
    t = sensor.temperature()
except OSError:
    t = None          # 這一次讀不到,下一輪再試

OLED:先畫,再 show()

常見的 0.96 吋 OLED 用 SSD1306 控制晶片,透過 I2C 匯流排和開發板連接,只要兩條訊號線(下一課會詳細介紹 I2C):

OLED   ESP32
VCC ── 3.3V
GND ── GND
SCL ── GPIO18
SDA ── GPIO19

MicroPython 的 ESP32 硬體 I2C 第 0 組預設就是 SCL=GPIO18、SDA=GPIO19,也可以指定其他腳位。 這類 OLED 的 I2C 位址通常是 0x3C(十進位 60)。

ssd1306 模組的畫法和第 08 課的燈條很像:fill()、text()、rect() 這些函式只是畫在開發板記憶體裡的畫布上, show() 才把整張畫布送到螢幕。內建字型每個字 8 × 8 像素,所以一行最多 16 個字、最多 8 行; 這套字型只有英文字母、數字與常用符號,不能直接顯示中文,所以螢幕上的單位寫成 C。

逐步看:在 OLED 上畫字與方框

第 8~13 行一直在畫,但上方的螢幕要等第 14 行 show() 之後才一次出現全部內容。座標從左上角 (0, 0) 開始,x 往右、y 往下。

把數字整理成固定格式

螢幕一行只有 16 個字,數字的位數一變,整行就會跳來跳去。字串的 format() 可以固定小數位數:

寫法 結果
"{:.1f}".format(26.43) 26.4
"{:.1f}".format(26) 26.0
"{:5.1f}".format(7.26) 7.3(總寬 5,前面補空白)
"Temp: {:.1f} C".format(26.43) Temp: 26.4 C

下一個範例把前面兩件事組起來:每 2 秒讀一次、讀到就用固定格式顯示,讀不到就顯示 Sensor error。

逐步看:溫溼度小氣象站

每一輪都是「讀取 → 組字串 → 清畫面 → 畫字 → show()」。看上方:螢幕的數字跟著 DHT22 的讀值更新。

互動練習:做自己的氣象站畫面

起始程式每 2 秒讀一次 DHT22,但螢幕上只有溫度。依序完成任務:

  1. 先直接執行,看螢幕顯示溫度。
  2. 在第二行(y=16)加上溼度,格式是 Hum: 60.0 %。
  3. 溫度超過 30°C 時,在第三行(y=32)顯示 HOT!。寫好之後,把「輸入設定」裡 DHT22 的結束溫度拖到 30°C 以上再執行。
  4. 回答一個問題。

小測驗:感測器

1.

執行 sensor.measure() 之後連續呼叫兩次 sensor.temperature(),兩次的結果是?

2.

DHT22 的資料線沒接好,measure() 會怎樣?

3.

下面的程式會印出什麼?

t = 26.46
print("Temp: {:.1f} C".format(t))
第 1 次作答

小測驗:OLED

1.

程式執行了 oled.fill(0) 和 oled.text("Hi", 0, 0),但螢幕沒有出現 Hi,最可能少了哪一行?

2.

內建字型每個字 8 × 8 像素,128 × 64 的 OLED 一行最多幾個字、最多幾行?

3.

下面的程式會印出什麼?

lines = ["Temp: 26.4 C", "Hum:  60.0 %", "HOT!"]
for i, s in enumerate(lines):
    if len(s) <= 16:
        print(i * 16, s)
第 1 次作答

重點整理

  • sensor = dht.DHT22(Pin(4));先 measure(),再 temperature()、humidity() 取值。DHT22 最快每 2 秒量一次。
  • 讀取失敗會發生 OSError,用 try/except 接住,下一輪再試,程式才不會停。
  • OLED(SSD1306)走 I2C:SSD1306_I2C(128, 64, I2C(0, scl=Pin(18), sda=Pin(19))),位址通常是 0x3C。
  • fill、text、hline、rect、fill_rect 畫在記憶體裡,show() 才更新螢幕;字 8 × 8 像素,一行 16 字、8 行,不能直接顯示中文。
  • "{:.1f}".format(數值) 固定小數位數,螢幕上的數字才不會跳動。

下一課深入 I2C:一條匯流排怎麼同時接好幾個裝置,以及怎麼直接讀感測器的暫存器。

這一課完成了!
Next lesson:I2C 匯流排與感測器
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。