樹莓派的GPIO埠詳解
首先上一張埠圖
GPIO(GeneralPurposeI/OPorts)意思為通用輸入/輸出埠,通俗地說,就是一些引腳,可以通過它們輸出高低電平或者通過它們讀入引腳的狀態-是高電平或是低電平。GPIO是個比較重要的概念,使用者可以通過GPIO口和硬體進行資料互動(如UART),控制硬體工作(如LED、蜂鳴器等),讀取硬體的工作狀態訊號(如中斷訊號)等。GPIO口的使用非常廣泛。掌握了GPIO,差不多相當於掌握了操作硬體的能力。
圖上可以看到,每一個針腳都有Pin#和NAME欄位。Pin代表的是該針腳的編號,其中01和02針腳對應第一張圖中GPIO最右邊豎排的兩個針腳。而NAME代表的是該針腳的BCM名稱,當然NAME也可以直接看得出針腳的預設功能。比如3.3v和5v代表著該針腳會輸出3.3v和5v的電壓,Ground代表著該針腳是接地的,GPIO0*則是一些待使用者開發的針腳。每個針腳都可以使用程式進行控制操作。
控制GPIO程式設計
可以用下面的程式碼匯入RPi.GPIO模組。
importRPi.GPIOasGPIO
引入之後,就可以使用GPIO模組的函數了。如果你想檢查模組是否引入成功,也可以這樣寫:
try:
importRPi.GPIOasGPIO
exceptRuntimeError:
print(“引入錯誤”)
針腳編號
在RPi.GPIO中,同時支援樹莓派上的兩種GPIO引腳編號。第一種編號是BOARD編號,這和樹莓派電路板上的物理引腳編號相對應。使用這種編號的好處是,你的硬體將是一直可以使用的,不用擔心樹莓派的版本問題。因此,在電路板升級後,你不需要重寫聯結器或程式碼。
第二種編號是BCM規則,是更底層的工作方式,它和Broadcom的片上系統中通道編號相對應。在使用一個引腳時,你需要查詢通道號和物理引腳編號之間的對應規則。對於不同的樹莓派版本,編寫的指令碼檔案也可能是無法通用的。
你可以使用下列程式碼(強制的)指定一種編號規則:
GPIO.setmode(GPIO.BOARD)
#or
GPIO.setmode(GPIO.BCM)
下面程式碼將返回被設定的編號規則
mode=GPIO.getmode()
警告
如果RPi.GRIO檢測到一個引腳已經被設定成了非預設值,那麼你將看到一個警告資訊。你可以通過下列程式碼禁用警告:
GPIO.setwarnings(False)
引腳設定
在使用一個引腳前,你需要設定這些引腳作為輸入還是輸出。配置一個引腳的程式碼如下:
#將引腳設定為輸入模式
GPIO.setup(channel,GPIO.IN)
#將引腳設定為輸出模式
GPIO.setup(channel,GPIO.OUT)
#為輸出的引腳設定預設值
GPIO.setup(channel,GPIO.OUT,initial=GPIO.HIGH)
釋放
一般來說,程式到達最後都需要釋放資源,這個好習慣可以避免偶然損壞樹莓派。釋放指令碼中的使用的引腳:
GPIO.cleanup()
注意,GPIO.cleanup()只會釋放掉指令碼中使用的GPIO引腳,並會清除設定的引腳編號規則。
將埠設定為輸出的狀態:
要想點亮一個LED燈,或者驅動某個裝置,都需要給電流和電壓他們,這個步驟也很簡單,設定引腳的輸出狀態就可以了,程式碼如下:
GPIO.output(channel,state)
狀態可以設定為0/GPIO.LOW/False/1/GPIO.HIGH/True。如果編碼規則為,GPIO.BOARD,那麼channel就是對應引腳的數字。
如果想一次性設定多個引腳,可使用下面的程式碼:
chan_list=[11,12]
GPIO.output(chan_list,GPIO.LOW)
GPIO.output(chan_list,(GPIO.HIGH,GPIO.LOW))
你還可以使用Input()函式讀取一個輸出引腳的狀態並將其作為輸出值,例如:
GPIO.output(12,notGPIO.input(12))
讀取
我們也常常需要讀取引腳的輸入狀態,獲取引腳輸入狀態如下程式碼:
GPIO.input(channel)
低電平返回0/GPIO.LOW/False,高電平返回1/GPIO.HIGH/True。
如果輸入引腳處於懸空狀態,引腳的值將是漂動的。換句話說,讀取到的值是未知的,因為它並沒有被連線到任何的訊號上,直到按下一個按鈕或開關。由於干擾的影響,輸入的值可能會反覆的變化。使用如下程式碼可以解決問題:
GPIO.setup(channel,GPIO.IN,pull_up_down=GPIO.PUD_UP)
#or
GPIO.setup(channel,GPIO.IN,pull_up_down=GPIO.PUD_DOWN)
需要注意的是,上面的讀取程式碼只是獲取當前一瞬間的引腳輸入訊號。
如果需要實時監控引腳的狀態變化,可以有兩種辦法。最簡單原始的方式是每隔一段時間檢查輸入的訊號值,這種方式被稱為輪詢。如果你的程式讀取的時機錯誤,則很可能會丟失輸入訊號。輪詢是在迴圈中執行的,這種方式比較佔用處理器資源。另一種響應GPIO輸入的方式是使用中斷(邊緣檢測),這裡的邊緣是指訊號從高到低的變換(下降沿)或從低到高的變換(上升沿)。
輪詢方式
whileGPIO.input(channel)==GPIO.LOW:
time.sleep(0.01)#wait10mstogiveCPUchancetodootherthings
邊緣檢測
邊緣是指訊號狀態的改變,從低到高(上升沿)或從高到低(下降沿)。通常情況下,我們更關心於輸入狀態的該邊而不是輸入訊號的值。這種狀態的該邊被稱為事件。先介紹兩個函式:
wait_for_edge()函式。wait_for_edge()被用於阻止程式的繼續執行,直到檢測到一個邊沿。也就是說,上文中等待按鈕按下的例項可以改寫為:channel=GPIO.wait_for_edge(channel,GPIO_RISING,timeout=5000)
ifchannelisNone:
print(‘Timeoutoccurred’)
else:
print(‘Edgedetectedonchannel’,channel)
add_event_detect()函式該函式對一個引腳進行監聽,一旦引腳輸入狀態發生了改變,呼叫event_detected()函式會返回true,如下程式碼:GPIO.add_event_detect(channel,GPIO.RISING)#addrisingedgedetectiononachannel
do_something()
//下面的程式碼放在一個執行緒迴圈執行。
ifGPIO.event_detected(channel):
print(‘Buttonpressed’)
上面的程式碼需要自己新建一個執行緒去迴圈檢測event_detected()的值,還算是比較麻煩的。
不過可採用另一種辦法輕鬆檢測狀態,這種方式是直接傳入一個回撥函式:
defmy_callback(channel):
print(‘Thisisaedgeeventcallbackfunction!’)
print(‘Edgedetectedonchannel%s’%channel)
print(‘Thisisruninadifferentthreadtoyourmainprogram’)
GPIO.add_event_detect(channel,GPIO.RISING,callback=my_callback)
如果你想設定多個回撥函式,可以這樣:
defmy_callback_one(channel):
print(‘Callbackone’)
defmy_callback_two(channel):
print(‘Callbacktwo’)
GPIO.add_event_detect(channel,GPIO.RISING)
GPIO.add_event_callback(channel,my_callback_one)
GPIO.add_event_callback(channel,my_callback_two)
注意:回撥觸發時,並不會同時執行回撥函式,而是根據設定的順序呼叫它們。
綜合例子:點亮LED燈
上面說明了一大堆函式庫的用法,那麼現在就應該來個簡單的實驗了。這個實驗很簡單,點亮一個LED燈。
編寫程式碼之前,首先你需要將led燈的針腳通過杜邦線連線到樹莓派的引腳上,比如你可以連線到11號引腳。
新建一個main.py檔案,寫入如下程式碼:
importRPi.GPIOasGPIO//引入函式庫
importtime
RPi.GPIO.setmode(GPIO.BOARD)//設定引腳編號規則
RPi.GPIO.setup(11,RPi.GPIO.OUT)//將11號引腳設定成輸出模式
whileTrue
GPIO.output(channel,1)//將引腳的狀態設定為高電平,此時LED亮了
time.sleep(1)//程式休眠1秒鐘,讓LED亮1秒
GPIO.output(channel,0)//將引腳狀態設定為低電平,此時LED滅了
time.sleep(1)//程式休眠1秒鐘,讓LED滅1秒
GPIO.cleanup()//程式的最後別忘記清除所有資源
儲存,並退出檔案。執行python3main.py,即可觀看效果。Ctrl+C可以關閉程式。
此外,不妨也試試其它的函式吧,增強印象。
使用PWM
這個python函式庫還支援PWM模式的輸出,我們可以利用PWM來製作呼吸燈效果。詳情看程式碼:
importtime
importRPi.GPIOasGPIO//引入庫
GPIO.setmode(GPIO.BOARD)//設定編號方式
GPIO.setup(12,GPIO.OUT)//設定12號引腳為輸出模式
p=GPIO.PWM(12,50)//將12號引腳初始化為PWM例項,頻率為50Hz
p.start(0)//開始脈寬調製,引數範圍為:(0.0《=dc《=100.0)
try:
while1:
fordcinrange(0,101,5):
p.ChangeDutyCycle(dc)//修改佔空比引數範圍為:(0.0《=dc《=100.0)
time.sleep(0.1)
fordcinrange(100,-1,-5):
p.ChangeDutyCycle(dc)
time.sleep(0.1)
exceptKeyboardInterrupt:
pass
p.stop()//停止輸出PWM波
GPIO.cleanup()//清除
結語
在文中,主要講解了GPIO的概念,以及如何使用python操作GPIO。但是想要充分了解樹莓派gpio程式設計,還需要自己實際動手操作以及分析總結。
以下為測試程式
# -*- coding: utf-8 -*- #通過宣告可以在程式中書寫中文
import RPi.GPIO as GPIO #引入RPi.GPIO庫函式命名為GPIO
import time #引入計時time函式
# BOARD編號方式,基於插座引腳編號
GPIO.setmode(GPIO.BOARD) #將GPIO程式設計方式設定為BOARD模式
# 輸出模式
GPIO.setup(11, GPIO.OUT) #將GPIO引腳11設定為輸出引腳
while True: # 條件為真,下面程式一直迴圈執行
GPIO.output(11, GPIO.HIGH) #將11引腳電壓置高,點亮LED燈
time.sleep(1) #延時1秒
GPIO.output(11, GPIO.LOW) #將11引腳電壓置低,熄滅LED燈
time.sleep(1)