DEV Community

codemee
codemee

Posted on • Edited on

控制蜂鳴器後伺服馬達就失效?

今天遇到有人想要同時控制蜂鳴器發聲與伺服馬達轉動, 但是卻發現只要使用蜂鳴器發聲後, 伺服馬達就失控, 可以參考以下的程式:

from machine import Pin,PWM import time # 伺服馬達接 D1, 頻率 50Hz servo = PWM(Pin(5), freq=50) servo.duty(100) # 轉到角度 A time.sleep(1) # 等待 1 秒  # 無緣蜂鳴器接 D8 buzzer = PWM(Pin(15)) buzzer.duty(0) servo.duty(30) # 轉到角度 B print('開門') time.sleep(1) # 等待 1 秒  buzzer.freq(261) # 設定聲音頻率 buzzer.duty(512) # 設定音量 time.sleep(0.5) # 持續播放半秒 buzzer.duty(0) # 停止播放  time.sleep(1) # 等待 1 秒 servo.duty(100) # 轉回角度 A print('關門') 
Enter fullscreen mode Exit fullscreen mode

播完聲音後, 伺服馬達就轉不回來了, 這主要是因為 PWM 的頻率是所有腳位共用, 播完聲音後頻率已經被改為 261Hz, 不再是控制伺服馬達所需要的 50Hz, 因此無法將馬達轉回來。要解決這問題, 最陽春的做法就是在控制伺服馬達前, 重新設定 PWM 的頻率:

from machine import Pin,PWM import time # 伺服馬達接 D1, 頻率 50Hz servo = PWM(Pin(5), freq=50) servo.duty(100) # 轉到角度 A time.sleep(1) # 等待 1 秒  # 無緣蜂鳴器接 D8 buzzer = PWM(Pin(15)) buzzer.duty(0) servo.duty(30) # 轉到角度 B print('開門') time.sleep(1) # 等待 1 秒  buzzer.freq(261) # 設定聲音頻率 buzzer.duty(512) # 設定音量 time.sleep(0.5) # 持續播放半秒 buzzer.duty(0) # 停止播放  time.sleep(1) # 等待 1 秒 servo.freq(50) # 重新設定頻率 servo.duty(100) # 轉回角度 A print('關門') 
Enter fullscreen mode Exit fullscreen mode

這樣就轉得回來了。不過這樣的作法在播放聲音的時候, 伺服馬達可能還是會受到頻率變換的影響, 導致偶有抖動的狀況, 最根本的做法就是在控制完 PWM 訊號的裝置後, 卸除 PWM 功能:

from machine import Pin,PWM import time def set_PWM( p, # 腳位編號  d, # 工作週期  f, # 頻率  t, # 持續時間 ): pwm = PWM(Pin(p), freq=f) # 建立 PWM 物件  pwm.duty(d) # 設定工作週期  time.sleep(t) # 等待持續時間  pwm.deinit() # 卸除 PWM  # 伺服馬達接 D1, 轉到角度 A, 1 秒 set_PWM(5, 100, 50, 1) # 伺服馬達接 D1, 轉到角度 B, 1 秒 print('開門') set_PWM(5, 30, 50, 1) # 無緣蜂鳴器接 D8, 播聲音 0.5 秒 set_PWM(15, 512, 261, 0.5) time.sleep(1) # 等待 1 秒  print('關門') # 伺服馬達接 D1, 轉到角度 A, 1 秒 set_PWM(5, 100, 50, 1) 
Enter fullscreen mode Exit fullscreen mode

如果是使用 ESP32, 那也可以參考使用 esp32.RMT 設計不同頻率的 PWM讓不同腳位以不同的頻率進行 PWM。

Top comments (0)