1. 程式人生 > >在樹莓派3B上使用RPi.GPIO

在樹莓派3B上使用RPi.GPIO

一直都聽說樹莓派功能很強大,這幾天就買了個pi3試玩一下。拿到手裝好系統,就開始測試GPIO口,點亮一個LED。直接用python去操作GPIO好像不行,還好網上有很多python封裝包可以用。RPi.GPIO使用比較簡單,官方主頁也給比較詳細的介紹也附帶了例子。

官網介紹的是英文了,我自己寫了箇中文的使用手冊:

RPi.GPIO是python呼叫包,提供了一些方法來操作樹莓派上GPIO引腳。使用python程式可以很方便的呼叫這些方法。目前RPi.GPIO提供了GPIO輸入、輸出和軟體模擬PWM方法,可惜的是暫不提供SPI、I2C、UART和硬體PWM方法。

使用不難,接下來我就來介紹下使用它的一些感受吧。

首先,既然是控制GPIO口,那就得看看它操作的速度了,雖然python是出了名的慢。

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BOARD)
GPIO.setup(35, GPIO.OUT)

start_time = time.time()
for i in range(0, 1000000):
    GPIO.output(35, 1)
    pass
end_time = time.time()

print(end_time - start_time)
GPIO.cleanup()

上面程式碼我運行了五次,平均下來每次時間為2.4396s。然後去除GPIO.output(35, 1),執行五次,每次平均時間為0.5222s。有這些資料就可以計算出執行1000000次GPIO.output(35, 1)的時間為1.9174s,則每次執行GPIO.output(35, 1)時間是1.9us。我的個神啊太慢了吧,後面我又對輸出0和改成輸入模式,測試的時間都基本一樣,一個字“慢”。現在很多8位微控制器都比這速度快了。估計用這速度去軟體模擬SPI、I2C傳大點的資料是不行了。本來還想模擬個SPI驅動下TFT顯示屏,看到這速度只能放棄了。

RPi.GPIO有個類似硬體中斷的函式,挺好玩的。

import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(35, GPIO.IN, GPIO.PUD_DOWN)

def my_callback(channel):
    print('--my_callback start--')
    for i in range(0, 10000000):
        pass
    print('--my_callback end--')
GPIO.add_event_detect(35
, GPIO.RISING, my_callback, bouncetime=200) while True: time.sleep(1) GPIO.cleanup()

GPIO.add_event_detect新增事件檢測,GPIO.RISING上升沿觸發,my_callback回撥函式,它還有個防抖延時bouncetime(單位ms),省得我們自己去軟體防抖。為什麼我要加for i in range(0, 10000000)呢?我是想知道當中斷被觸發後但還沒有退出來,再次給它個上升沿,它會不會再次進入回撥函式呢?答案是不會。

硬體中的中斷有巢狀關係,需要給每個中斷設定優先順序。51類的需設定一個(不設定就預設),stm32要設定兩個:搶佔優先順序和子優先順序。RPi.GPIO主頁文件中沒有說明這一點,我想通過一段程式碼測試一下。

import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup([35,37], GPIO.IN, GPIO.PUD_UP)

def my_callback_one(channel):
    print('--my_callback_one start--')
    for i in range(0, 100000):
        pass
    print('--my_callback_one end--')
def my_callback_two(channel):
    print('--my_callback_two start--')
    for i in range(0, 100000):
        pass
    print('--my_callback_two end--')
GPIO.add_event_detect(35, GPIO.FALLING, my_callback_one, bouncetime=200)
GPIO.add_event_detect(37, GPIO.FALLING, my_callback_two, bouncetime=200)

while True:
    time.sleep(1)
GPIO.cleanup()

我先是把35和37引腳連在一起,同時給下降沿,發現它們雖然都被觸發了,但還是會先執行一個,執行完後再執行下一個,而不會出現巢狀現象。然後我再嘗試先給35引腳一個下降沿,當35引腳的中斷被觸發,開始執行回撥函式時但還沒有退出回撥的時候我馬上給37引腳一個下降沿,此時37引腳並沒有馬上被觸發去呼叫它的回撥函式而是等35引腳的回撥函式執行完才被觸發。把35引腳和37引腳順序調過來情況也一樣。按理說樹莓派用3的BCM2837處理器的GPIO口中斷應該有巢狀、優先順序的,估計已經被RPi.GPIO預設設定好了。可能被測試的引腳剛好被RPi.GPIO設定成優先順序一個高一個低,不能被搶佔。

綜合上訴測試,RPi.GPIO可以被利用到一些時序要求不高、小量資料傳輸、簡單IO操作的專案上。

RPi.GPIO還有其他的一些用法,如果感興趣可以下載我寫的 《RPi.GPIO使用手冊》或者到 RPi.GPIO主頁 檢視。