1. 程式人生 > >樹莓派的GPIO埠詳解

樹莓派的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燈

樹莓派gpio介面及程式設計方法

  上面說明了一大堆函式庫的用法,那麼現在就應該來個簡單的實驗了。這個實驗很簡單,點亮一個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介面及程式設計方法

  結語

  在文中,主要講解了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)