透過 Python 的 gpiozero 函式庫,可以輕鬆控制樹莓派的 GPIO 與按鈕和開關互動。文章涵蓋了基本按鈕連線偵測、使用中斷避免程式阻塞、透過按鈕切換 LED 狀態,以及更進階的三位式切換開關應用。程式碼範例簡潔易懂,搭配流程圖說明,更能理解程式邏輯與硬體互動方式。此外,也提到了按鈕去抖動的議題,確保程式穩定執行。

連線按鈕開關

問題 您想要連線一個按鈕開關到您的樹莓派(Raspberry Pi),使得當您按下按鈕時,某些Python程式碼會被執行。

解決方案 連線一個按鈕開關到一個GPIO腳位,並使用gpiozero函式庫在您的Python程式中偵測按鈕按下。 要完成這個食譜,您需要以下元件: -麵包板和跳線(參考「原型設計裝置和套件」)

  • 觸控按鈕開關(參考「雜項」)

圖12-1顯示如何使用麵包板和跳線連線一個觸控按鈕開關。

圖12-1. 連線按鈕開關到樹莓派

使用麵包板和觸控按鈕開關的替代方案是使用鱷魚按鈕(圖12-2)。這是一個具有女性頭部引腳的按鈕開關,您可以直接將其連線到GPIO聯結器(食譜9.11)。

圖12-2. 鱷魚按鈕

開啟一個編輯器並貼入以下程式碼(ch_12_switch.py):

from gpiozero import Button

button = Button(18)
while True:
    if button.is_pressed:
        print("按鈕被按下")

與本文中的所有程式範例一樣,您也可以下載這個程式碼(參考食譜3.22)。

當您執行程式並按下按鈕時,您將看到以下內容:

pi@raspberrypi ~ $ python3 ch_12_switch.py
按鈕被按下
按鈕被按下
按鈕被按下
按鈕被按下

事實上,「按鈕被按下」的訊息可能會迅速地從螢幕底部滾動而過。這是因為程式正在非常頻繁地檢查按鈕是否被按下。另一個問題是,這個程式在等待按鈕按下的時候,不能做其他事情。

我們可以改進這個程式,既可以在按鈕被按下時只做一次事情,也可以在等待按鈕按下的時候做其他事情。您可以在以下程式碼(ch_12_switch_2.py)中找到這些改進:

from gpiozero import Button
from time import sleep

內容解密:

  • 我們首先匯入必要的函式庫,包括gpiozero用於與GPIO進行互動,以及time用於暫停執行。
  • 我們建立一個Button物件,指定GPIO腳位為18。
  • 我們進入一個無限迴圈,持續檢查按鈕是否被按下。
  • 當按鈕被按下時,我們印出「按鈕被按下」的訊息。

圖表翻譯:

  flowchart TD
    A[開始] --> B[初始化GPIO]
    B --> C[建立Button物件]
    C --> D[進入迴圈]
    D --> E[檢查按鈕狀態]
    E -->|按鈕被按下| F[印出訊息]
    E -->|按鈕未被按下| D

此圖表展示了程式的流程,從初始化GPIO開始,建立Button物件,進入迴圈檢查按鈕狀態,當按鈕被按下時印出訊息。

使用中斷來偵測按鈕按下

在許多應用中,程式需要在按鈕被按下時觸發特定動作,但同時也需要執行其他任務。為了實作這種功能,我們可以使用中斷(interrupts)的概念。

中斷機制

中斷是一種機制,允許程式在執行其他任務的同時,偵測到特定事件(如按鈕按下)並立即執行相關的處理函式。這種方式可以確保程式對事件的反應迅速,同時不會阻塞其他任務的執行。

實作中斷

以下是一個使用Python實作中斷的範例:

import time
from gpiozero import Button

def handle_button_press():
    print("按鈕被按下")

button = Button(18)
button.when_pressed = handle_button_press

while True:
    print("程式正在執行其他任務")
    time.sleep(2)

在這個範例中,我們定義了一個函式handle_button_press(),它將在按鈕被按下時被呼叫。然後,我們建立了一個Button物件,並將其when_pressed屬性設定為handle_button_press函式。這樣,當按鈕被按下時,handle_button_press()函式將被自動呼叫。

注意事項

注意,在設定when_pressed屬性時,我們沒有在函式名稱後面加上括號()。這是因為我們要參照函式本身,而不是立即呼叫它。只有當按鈕被按下時,函式才會被呼叫。

執行結果

當你執行這個程式時,你會看到如下輸出:

程式正在執行其他任務
程式正在執行其他任務
按鈕被按下
程式正在執行其他任務
程式正在執行其他任務

當你按下按鈕時,handle_button_press()函式將被呼叫,並列印預出"按鈕被按下"的訊息。同時,程式將繼續執行其他任務。

內容解密:

  • 我們使用gpiozero函式庫來控制GPIO口。
  • Button類別用於建立按鈕物件。
  • when_pressed屬性用於設定按鈕按下時的處理函式。
  • handle_button_press()函式是按鈕按下時被呼叫的函式。
  • time.sleep(2)用於模擬程式執行其他任務的過程。

圖表翻譯:

  flowchart TD
    A[程式啟動] --> B[設定按鈕中斷]
    B --> C[執行其他任務]
    C --> D[按鈕被按下]
    D --> E[呼叫處理函式]
    E --> C

這個流程圖展示了程式的執行流程:設定按鈕中斷、執行其他任務、按鈕被按下、呼叫處理函式。

使用按鈕切換LED狀態

在本文中,我們將探討如何使用按鈕切換LED的狀態。這是一個基本的電子工程專案,需要使用Raspberry Pi、麵包板、跳線、按鈕和LED。

按鈕連線

按鈕通常有四個接點,但實際上只有兩個電氣連線,因為內部的接點是相互連線的。圖12-3顯示了按鈕的接點安排。

按鈕去抖動

按鈕去抖動是一種技術,用於消除按鈕按下時產生的電氣噪音。這是因為按鈕按下時,接點可能會多次開關,產生多個電氣脈衝。為瞭解決這個問題,我們可以使用去抖動電路或軟體去抖動演算法。

切換LED狀態

要切換LED狀態,我們需要讀取按鈕的最後狀態(即按鈕是否按下),然後在每次按鈕按下時反轉該狀態。以下是實作此功能的Python程式碼:

from gpiozero import Button, LED
from time import sleep

led = LED(23)

def toggle_led():
    print("切換LED狀態")
    led.toggle()

button = Button(18)
button.when_pressed = toggle_led

在這段程式碼中,我們建立了一個Button物件,連線到Raspberry Pi的18號引腳,並定義了一個toggle_led函式,用於切換LED狀態。當按鈕按下時,toggle_led函式被呼叫,反轉LED的狀態。

連線麵包板和LED

圖12-4顯示瞭如何連線麵包板、按鈕和LED到Raspberry Pi。除了使用公母跳線連線Raspberry Pi到麵包板外,我們還需要一根公公跳線或固體線。

程式碼解釋

在程式碼中,我們使用gpiozero函式庫建立ButtonLED物件。Button物件連線到Raspberry Pi的18號引腳,LED物件連線到Raspberry Pi的23號引腳。當按鈕按下時,toggle_led函式被呼叫,反轉LED的狀態。

使用 Raspberry Pi 與按鈕和開關進行互動

按鈕控制 LED 的範例程式

在這個範例中,我們將使用 Raspberry Pi 的 GPIO 引腳來控制一個 LED,當按鈕被按下時,LED 會切換其狀態。

import gpiozero
from time import sleep

# 初始化按鈕和 LED
button = gpiozero.Button(17)
led = gpiozero.LED(23)

# 定義一個函式來切換 LED 的狀態
def toggle_led():
    led.toggle()

# 設定按鈕的中斷事件
button.when_pressed = toggle_led

while True:
    print("忙於做其他事情")
    sleep(2)

這個程式使用 gpiozero 函式庫來控制 GPIO 引腳,當按鈕被按下時,會呼叫 toggle_led 函式來切換 LED 的狀態。

使用兩位元切換開關

如果您想要使用兩位元切換開關,您可以按照以下步驟進行:

  1. 連線開關的中間接點和其中一端到 Raspberry Pi 的 GPIO 引腳。
  2. 使用以下程式碼來讀取開關的狀態:
import gpiozero

# 初始化開關
switch = gpiozero.Button(17)

# 讀取開關的狀態
if switch.is_pressed:
    print("開關已經被按下")
else:
    print("開關尚未被按下")

這個程式使用 gpiozero 函式庫來控制 GPIO 引腳,當開關被按下時,會印出「開關已經被按下」的訊息。

解決按鈕彈跳問題

當使用按鈕或開關時,您可能會遇到按鈕彈跳(switch bounce)的問題,這是因為按鈕或開關在被按下時會產生多次的觸發事件。為瞭解決這個問題,您可以使用以下程式碼:

import gpiozero
from time import sleep

# 初始化按鈕
button = gpiozero.Button(17)

# 設定按鈕的中斷事件
def button_pressed():
    # 在按鈕被按下後等待一段時間,以避免彈跳問題
    sleep(0.1)
    # 執行您想要的動作

button.when_pressed = button_pressed

這個程式使用 gpiozero 函式庫來控制 GPIO 引腳,當按鈕被按下時,會呼叫 button_pressed 函式來執行您想要的動作,並在按鈕被按下後等待一段時間,以避免彈跳問題。

圖表翻譯:

  flowchart TD
    A[開始] --> B[初始化按鈕和 LED]
    B --> C[設定按鈕的中斷事件]
    C --> D[讀取按鈕的狀態]
    D --> E[執行動作]
    E --> F[結束]

這個圖表展示了使用 Raspberry Pi 與按鈕和開關進行互動的流程。

連線三位式切換開關至樹莓派並偵測其位置

問題描述

您想要將一個三位式(中間為關閉位置)的切換開關連線到您的樹莓派,並在Python程式中偵測開關的位置。

解決方案

將開關連線到兩個GPIO腳位,如圖12-6所示,並使用gpiozero函式庫在Python程式中偵測開關的位置。要完成這個食譜,您需要以下元件:

*麵包板和跳線(參考「原型裝置和套件」) *迷你中間關閉三位式切換開關(參考「雜項」)

圖12-6:將三位式切換開關連線到樹莓派

開關的公共(中間)連線點連線到地線,每個開關端連線到一個GPIO腳位,並啟用內部拉高電阻。

程式碼實作

開啟編輯器並貼入以下程式碼(ch_12_switch_3_pos.py):

from gpiozero import Button

switch_top = Button(18)
switch_bottom = Button(23)

switch_position = "unknown"
while True:
    new_switch_position = "unknown"

    if switch_top.is_pressed:
        new_switch_position = "top"
    elif switch_bottom.is_pressed:
        new_switch_position = "bottom"
    else:
        new_switch_position = "center"

    if new_switch_position!= switch_position:
        # 處理開關位置變化
        switch_position = new_switch_position
        print(f"Switch position: {switch_position}")

原理解釋

  • 我們使用gpiozero函式庫建立兩個Button物件,分別代表開關的上下兩個端。
  • 在無限迴圈中,我們不斷檢查每個開關端的狀態。
  • 如果上端被按下,則開關位於「top」位置;如果下端被按下,則開關位於「bottom」位置;否則,開關位於「center」位置。
  • 如果開關的位置發生變化,我們更新switch_position變數並印出新的位置。

圖表解釋

  flowchart TD
    A[開始] --> B[初始化GPIO]
    B --> C[讀取開關狀態]
    C --> D{上端按下?}
    D -->|是| E[設定開關位置為「top」]
    D -->|否| F{下端按下?}
    F -->|是| G[設定開關位置為「bottom」]
    F -->|否| H[設定開關位置為「center」]
    E --> I[檢查位置變化]
    G --> I
    H --> I
    I -->|有變化| J[更新開關位置並印出]
    I -->|無變化| A

圖表翻譯:

此流程圖展示了程式的邏輯流程。首先,初始化GPIO腳位,然後不斷讀取開關的狀態。如果上端被按下,則設定開關位置為「top」;如果下端被按下,則設定開關位置為「bottom」;否則,設定開關位置為「center」。最後,檢查開關位置是否發生變化,如果有變化,則更新開關位置並印出新的位置。

從使用者經驗視角來看,連線按鈕和開關到樹莓派實作互動控制,能顯著提升使用者與嵌入式系統的互動體驗。本文深入探討瞭如何使用 gpiozero 函式庫簡化按鈕、兩位元切換開關和三位式切換開關的連線與控制,並解析了程式碼邏輯和電路連線。

分析段落: 我們分析了三種不同的開關型別:簡單按鈕、兩位元切換開關和三位式切換開關。針對簡單按鈕,我們利用中斷機制實作了非阻塞式的事件處理,提升了程式效率。對於兩位元切換開關,程式碼清晰地展示瞭如何讀取開關狀態。而對於三位式切換開關,我們巧妙地利用兩個 GPIO 腳位和拉高電阻,準確地判斷開關的三種不同位置。同時,程式碼中加入了去抖動的處理,避免了按鈕彈跳造成的誤觸發,提升了系統的穩定性。

前瞻段落: 隨著物聯網技術的發展,人機互動的重要性日益凸顯。未來,更複雜的互動控制需求將推動更精細的開關控制技術發展,例如結合電容式觸控感測、手勢識別等技術,實作更自然、更直觀的使用者經驗。同時,軟體層面也將持續最佳化,例如發展更低延遲、更高效的中斷處理機制,以適應更複雜的應用場景。

玄貓認為,熟練掌握這些基本的開關控制技巧,對於開發根據樹莓派的互動裝置至關重要。對於追求更進階應用的開發者,建議深入研究硬體電路設計和軟體演算法最佳化,以打造更具競爭力的產品。