Learning Objectives
- 說明 PWM 的週期、頻率與工作週期,算出平均電壓
- 用 gpiozero 的 PWMLED 設定 LED 的亮度,寫出呼吸燈
- 分辨有源與無源蜂鳴器,用 TonalBuzzer 依音名播放音階
- 說明軟體 PWM 與硬體 PWM 的差別,以及什麼時候需要在意
只有開和關,怎麼做出「半亮」
上一課的 LED 只有兩種狀態:led.on() 讓腳位輸出 3.3V,led.off() 輸出 0V。樹莓派的 GPIO 是數位腳位,
沒有辦法直接輸出 1.65V 這種「中間」的電壓。
可是很多時候我們要的就是中間值:檯燈要能調亮度、蜂鳴器要能唱出不同的音、伺服馬達要轉到指定的角度。 這一課要回答:
- 只能開和關的腳位,怎麼讓 LED 看起來只有一半亮?
- 同一個技巧,為什麼也能讓蜂鳴器發出 Do、Re、Mi?
- gpiozero 的
PWMLED、TonalBuzzer要怎麼用?
答案是脈波寬度調變(Pulse Width Modulation,PWM):開、關切換得非常快,再控制「開」佔了多少時間。
週期、頻率與工作週期
把腳位快速地開、關、開、關,電壓畫出來會是一串方波。描述它只需要兩個數字:
| 名詞 | 意思 | 例子 |
|---|---|---|
| 週期(period)T | 開加關一輪花多少時間 | 10 ms |
| 頻率(frequency)f | 一秒有幾輪,= 1 ÷ 週期 | 1 ÷ 0.01 秒 = 100 Hz |
| 工作週期(duty cycle) | 一輪裡「開」佔幾 %,也就是高電位的時間 ÷ 週期 | 開 2.5 ms ÷ 10 ms = 25% |
一個週期內的平均電壓= 3.3V × 工作週期。工作週期 25% 時平均是 0.825V,50% 是 1.65V。
LED 每秒亮暗 100 次,眼睛跟不上,看到的是平均的效果:工作週期越大,看起來越亮。
gpiozero 的 PWMLED 把這件事包好了:
from gpiozero import PWMLED
led = PWMLED(18)
led.value = 0.25 # 工作週期 25%:value 是 0~1 的小數
PWMLED 預設的頻率是 100 Hz(建立時可以用 frequency= 改)。value 寫 0 等於 off(),寫 1 等於 on()。
接線和上一課一樣:GPIO18 經過限流電阻接 LED 長腳,短腳接 GND。
逐步看:四種亮度
注意上方電路的 LED:每執行一次第 7 行,下一步亮度就換成新的工作週期。輸出列出每一種工作週期對應的平均電壓。
呼吸燈:讓亮度慢慢變
亮度能調之後,把 value 一點一點加上去、再一點一點減下來,LED 就像在呼吸。最直接的寫法是迴圈:
for i in range(11): # 0.0、0.1、…、1.0
led.value = i / 10
time.sleep(0.1)
gpiozero 也內建了 pulse():呼叫之後立刻回到你的程式,呼吸在背景一直進行,程式可以同時做別的事。
fade_in_time、fade_out_time 設定變亮與變暗各花幾秒。
下一個範例兩種都用。逐步動畫只會在「執行一行程式」時畫一次電路,所以背景的 pulse() 在 sleep 的那一步一口氣跑完;
想看它真的一明一暗,到下面的電路模擬器按播放。
逐步看:自己寫的呼吸與 pulse()
前兩個迴圈每 0.1 秒改一次亮度。第二個迴圈的 range 每次減 2,所以變暗比變亮快一倍。
蜂鳴器:頻率就是音高
蜂鳴器有兩種,外觀很像,用法完全不同:
| 有源蜂鳴器 | 無源蜂鳴器 | |
|---|---|---|
| 裡面 | 自帶振盪電路 | 只有振動片,沒有振盪電路 |
| 怎麼讓它響 | 給高電位就響,音高固定 | 要送方波進去,方波的頻率就是聲音的頻率 |
| gpiozero | Buzzer(on、off、beep) |
TonalBuzzer(play、stop) |
聲音是空氣的振動,每秒振動幾次就是頻率,頻率越高聽起來越高。國際標準音 A4(La)是 440 Hz, 高八度的 A5 是 880 Hz,低八度的 A3 是 220 Hz:每升高一個八度,頻率乘 2。
TonalBuzzer 的 play() 可以直接寫音名(例如 "C4"、"A4"),它會換算成頻率,送出工作週期 50% 的方波。
它預設以 A4 為中心,可以播上下各一個八度(A3~A5)的音;要更寬的範圍,建立時設定 octaves。
無源蜂鳴器的工作週期影響的是音色與音量,音高只看頻率。工作週期 0% 或 100% 時電壓沒有變化,振動片不會動,就不會響。
逐步看:Do Re Mi Fa Sol
看電路上蜂鳴器顯示的頻率:C4 約 262 Hz,往上每個音都比前一個高一些。
軟體 PWM 與硬體 PWM
PWM 可以用兩種方式產生:
- 軟體 PWM:由程式(或函式庫的背景執行緒)按時間開、關腳位,任何 GPIO 都能用。樹莓派執行的是 Linux, 作業系統同時在做很多事,開關的時間點偶爾會晚一點點。LED 亮度差一點點看不出來,但伺服馬達對脈波寬度很敏感, 可能會微微抖動(第 11 課會再談)。
- 硬體 PWM:由晶片裡專門的電路產生,時間很準,不受程式忙不忙影響。樹莓派只有少數腳位接得到硬體 PWM (例如 GPIO12、GPIO13、GPIO18、GPIO19,依型號與設定而定),通道數也很少。
gpiozero 會用哪一種,取決於它背後使用的「腳位工廠」(pin factory)與腳位;初學時不用管,寫法都一樣。 ESP32 這類微控制器有很多組硬體 PWM,「ESP32」軌第 05 課用同樣的觀念做呼吸燈、音階與伺服。
小測驗:PWM 的數字
樹莓派的腳位輸出工作週期 25% 的 PWM,平均電壓大約是多少?
PWMLED 預設的頻率是 100 Hz,一個週期是多久?
下面的程式會印出什麼?(高電位時間=工作週期 × 週期,單位毫秒)
duty = 0.4
freq = 50
period_ms = 1000 / freq
print(duty * period_ms)
小測驗:亮度與聲音
想讓 LED 看起來更亮,PWM 要改哪一個數字?
一個蜂鳴器接上 3.3V 就會「嗶」一聲、音高固定,它是哪一種?該用 gpiozero 的哪個類別?
A4 是 440 Hz,bz.play("A5") 送出的方波頻率大約是多少?
重點整理
- PWM 用快速的開、關模擬中間值:頻率是一秒幾輪,工作週期是一輪裡高電位佔幾 %。
- 平均電壓=3.3V × 工作週期;LED 看起來的亮度跟著工作週期走,頻率只要夠高、看不出閃爍。
PWMLED(腳位)的value是 0~1;pulse()在背景做呼吸燈,程式可以繼續做別的事。- 有源蜂鳴器通電就響(
Buzzer);無源蜂鳴器靠方波的頻率決定音高(TonalBuzzer.play("C4")),高一個八度頻率乘 2。 - 軟體 PWM 任何腳位都能用但時間不一定準;需要準確時序(例如伺服)時,考慮硬體 PWM。
下一課讀取類比訊號:樹莓派沒有類比輸入,要靠 ADC 晶片 MCP3008,把可變電阻轉到的位置變成數字。