Learning Objectives
- 說明 16x2 字元 LCD 與 I2C 轉接板的接法與位址
- 用 RPLCD 在指定的列與行寫字、清除畫面、開關背光
- 用 f-string 的寬度與對齊,讓數值變短時不會殘留舊字
- 把 I2C 溫度感測器的讀值顯示在 LCD 上,並說明 LCD 與 OLED 的差別
不接螢幕,也看得到數值
到目前為止,感測器的讀值都用 print() 印在終端機上。可是作品做好後,樹莓派通常不會接螢幕、也不會一直開著 SSH,
這時候一塊小小的顯示器就很有用:溫度、IP 位址、目前的狀態,一眼就看得到。
這一課用最常見的 16x2 字元 LCD(俗稱 LCD1602):兩行、每行 16 個字。要回答的問題是:
- 它怎麼接到樹莓派?上一課的 I2C 怎麼派上用場?
- 怎麼在第二行的第 5 格寫字?
- 數字從 100 變成 99 時,為什麼畫面會顯示 990?
LCD1602 與 I2C 轉接板
LCD1602 的每一格是 5×8 個點組成的字,由一顆 HD44780 相容的控制晶片負責畫。這顆晶片內建的字形 主要是英文字母、數字、符號(常見的版本還有日文片假名),沒有中文字,所以 LCD 上的文字要用英文與數字。
LCD 原本要接十幾條線。市面上的模組背面通常焊了一塊 I2C 轉接板(使用 PCF8574 晶片),把它變成上一課的 I2C 裝置:
只要接 VCC、GND、SDA(GPIO2)、SCL(GPIO3)四條線。轉接板的位址常見是 0x27,使用 PCF8574A 的版本是 0x3F,
接好後用 sudo i2cdetect -y 1 確認。轉接板上通常還有一顆可變電阻調整對比,畫面一片空白或整排方塊時先轉轉看。
在 Python 裡用 RPLCD 套件:
from RPLCD.i2c import CharLCD
lcd = CharLCD(i2c_expander='PCF8574', address=0x27, port=1, cols=16, rows=2)
cols與rows一定要寫:RPLCD 預設是 20x4 的顯示器,用在 16x2 上換行的位置會不對。
| 動作 | 寫法 |
|---|---|
| 從游標位置往右寫字 | lcd.write_string("Hello") |
| 移動游標到第 r 列第 c 行(從 0 數起) | lcd.cursor_pos = (r, c) |
| 清除畫面、游標回到 (0, 0) | lcd.clear() |
| 開關背光 | lcd.backlight_enabled = False |
逐步看:在 LCD 上寫兩行字
看電路上的 LCD:每次 write_string 之後,字會出現在游標所在的位置。cursor_pos 是(列, 行),第一個數字選第幾行字。
為什麼 99 會變成 990
LCD 不會自己清除舊的字:write_string 只會覆蓋它寫到的格子,沒寫到的格子維持原樣。
先寫「Count: 100」再從頭寫「Count: 99」,第 10 格的「0」沒有被蓋掉,畫面就變成「Count: 990」。
有兩種解法:
- 每次都
lcd.clear()再重寫。簡單,但畫面會閃一下,而且清除比較花時間。 - 固定寬度:每次寫的字數一樣多,不夠的補空白。f-string 可以指定寬度與對齊:
| 寫法 | 結果(用 · 表示空白) | 說明 |
|---|---|---|
f"{99:<4}" |
99·· |
4 格寬、靠左,右邊補空白 |
f"{99:>4}" |
··99 |
4 格寬、靠右 |
f"{25.06:5.1f}" |
·25.1 |
5 格寬、小數 1 位 |
"Hi".ljust(16) |
Hi 加 14 個空白 |
補滿一整行 |
逐步看:殘留的舊字
注意第 10 行執行後 LCD 的第一行:多出來的 0 就是上一次留下的。第 14 行用固定寬度把它蓋掉。
逐步看:溫度顯示在 LCD 上
TMP102(0x48)與 LCD(0x27)接在同一條 I2C 匯流排上。模擬的溫度從 9.5°C 升到 10.6°C,
看溫度從一位數變成兩位數時,:5.1f 讓第一行的字數維持不變。
LCD 與 OLED 的差別
另一種常見的小螢幕是 OLED(例如 128×64 點、SSD1306 控制晶片,I2C 位址常見 0x3C)。兩者的差別:
| 字元 LCD(1602) | OLED(128×64) | |
|---|---|---|
| 畫面單位 | 32 個字格,每格 5×8 點 | 8192 個點,每個點可以單獨控制 |
| 能顯示 | 英數與符號 | 文字、線條、圖形、圖示(畫得出來就能顯示) |
| 背光 | 需要背光,暗處也看得清楚 | 每個點自己發光,不需要背光,對比高 |
| 程式寫法 | 指定位置寫字 | 先在記憶體裡畫好,再一次送到螢幕 |
樹莓派上驅動 OLED 常用 luma.oled 這類套件;ESP32 軌第 09 課用 MicroPython 的 ssd1306 模組在 OLED 上顯示溫溼度,
可以對照「先畫好再送出」的寫法。
小測驗:LCD 的位置與接線
16x2 LCD 上,lcd.cursor_pos = (1, 3) 之後寫字,字會出現在哪裡?
帶 I2C 轉接板的 LCD 接上樹莓派後,i2cdetect 沒有看到 0x27,最先該做什麼?
想在 LCD1602 上顯示「溫度」兩個中文字,會怎樣?
小測驗:格式化
下面的程式會印出什麼?(用方括號標出頭尾,看得到空白)
t = 9.46
print("[" + f"{t:5.1f}" + "]")
下面的程式會印出什麼?
line = f"Count: {7:<3}"
print(len(line))
重點整理
- LCD1602 是 16 行 × 2 列的字元顯示器,字形以英數符號為主,不能直接顯示中文。
- 帶 PCF8574 轉接板的 LCD 走 I2C,位址常見 0x27(PCF8574A 是 0x3F),可以和其他感測器共用同一條匯流排。
- RPLCD:
CharLCD('PCF8574', 0x27, cols=16, rows=2);write_string寫字、cursor_pos = (列, 行)移動游標、clear()清除、backlight_enabled開關背光。 - LCD 不會清掉沒寫到的格子:用固定寬度(
f"{n:<4}"、f"{t:5.1f}")覆蓋舊字,比每次 clear 更穩定。 - 需要圖形或中文時用 OLED 這類點陣螢幕:每個點可以單獨控制,先畫好再送出。
下一課讓東西動起來:伺服馬達轉到指定角度、用驅動板控制直流馬達的方向與速度。