1. 程式人生 > >樹莓派GPIO 模組使用基礎

樹莓派GPIO 模組使用基礎

   這篇日誌的內容應該算是《RPi.GPIO 模組使用基礎》Input 部分的擴充套件講解,詳細講解了 Input 部分的一些高階應用技巧。目前有幾種途徑可以在您的程式中獲得 GPIO 的輸入資訊。第一種也是最簡易的一種為在某個時間點檢查輸入值。這即是所謂的“輪詢(polling)”,而且如果您的程式在錯誤的時間裡進行了讀取,可能會錯過某個輸入值。在迴圈中運用輪詢,有可能使處理器資源緊張。另一種對 GPIO 輸入進行響應的方式可以使用“中斷(interruots)”(邊緣檢測(edge detection))。邊緣可以是從 HIGH 到 LOW 的過度(下降臨界值(falling edge))或從 LOW 到 HIGH 的過度(上升臨界值(rising edge))。

上拉/下拉電阻

如果您在輸入針腳上沒有連線任何元件,那麼它將是“浮動(float)”的。換句話說,因為您沒有連線任何元件,在按下按鈕或開關之前,讀取的值是沒有意義的。由於電源的波動,獲取到的值可能會有很大的變化。

為了解決這個問題,我們需要使用上拉/下拉電阻。這樣,我們就可設定輸入的預設值了。在這裡,可以使用硬體或軟體對電阻進行上拉/下拉。使用硬體方式,將一個 10K 的電阻連線在輸入通道與 3.3V(上拉)或 0V(下拉)之間是常用的做法。而 RPi.GPIO 也允許您通過軟體的方式對配置 Broadcom SOC 來達到目的:

  1. GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)

或者

  1. GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

(通道編號是基於您所使用的編號系統所指定的(BOARD 或 BCM)。)

輸入測試(輪詢(polling))

您可以在某個時間點獲得一次輸入的快照:

  1. if GPIO.input(channel):
  2.     print('Input was HIGH')
  3. else:
  4.     print('Input was LOW')

在迴圈中等待按鈕被按下後進行輪詢:

  1. while GPIO.input(channel) == GPIO.LOW:
  2.     time.sleep(0.01)  # 為 CPU 留出 10 毫秒,供其處理其它事物

(這裡假設為當按下按鈕時,輸入狀態從 LOW 到 HIGH)

中斷和邊檢檢測

邊緣的定義為電訊號從 LOW 到 HIGH(上升臨界值)或從 HIGH 到 LOW(下降臨界值)狀態的改變。正常情況下,對於輸入的值來說,我們更關心的是輸入的狀態是否發生了改變。這種狀態上的改變是很重要的。

為了避免您的程式在忙於處理其它的事物時而錯過了您按下按鈕的操作,這裡有兩種方法可以解決:

  • wait_for_edge() 函式
  • event_detected() 函式
  • 在檢測到邊緣時執行執行緒回撥函式

WAIT_FOR_EDGE() 函式

wait_for_edge() 函式被設計用於在檢測到邊緣之前阻止程式的執行。換句話說,上面的示例中,等待按鈕被按下的語句可以改寫為:

  1. GPIO.wait_for_edge(channel, GPIO.RISING)

注意,您可以輸入 GPIO.RISING、GPIO.FALLING、GPIO.BOTH 對邊緣進行檢測。這種方式的優點是佔用 CPU 資源很少,因此係統可以有充裕的資源處理其它事物。

EVENT_DETECTED() 函式

event_detected() 函式被設計用於迴圈中有其它東西時使用,但不同於輪詢的是,它不會錯過當 CPU 忙於處理其它事物時輸入狀態的改變。這在類似使用 Pygame 或 PyQt 時主迴圈實時監聽和響應 GUI 的事件是很有用的。

  1. GPIO.add_event_detect(channel, GPIO.RISING)  # 在通道上新增上升臨界值檢測
  2. do_something()
  3. if GPIO.event_detected(channel):
  4.     print('Button pressed')

注意,您可以輸入 GPIO.RISING、GPIO.FALLING、GPIO.BOTH 對邊緣進行檢測。

執行緒回撥

RPi.GPIO 在第二條執行緒中執行回撥函式。這意味著回撥函式可以同您的主程式同時執行,並且可以立即對邊緣進行響應。例如:

  1.  def my_callback(channel):
  2.     print('這是一個邊緣事件回撥函式!')
  3.     print('在通道 %s 上進行邊緣檢測'%channel)
  4.     print('該程式與您的主程式執行在不同的程序中')
  5.   GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback)  # 在通道上新增上升臨界值檢測
  6. ... 其它程式程式碼 ...

如果您需要多個回撥函式:

  1. def my_callback_one(channel):
  2.     print('回撥 1')
  3. def my_callback_two(channel):
  4.     print('回撥 2')
  5. GPIO.add_event_detect(channel, GPIO.RISING)
  6. GPIO.add_event_callback(channel, my_callback_one)
  7. GPIO.add_event_callback(channel, my_callback_two)

注意,在該示例中,回撥函式為順序執行而不是同時執行。這是因為當前只有一個程序供回撥使用,而回調的執行順序是依據它們被定義的順序。

開關防抖

您可能會注意到,每次按鈕按下時,回撥操作被呼叫不止一次。這種現象被稱作“開關抖動(switch bounce)”。這裡有兩種方法解決開關抖動問題:

  • 將一個 0.1uF 的電容連線到開關上。
  • 軟體防止抖動
  • 兩種方式一起用

使用軟體方式抖動,可以在您指定的回撥函式中新增 bouncetime= 引數。 抖動時間需要使用毫秒為單位進行書寫。例如:

  1. # 在通道上新增上升臨界值檢測,忽略由於開關抖動引起的小於 200ms 的邊緣操作
  2. GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback, bouncetime=200)

或者

  1. GPIO.add_event_callback(channel, my_callback, bouncetime=200)

remove_event_detect()

由於某種原因,您不希望您的程式檢測邊緣事件,您可以將它停止:

  1. GPIO.remove_event_detect(channel)

注:此文章是轉載的,

希望能幫到學習樹莓派GPIO 模組的同學。