一起玩轉樹莓派(4)——用開關控制蜂鳴器發聲
在本系列的前幾篇部落格中,我們使用桌面軟體控制過紅綠燈,也程式設計點亮過炫彩的3色LED 燈。在這些實驗的過程中,相信你對樹莓派GPIO引腳如何輸出高低電平,以及如何使用PWM技術來控制電壓輸出等都有了了解。本篇部落格,我們将再探索一些樹莓派程式設計更多新鮮好玩的領域,來嘗試使用硬體來控制硬體。
現在,我們将嘗試完成這樣一個實驗,使用按壓開關控制蜂鳴器的發聲。将開關元件和蜂鳴器都連接配接到樹莓派,當按下開關時,讓蜂鳴器發聲,當松開開關時,蜂鳴器停止發聲。
一、主角登場
開始動手實驗前,我們先來認識一下将要出場的主角們,當然,無論什麼實驗,樹莓派都是當之無愧的第一主角,但我相信你已經對它已經有了足夠的了解(如果沒有,可以檢視本系列的前幾篇部落格),是以我們将介紹的重點放在兩個新登場的“角色”上:蜂鳴器與按壓開關。
1.本實驗的“主角甲”——有源蜂鳴器
蜂鳴器,顧名思義,其是一種發聲元件。廣泛應用于計算機、列印機、電話、玩具等電子裝置中。
蜂鳴器可以分為“有源蜂鳴器”和“無源蜂鳴器”。其中的源并非指電源,而是指蜂鳴器内部是否有震蕩源。有源蜂鳴器自帶一個震蕩源子產品,其使用起來非常簡單,隻要接通直流電,其就會自動發出聲音。而無源蜂鳴器内部沒有震蕩源,需要外接使用一定頻率的方波來驅動其發聲。關于無源蜂鳴器更多深入的用法,我們後續部落格再專門介紹。這裡,我們先着重了解有源蜂鳴器的工作原理。
本實驗中,我們采用的是低電平觸發的有源蜂鳴器,元件如下圖所示:

其有3個引腳,GND引腳用來接地,VCC引腳用來接3.3V的電源,I/O引腳用來進行蜂鳴器是否播放聲音的控制。你可能有些疑惑,為什麼低電平也可以觸發元件的“開”狀态,這要歸功于PNP型三極管的功勞,對于PNP型三極光,當輸入管腳為低電平時,三極管處于導通狀态,使得蜂鳴器被加電壓,當輸入管腳為高電平時,三極管處于截止狀态,蜂鳴器無電壓。原理如下圖所示:
現在,我們先來編寫一段簡單的Python程式,來使蜂鳴器發出聲音。
2. 觸發蜂鳴器播放聲音
我們使用的蜂鳴器的3個引腳,其中VCC接電源,GND接地,I/O引腳我們可以選擇樹莓派BCM編碼為27的GPIO引腳,通過查表,可以得到其實體編碼為13。連線示意如下:
編寫Python程式代碼如下:
#coding:utf-8
# 導入GPIO控制薄塊
import RPi.GPIO as GPIO
# 導入time子產品
import time
# 定義引腳
fm = 13
# 設定使用的引腳編碼模式
GPIO.setmode(GPIO.BOARD)
# 進行引腳的初始化,因為是低電平觸發,初始時設定為高電平
GPIO.setup(fm,GPIO.OUT, initial=GPIO.HIGH)
# 進行一長兩短的聲音播放
# 播放1秒聲音
GPIO.output(fm, GPIO.LOW)
time.sleep(1)
GPIO.output(fm, GPIO.HIGH)
time.sleep(0.1)
# 播放0.5秒聲音
GPIO.output(fm, GPIO.LOW)
time.sleep(0.5)
GPIO.output(fm, GPIO.HIGH)
time.sleep(0.1)
# 播放0.5秒聲音
GPIO.output(fm, GPIO.LOW)
time.sleep(0.5)
# 停止蜂鳴器播放
GPIO.output(fm, GPIO.HIGH)
GPIO.cleanup()
在樹莓派上運作代碼,你應該已經可以聽到蜂鳴器發出一長兩短的鳴叫聲了。
3.本實驗的“主角乙”——按壓開關
按壓開關是電子裝置中最為常用的一種元件,關于按壓開關本身的結構和原理,其實非常簡單,其按鍵内部會有彈簧進行控制,當沒有外力作用時,彈簧會将開關自動頂起,接觸器上升。當外力将按鍵按下時,接觸器下降。通過接觸器的上升和下降來控制電路的導通。如下圖所示:
本次實驗,我們使用的按壓開關元件如下圖所示:
我們使用的此開關當按鍵按下式,會向引腳輸入低電平,當按鍵松開時,會向引腳輸入低電平。在連線時,按壓開關的“-”引腳接地,中間引腳節3.3V電壓,“S”引腳接GPIO信号引腳,我們可以将其接BCM編碼為GPIO5的引腳,其實體編碼為29。連線如下圖所示:
下面,我們要來學習點新東西了,如何擷取到GPIO引腳的輸入。
4. 使用GPIO輸入信号
之前,我們都是将GPIO作為輸出引腳進行使用,即讓GPIO輸出高電平或低電平進而控制元件。其實還有很多場景,需要讀取GPIO的輸入信号,例如各種傳感器和開關元件。通常,我們可以采用兩種方式來擷取GPIO的輸入信号:輪詢式或中斷式。
輪詢式很好了解,即我們不停的詢問目前GPIO引腳:輸入的信号是什麼啊?之後GPIO會将目前的輸入資訊告訴我們,這種不停的讀取某個GPIO引腳的值的方式就是輪詢式擷取輸入信号。更多時候,我們會采取中斷式,中斷式是指在程式運作過程中,如果出現外部事件,則中斷目前程式運作來處理外部事件。在本實驗中,開關的按下和松開就可以了解為中斷事件。
需要注意,對于作為輸入使用的GPIO引腳來說,當我們未接任何輸入源時,其值可能是任意的,即其值是浮動且不可控的,是以我們需要為其配置一個預設值,硬體上,我們通常使用下拉電阻或上拉電阻。軟體上我們也可以通過GPIO庫的相關接口來實作同樣的功能,例如使用下面的方式初始化引腳:
# 将引腳初始化為輸入引腳,同時設定預設值為高電平
GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# 将引腳初始化為輸入引腳,同時設定預設值為低電平
GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
若要擷取到某個輸入引腳目前的電平情況,可以使用如下方法:
# 1表示高電平 0表示低電平
GPIO.input(channel)
例如可以通過如下的方式輪訓檢查某個引腳的輸入:
while GPIO.input(channel) == GPIO.LOW:
time.sleep(0.01)
我們通常隻需要關心電平的變化,以及變化方向,以本實驗為例,當按下開關時,電平由低變高,當松開開關時,電平由高到低。下面方法可以中斷目前程式的運作,等待電平變化的信号:
# 當channel引腳由低電平變到高電平時會觸發向後執行, timeout設定逾時時間
GPIO.wait_for_edge(channel, GPIO.RISING, timeout=5000)
GPIO.RISING表示要等待的是由低到高的電平變化,與之對應的還有GPIO.FALLING表示由高到低的電平變化,GPIO.BOTH表示兩個方向的電平變化都會觸發。
對于本實驗的場景,GPIO.wait\_for\_edge方法并不實用,如果我們要采用輪詢的方式擷取GPIO輸入信号,則可以實用下面的方法:
# 為channel輸入引腳添加[從低到高]的電平變化監聽
GPIO.add_event_detect(channel, GPIO.RISING)
# 下面的判斷可以放在輪詢中,隻要有[從低到高]的電平變化,即會命中if判斷
if GPIO.event_detected(channel):
print('從低到高變化')
需要注意,GPIO.add\_event\_detect方法比直接輪詢通過GPIO.input方法擷取信号要可靠的多,直接輪詢可能會錯過某些電平變化事件,而GPIO.add\_event\_detect 不會。在使用GPIO.add\_event\_detect方法時,我們也可以直接設定回調函數,當有變化發生時,即會執行到回調函數,例如:
# 定義回調函數
def my_callback(channel):
pass
# 注冊回調函數 bouncetime參數用來進行防抖
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback, bouncetime=200)
上面示例代碼中,bouncetime參數能夠提供軟體防抖的功能,其機關為毫秒,200毫秒内的多次電平變化來回将被忽略。
最後,如果你不再需要監聽,可以使用如下方法移除:
GPIO.remove_event_detect(channel)
5. 擷取按壓開關元件的狀态
現在,我們可以嘗試使用樹莓派讀取按壓開關元件的開關狀态了。示例代碼如下:
#coding:utf-8
# 導入GPIO控制薄塊
import RPi.GPIO as GPIO
# 導入time子產品
import time
# 設定使用的引腳編碼模式
GPIO.setmode(GPIO.BOARD)
# 定義開關引腳
swi = 29
# 進行開關引腳的初始化,設定為輸入引腳,且預設為高電平
GPIO.setup(swi, GPIO.IN, pull_up_down=GPIO.PUD_PU)
# 定義狀态變化的回調函數
def switch(channel):
# 高電平的開關松開
if GPOI.input(channel):
print("開關松開")
# 低電平為開關按下
else:
print("開關按下")
# 添加輸入引腳電平變化的回調函數
GPIO.add_event_detect(swi, GPIO.BOTH, callback=switch, bouncetime=200)
# 開啟循環
while True:
pass
在樹莓派運作上面代碼,通過按壓和松開開關,觀察控制台的輸出是否正确。
二、開關控制蜂鳴器播放
如果你成功做完了前面的工作,那麼好了,本節的内容将非常簡單,隻需要将上面編寫的蜂鳴器程式和開關程式進行結合,你就可以使用開關來控制蜂鳴器了。示例代碼如下:
#coding:utf-8
# 導入GPIO控制薄塊
import RPi.GPIO as GPIO
# 導入time子產品
import time
# 設定使用的引腳編碼模式
GPIO.setmode(GPIO.BOARD)
# 定義開關引腳
swi = 29
# 定義蜂鳴器引腳
fm = 13
# 進行開關引腳的初始化,設定為輸入引腳,且預設為高電平
GPIO.setup(swi, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# 進行蜂鳴器引腳的初始化,因為是低電平觸發,初始時設定為高電平
GPIO.setup(fm,GPIO.OUT, initial=GPIO.HIGH)
# 定義狀态變化的回調函數
def switch(channel):
# 高電平的開關松開
if GPI0.input(channel):
GPIO.output(fm, GPIO.HIGH)
# 低電平為開關按下
else:
GPIO.output(fm, GPIO.LOW)
# 添加輸入引腳電平變化的回調函數
GPIO.add_event_detect(swi, GPIO.BOTH, callback=switch, bouncetime=200)
# 開啟循環
while True:
pass
現在,運作程式,用開關來控制蜂鳴器的聲音播放吧。恭喜!你已經能夠使用硬體來控制硬體了!
三、休息一下吧
通過本篇部落格,你應該收獲了GPIO輸入信号的程式設計方法,以及通過GPIO讀取有輸入功能的傳感器資料的方法。本篇部落格涉及的内容很多,重點在于GPIO輸入引腳中斷的相關用法,需要你多多練習。說了這麼多,你有沒有發現這次我們完成的實驗很像生活中的一種東西?沒錯,就是門鈴,你已經可以使用樹莓派實作一個簡單的門鈴器件啦。
專注技術,懂的熱愛,願意分享,做個朋友
QQ:316045346