跳轉到內容

Mizar32/PWM

來自華夏公益教科書,開放的書籍,開放的世界
Mizar32 PWM LED 衰減器示例電路

PWM 代表脈衝寬度調製,它是一種生成不同頻率的方波輸出訊號的方法,並且每個波形週期的不同比例是低輸出或高輸出。

當您設定 PWM 輸出時,您指定輸出的頻率(每秒高低變化的次數)及其佔空比(每個週期中花費在高輸出上的百分比)。

PWM 輸出最常見的用法是使用固定頻率並改變佔空比,從而建立一個粗略的數字到模擬轉換器來控制光的亮度或電機提供的功率。如果輸出訊號被放大以控制大功率裝置,這將導致更有效的系統,因為如果放大器全功率開啟一半時間,全功率關閉另一半時間,這比始終以半功率開啟浪費的能量少。

另一種用途是透過使用固定佔空比並改變頻率來生成簡單的音效或風琴音符,以生成具有方波波形的音效。在這種情況下,改變佔空比會改變產生的聲音的音調。

最後,PWM 系統可以透過使能 PWM 中斷來生成固定時間間隔的中斷。這樣,每完成一次 PWM 輸出週期,處理器就會停止當前的操作,執行一段稱為中斷例程的特殊程式碼,完成後,它會回到中斷髮生之前繼續執行它正在做的事情。雖然硬體能夠做到這一點,但 eLua 中尚未實現 PWM 中斷。

硬體檢視

[編輯 | 編輯原始碼]

Mizar32 有七個獨立的 PWM 輸出,雖然在電路圖中只標註了 PWM0 到 PWM5。如果啟用 PWM6,它將出現在標註為“GPIO50”的引腳上。

匯流排引腳
PWM AVR32 引腳 匯流排引腳 eLua 名稱 PicoLisp 備註
PWM0 PB19 BUS4 引腳 7 pio.PB_19 'PB_19
PWM1 PB20 BUS4 引腳 8 pio.PB_20 'PB_20 也連線到 JTAG 引腳 7“EVT0”
PWM2 PB21 BUS1 引腳 8 pio.PB_21 'PB_21
PWM3 PB22 BUS6 引腳 1 pio.PB_22 'PB_22
PWM4 PB27 BUS6 引腳 2 pio.PB_27 'PB_27
PWM5 PB28 BUS6 引腳 3 pio.PB_28 'PB_28
PWM6 PB18 BUS5 引腳 9 pio.PB_18 'PB_18 在 Mizar32 總線上,該引腳稱為“GPIO50”

軟體檢視

[編輯 | 編輯原始碼]

Alcor6L 的 PWM 模組 用於程式設計 PWM 引腳。

PWM6 不可用作使用者,因為它在內部用於提供系統定時器(eLua 中的 tmr.SYS_TIMER,PicoLisp 中的 *tmr-sys-timer*)。

輸出頻率和佔空比

[編輯 | 編輯原始碼]

兩個函式用於在引腳上獲得一些 PWM 輸出。

語言 示例
eLua pwm.setup(channel, frequency, duty_cycle)
PicoLisp (pwm-setup channel frequency duty_cycle)

設定輸出頻率和佔空比,其中 channel(從 0 到 6)是您要使用的 PWM 通道,frequency(從 1 到 1000000)確定輸出波形的頻率(以每秒週期計),duty_cycle(從 0 到 100 的值)確定波形輸出值的每個週期中花費在高電平上的百分比。

語言 示例
eLua pwm.start(channel)
PicoLisp (pwm-start channel)

設定振盪器執行以產生迴圈輸出波形。

如果在呼叫 start() 函式之前呼叫了 setup() 函式,正如我們剛才描述的那樣,總線上的相應引腳將變為輸出引腳,在 setup 完成時輸出 0 伏,然後,當呼叫 start() 時,輸出波形變為高電平,保持高電平一段時間,該時間佔週期的指定百分比,然後在週期的剩餘時間變為低電平,重複此過程,直到對同一通道呼叫 stop() 為止。

或者,如果先呼叫 start(),則該引腳將保持為輸入狀態,直到呼叫 setup(),此時它將變為輸出狀態並開始產生波形。

當呼叫 stop() 時,PWM 輸出總是完成當前週期;“停止”狀態意味著噹噹前週期完成時,它不會開始一個新的週期,因此您可以像這樣獲得恰好一個完整的輸出週期

在 eLua 中

pwm.setup(0, 10, 50)
pwm.start(0)
pwm.stop(0)

在 PicoLisp 中

(pwm-setup 0 10 50)
(pwm-start 0)
(pwm-stop 0)

此程式程式碼將在整個週期輸出完成之前完成,請注意,當它“停止”時,該引腳將繼續輸出 0 伏。

時鐘頻率

[編輯 | 編輯原始碼]

另一個函式

語言 示例
eLua pwm.setclock(id, freq)
PicoLisp (pwm-setclock id freq)

允許您設定 PWM 時鐘頻率,該頻率高於輸出頻率,並確定輸出波形的時間粒度。實際上,PWM 硬體只在每 1/freq 秒內決定是否更改每個 PWM 引腳的輸出值一次,因此更高的時鐘頻率在時間和頻率方面提供更好的精度。

PWM 時鐘頻率也決定了 PWM 輸出波形的最低和最高可能頻率:較低的時鐘頻率允許輸出頻率更低。

Mizar32 上的時鐘頻率可能的取值為 63Hz 到 16500000Hz。如果您要求超出此範圍的值,它將相應地設定這兩個值中的最低值或最高值。在此範圍內,並非所有頻率都可用;在可用的頻率中,它將設定最接近您要求的頻率,並且 setclock()getclock() 都返回一個整數,該整數是實際設定為 PWM 時鐘的頻率。

雖然 Alcor6L 的 setclock()getclock() 函式接受第一個引數來指定要設定時鐘的通道,但實際上硬體只有一個用於所有通道的時鐘,因此設定任何一個通道的時鐘頻率將改變所有通道的時鐘頻率,以及改變任何正在執行的通道的當前輸出頻率。因此,setclock() 通常只在設定各個通道之前呼叫一次。

PWM 輸出頻率的範圍和精度

[編輯 | 編輯原始碼]

在 Alcor6L 中,setup() 函式的引數只關注數字的整數部分,忽略任何小數部分,因此您可以要求的最低頻率為每秒一個週期,最大精度為一赫茲。

此外,硬體只能生成某些頻率(時鐘頻率的精確除數),並且 setup() 返回一個整數,該整數是設定的實際輸出頻率的整數部分的最近似值,這可能與您要求的頻率不同。

例如,在預設時鐘頻率為 1 兆赫茲的情況下,您可以設定從 1 到 1037 的任何整數頻率,但 1038 會得到 1039,然後越來越多的值變得越來越不準確,直到我們來到最高可用的頻率 250000Hz、333333Hz、500000Hz 和 1000000Hz,它們是時鐘頻率分別除以 4、3、2 和 1 的結果。

相反,在最高時鐘速率為 16500000Hz 的情況下,可以獲得從 16Hz 到 4105Hz 的每個整數頻率,並且在這個頻率之上,可以獲得更廣泛的值範圍,這更適合諸如電子管風琴之類的應用,在這種應用中,高音符頻率的準確性比產生極低音符更重要。

使用 PWM 引腳作為 PIO 引腳

[編輯 | 編輯原始碼]

如果特定 PWM 輸出沒有用於 PWM 輸出,您可以透過在該引腳上呼叫 pio 模組中的函式來將其用作通用 PIO 引腳。

如果您希望之前用於 PWM 輸出的引腳完全停止輸出電壓,您也可以使用此方法:您將呼叫

語言 示例
eLua pio.pin.setdir(pio.INPUT, pio.PB_xx)
PicoLisp (pio-pin-setdir *pio-input* 'PB_xx)

其中 xx 是上述表格中該 PWM 通道的引腳編號。

示例程式碼 (eLua)

[編輯 | 編輯原始碼]
-- Make a LED slowly fade up and down forever

-- Connect a LED in series with a
-- 330 ohm resistor between the PWM0 pin
-- (BUS4 pin 7) and GND (BUS4 pin 1)

local pwmid = 0     -- Which channel to use?
local speed = 3000  -- PWM frequency in Hz
local fadetime = 1  -- How many secs to fade up?
local tmrid = 0     -- Which timer for the delay?
local nsteps = 100  -- How many steps in the fade? 

-- Calculate the delay for each steps, in microseconds
local delay = pwm.getclock( tmrid ) * fadetime / nsteps

pwm.start( pwmid )

while true do
  -- Fade the LED up
  for duty = 0, nsteps do
    pwm.setup( pwmid, speed, duty )
    tmr.delay( tmrid, delay )
  end

  -- Fade the LED back down again
  for duty = nsteps, 0, -1 do
    pwm.setup( pwmid, speed, duty )
    tmr.delay( tmrid, delay )
  end
end

示例程式碼 (PicoLisp)

[編輯 | 編輯原始碼]
# Make the LED slowly fade up and down forever

# Connect a LED in series with a
# 330 ohm resistor between PWM0 pin
# (BUS4 pin 7) and GND (BUS4 pin 1)

(setq
   pwmid 0 # Which channel to use?
   speed 3000 # PWM frequency in Hz
   fadetime 1 # How many secs to fade up?
   nsteps 100 ) # How many steps in the fade?

(setq delay (/ (* (pwm-getclock tmrid) fadetime)
               nsteps ) )

(pwm-start pwmid)

(loop
   # Fade the LED up
   (for duty nsteps
      (pwm-setup pwmid speed duty)
      (tmr-delay *tmr-sys-timer* delay) )
   
   # Fade the LED down
   (for (i nsteps (ge0 i) (dec i))
      (pwm-setup pwmid speed i)
      (tmr-delay *tmr-sys-timer* delay) ) )

進一步閱讀

[編輯 | 編輯原始碼]
華夏公益教科書