3.13. 使用 PWM 與 RC 濾波器產生類比訊號

ADC 會讀取接腳上的電壓。相反的做法——在接腳上產生介於 0 V 與 Vcc 之間的中間電壓——則比較困難,因為 GPIO 輸出只知道如何驅動它的兩條電源軌。標準的替代做法是以足夠快的速度在兩條電源軌之間切換接腳,使你真正在意的平均電壓正好是想要的值。

3.13.1. 脈衝寬度調變

脈衝寬度調變(pulse-width modulation,PWM)訊號是一種固定頻率的方波,其高態時間——也就是每個週期中停留在 Vcc(而非接地)的比例——由軟體設定。這個比例就是工作週期。波形的平均電壓等於工作週期乘以 Vcc:

V_avg = duty × Vcc

25 % 的工作週期平均為 Vcc / 4;50 % 的工作週期平均為 Vcc / 2;75 % 的工作週期平均為 3 × Vcc / 4

三條垂直堆疊的方波波形,頻率都相同。最上方的波形在每個週期中有 25 % 的時間為高態、75 % 為低態。中間的波形高態與低態各佔週期的一半。最下方的波形有 75 % 為高態、25 % 為低態。

工作週期分別為 25 %、50 % 與 75 % 的 PWM。平均電壓會跟隨工作週期變化。

頻率在設定 PWM 時就已決定;工作週期則是軟體可以即時改變的部分。machine.PWM 類別封裝了一個產生波形的硬體計時器通道,無需 CPU 介入——一旦設定完成,訊號就會以所選的頻率與工作週期持續輸出,直到被改變為止。

3.13.2. machine.PWM 類別

用接腳以及初始頻率與工作週期來建構一個 PWM 實例:

from machine import PWM, Pin

pwm = PWM(Pin("P7"), freq=20_000, duty_u16=32768)

這會在 P7 上以 50 % 工作週期啟動一個 20 kHz 的方波。有兩個方法可以即時改變輸出:

pwm.duty_u16(16384)   # change to 25 % (16384 / 65535)
pwm.freq(5_000)       # change to 5 kHz

duty_u16() 接受一個無號 16 位元整數,0 對應到「永遠為低態」,65535 對應到「永遠為高態」。freq() 則以赫茲為單位設定載波頻率。

備註

同一個硬體計時器上的每個 PWM 通道共用相同的頻率。在某個通道上呼叫 freq() 會改變連接到該計時器的所有其他通道。當輸出必須以不同頻率運作時,請使用不同計時器的通道。

當不再需要輸出時,呼叫 deinit() 以釋放該計時器通道。

3.13.3. 使用 RC 低通濾波器取平均

原始的 PWM 並不是平滑的電壓;它是一個方波,我們想要的是它的平均值。為了取出該平均值,請讓 PWM 通過一個低通濾波器——也就是 去彈跳 中用於開關去彈跳的同一組電阻與電容組合。

一支 PWM 接腳經過一個串聯電阻 R 連接到一個輸出節點。從該節點接到接地的一個電容 C 構成了低通濾波器;平滑後的電壓出現在 V_out。

PWM 通過 RC 低通濾波器:電容將方波平均成一個與工作週期成正比的直流電壓。

濾波器的截止頻率——也就是它所通過的頻率與所阻擋的頻率之間的分界——由與去彈跳電路時間常數相同的 RC 乘積決定:

f_c = 1 / (2π × R × C)

為了讓濾波器能從 PWM 輸入取出乾淨的直流電壓,截止頻率必須遠低於 PWM 頻率本身。直流分量(頻率為 0)會原封不動地通過;PWM 的基波諧波(位於 PWM 頻率處)則大約被衰減 f_c / f_PWM1 / 200 的比值可將輸出端的殘餘漣波降至約輸入擺幅的 0.5 %

對於緩慢變化的設定點,一個合理的起點是:

  • PWM 頻率 f_PWM = 20 kHz——遠高於音頻,且計時器易於乾淨地產生。

  • 濾波器數值 R = 1.6 C = 1 µF——得到 f_c = 1 / (2π × 1.6 × 1 µF) 100 Hz

載波處 200 倍的抑制會將 PWM 的完整擺幅降至 V_out 處約 Vcc / 200 的殘餘漣波——在 3.3 V 時約為 16 mV。

兩點實務注意事項:

  • 濾波器的輸出阻抗大致為 R。任何抽取電流的下游負載都會讓 R 與該負載組成一個分壓器,使 V_out 被拉到低於理想平均值,這與 使用 ADC 讀取類比訊號 頁面上的分壓器情況完全相同。請饋入 ADC 接腳或高阻抗緩衝器,而不是會吸取數毫安培的負載。

  • 當工作週期改變時,電容約需 5 × R × C 8 ms 才能穩定;V_out 會比工作週期設定值落後這麼多時間。若設定點需要更快更新,請提高截止頻率(較小的 RC)並接受較多的漣波。