返回文章列表

樹莓派按鈕開關控制與應用

本文介紹如何使用樹莓派的 GPIO 與按鈕、開關進行互動,包含偵測按鈕按下、使用中斷處理按鈕事件、切換 LED 狀態以及處理三位式切換開關等應用,並提供相應的 Python 程式碼範例與流程圖解說。

硬體開發 嵌入式系統

透過 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。
  • 我們進入一個無限迴圈,持續檢查按鈕是否被按下。
  • 當按鈕被按下時,我們印出「按鈕被按下」的訊息。

圖表翻譯:

此圖表展示了程式的流程,從初始化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)用於模擬程式執行其他任務的過程。

圖表翻譯:

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

使用按鈕切換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 函式來執行您想要的動作,並在按鈕被按下後等待一段時間,以避免彈跳問題。

圖表翻譯:

這個圖表展示了使用 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變數並印出新的位置。

圖表解釋

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title 樹莓派按鈕開關控制與應用

package "Python 應用架構" {
    package "應用層" {
        component [主程式] as main
        component [模組/套件] as modules
        component [設定檔] as config
    }

    package "框架層" {
        component [Web 框架] as web
        component [ORM] as orm
        component [非同步處理] as async
    }

    package "資料層" {
        database [資料庫] as db
        component [快取] as cache
        component [檔案系統] as fs
    }
}

main --> modules : 匯入模組
main --> config : 載入設定
modules --> web : HTTP 處理
web --> orm : 資料操作
orm --> db : 持久化
web --> cache : 快取查詢
web --> async : 背景任務
async --> fs : 檔案處理

note right of web
  Flask / FastAPI / Django
end note

@enduml

圖表翻譯:

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

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

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

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

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