在嵌入式系統開發中,使用樹莓派控制外部裝置如按鈕、旋轉編碼器和鍵盤是常見的需求。本文將介紹如何使用 Python 和樹莓派的 GPIO 控制這些裝置,並提供實際的程式碼範例和電路圖解說。首先,我們會探討按鈕開關的型別、工作原理和應用,包含單極單擲、單極雙擲等,並以 Python 程式碼示範如何讀取按鈕狀態並控制 LED 燈。接著,我們會深入探討如何使用外部拉電阻來解決長距離線路連線時可能產生的訊號幹擾和誤讀問題,確保系統穩定性。此外,文章也涵蓋了旋轉編碼器的應用,包含如何偵測旋轉方向和速度,並提供程式碼示範如何使用 gpiozero 函式庫簡化開發流程。最後,我們將介紹如何連線和使用鍵盤,包含硬體接線和 Python 程式碼範例,以及如何處理鍵盤輸入。

按鈕開關的基本原理和應用

在電子工程中,按鈕開關是一種常見的元件,用於控制電路的開啟和關閉。下面我們將探討按鈕開關的基本原理和應用。

按鈕開關的型別

按鈕開關有多種型別,包括單極單擲(SPST)、單極雙擲(SPDT)和雙極雙擲(DPDT)等。其中,單極單擲開關只有一個接點,可以控制一個電路的開啟和關閉;單極雙擲開關有兩個接點,可以控制兩個電路的開啟和關閉;雙極雙擲開關有四個接點,可以控制四個電路的開啟和關閉。

按鈕開關的工作原理

按鈕開關的工作原理是透過機械接點的開啟和關閉來控制電路的通斷。當按鈕被按下時,接點會接觸,電路就會通;當按鈕被釋放時,接點會斷開,電路就會斷。

按鈕開關的應用

按鈕開關在電子工程中有廣泛的應用,例如在控制電路、通訊系統、工業控制系統等方面。下面是一個簡單的例子:

import RPi.GPIO as GPIO

# 設定GPIO模式
GPIO.setmode(GPIO.BCM)

# 設定按鈕開關的引腳
button_pin = 17

# 設定LED的引腳
led_pin = 23

# 初始化按鈕開關和LED
GPIO.setup(button_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(led_pin, GPIO.OUT)

try:
    while True:
        # 讀取按鈕開關的狀態
        button_state = GPIO.input(button_pin)

        # 如果按鈕被按下,則點亮LED
        if button_state == False:
            GPIO.output(led_pin, GPIO.HIGH)
        else:
            GPIO.output(led_pin, GPIO.LOW)

except KeyboardInterrupt:
    # 清除GPIO設定
    GPIO.cleanup()

按鈕開關的去彈跳

在實際應用中,按鈕開關可能會出現彈跳現象,即按鈕被按下時,接點會多次接觸和斷開,導致電路的通斷不穩定。為瞭解決這個問題,可以使用去彈跳技術,例如使用RC電路或軟體去彈跳演算法等。

import RPi.GPIO as GPIO
import time

# 設定GPIO模式
GPIO.setmode(GPIO.BCM)

# 設定按鈕開關的引腳
button_pin = 17

# 設定LED的引腳
led_pin = 23

# 初始化按鈕開關和LED
GPIO.setup(button_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(led_pin, GPIO.OUT)

try:
    while True:
        # 讀取按鈕開關的狀態
        button_state = GPIO.input(button_pin)

        # 如果按鈕被按下,則延遲一段時間後再讀取狀態
        if button_state == False:
            time.sleep(0.1)
            button_state = GPIO.input(button_pin)

            # 如果按鈕仍然被按下,則點亮LED
            if button_state == False:
                GPIO.output(led_pin, GPIO.HIGH)
            else:
                GPIO.output(led_pin, GPIO.LOW)

except KeyboardInterrupt:
    # 清除GPIO設定
    GPIO.cleanup()

內容解密:

上述程式碼示範瞭如何使用Python語言控制按鈕開關和LED。程式碼首先設定GPIO模式和引腳,然後初始化按鈕開關和LED。主迴圈中,程式碼讀取按鈕開關的狀態,如果按鈕被按下,則延遲一段時間後再讀取狀態,以去除彈跳現象。如果按鈕仍然被按下,則點亮LED。

圖表翻譯:

  flowchart TD
    A[開始] --> B[讀取按鈕開關狀態]
    B --> C[按鈕被按下]
    C --> D[延遲一段時間]
    D --> E[再次讀取按鈕開關狀態]
    E --> F[按鈕仍然被按下]
    F --> G[點亮LED]
    G --> H[結束]

上述Mermaid圖表示範了程式碼的流程,從開始到結束,包括讀取按鈕開關狀態、延遲一段時間、再次讀取按鈕開關狀態和點亮LED等步驟。

使用外部拉電阻以解決長距離線路的誤讀問題

在使用樹莓派(Raspberry Pi)進行電子製作時,尤其是當你需要將按鈕或開關連線到樹莓派的GPIO引腳上時,可能會遇到一個問題:當連線線路過長時,可能會出現假的觸發或誤讀。這是因為長距離的線路可能會受到外界電磁幹擾,或者是由於線路本身的特性導致訊號衰減。

解決方案

樹莓派的GPIO引腳內建有拉電阻(pull-up resistor),可以在程式中啟用或停用。當GPIO引腳作為數位輸入使用時,其內建拉電阻會保持輸入為高電位(3.3V),直到輸入被拉低到地線(GND)。然而,這些內建拉電阻相當弱(約40kΩ),對於長距離的線路可能不足夠。

使用外部拉電阻

為瞭解決這個問題,你可以使用外部拉電阻。外部拉電阻可以提供更強的拉電效果,減少長距離線路的誤讀問題。

import RPi.GPIO as GPIO
import time

# 設定GPIO模式
GPIO.setmode(GPIO.BCM)

# 設定GPIO引腳為輸入模式
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)

try:
    while True:
        # 讀取GPIO引腳的狀態
        state = GPIO.input(18)
        print(state)
        time.sleep(0.1)
except KeyboardInterrupt:
    # 清除GPIO設定
    GPIO.cleanup()

在上述程式中,GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)這一行設定了GPIO引腳18為輸入模式,並啟用了內建的拉電阻。但是,如果你需要使用外部拉電阻,你可以將pull_up_down引數設為GPIO.PUD_OFF,然後手動連線外部拉電阻。

Mermaid 圖表:使用外部拉電阻

  graph LR
    A[樹莓派 GPIO] -->|內建拉電阻|> B[輸入訊號]
    B -->|長距離線路|> C[外界幹擾]
    C -->|誤讀|> D[錯誤觸發]
    A -->|外部拉電阻|> E[穩定訊號]
    E -->|正確觸發|> F[正常工作]

圖表翻譯:

上述Mermaid圖表展示了使用外部拉電阻以解決長距離線路的誤讀問題。圖表中,樹莓派的GPIO引腳內建拉電阻可能不足以抵禦長距離線路的外界幹擾,從而導致誤讀和錯誤觸發。透過使用外部拉電阻,可以提供更強的拉電效果,穩定輸入訊號,從而實作正確的觸發和正常的工作。

使用旋轉編碼器(Quadrature Encoder)來偵測旋轉

問題描述

您想要偵測旋轉的方向和速度,例如使用旋轉編碼器(Rotary Encoder)來控制音量。

解決方案

使用兩個GPIO引腳連線旋轉編碼器(Quadrature Encoder),如圖12-10所示。

所需元件

-麵包板和跳線(見「原型設計裝置和套件」)

  • 旋轉編碼器(Quadrature型;見「雜項」)

原理

這種旋轉編碼器被稱為Quadrature編碼器,它的行為就像一對開關。當旋轉編碼器的軸被轉動時,開關的開啟和關閉順序決定了旋轉的方向。

實作步驟

  1. 連線旋轉編碼器到麵包板和Raspberry Pi的GPIO引腳。
  2. 編寫Python程式碼來讀取旋轉編碼器的輸出訊號。

程式碼實作

from gpiozero import Button
import time

# 定義GPIO引腳
input_A = Button(18)
input_B = Button(23)

# 初始化變數
old_a = True
old_b = True

def get_encoder_turn():
    # 傳回-1(逆時針),0(無運動),或+1(順時針)
    global old_a, old_b
    result = 0
    
    new_a = input_A.is_pressed
    new_b = input_B.is_pressed
    
    # 判斷旋轉方向
    if old_a!= new_a and old_b!= new_b:
        if new_a and not new_b:
            result = 1  # 順時針
        elif not new_a and new_b:
            result = -1  # 逆時針
    
    old_a = new_a
    old_b = new_b
    
    return result

# 測試旋轉編碼器
while True:
    turn = get_encoder_turn()
    if turn!= 0:
        print("旋轉方向:", turn)
    time.sleep(0.1)

討論

旋轉編碼器是一種常用的輸入裝置,可以用來控制音量、亮度等引數。透過連線旋轉編碼器到Raspberry Pi的GPIO引腳,並使用Python程式碼來讀取輸出訊號,可以實作旋轉方向和速度的偵測。

圖表翻譯:

  flowchart TD
    A[旋轉編碼器] --> B[GPIO引腳]
    B --> C[Python程式碼]
    C --> D[讀取輸出訊號]
    D --> E[判斷旋轉方向]
    E --> F[傳回旋轉方向]

內容解密:

上述程式碼使用gpiozero函式庫來讀取GPIO引腳的狀態,並使用Button類別來偵測旋轉編碼器的輸出訊號。get_encoder_turn()函式用來判斷旋轉方向,傳回-1(逆時針)、0(無運動),或+1(順時針)。在主程式中,使用while迴圈來不斷讀取旋轉編碼器的輸出訊號,並列印預出旋轉方向。

旋轉編碼器的實作

旋轉編碼器是一種可以檢測旋轉方向和次數的元件,常用於各種電子裝置中。以下是使用Python實作旋轉編碼器的程式碼範例:

import time

def get_encoder_turn():
    # 此函式模擬從旋轉編碼器取得轉動資訊
    # 實際上,您需要根據您的硬體裝置實作這個函式
    # 例如,讀取GPIO引腳的狀態來判斷旋轉方向
    # 這裡簡單地傳回一個模擬值
    return 1  # 或 -1,代表不同的旋轉方向

def rotary_encoder(new_a, new_b, old_a, old_b):
    """
    處理旋轉編碼器的邏輯。
    
    :param new_a: 當前A相的狀態
    :param new_b: 當前B相的狀態
    :param old_a: 上一次A相的狀態
    :param old_b: 上一次B相的狀態
    :return: 旋轉編碼器的結果
    """
    if new_a!= old_a or new_b!= old_b:
        if old_a == 0 and new_a == 1:
            # 根據旋轉方向計算結果
            result = (old_b * 2 - 1)
        elif old_b == 0 and new_b == 1:
            # 根據旋轉方向計算結果
            result = -(old_a * 2 - 1)
        old_a, old_b = new_a, new_b
        time.sleep(0.001)  # 短暫延遲,避免過快讀取
        return result

# 測試程式
x = 0
while True:
    change = get_encoder_turn()
    if change!= 0:
        x += change
        print(x)

內容解密:

上述程式碼展示瞭如何使用Python實作旋轉編碼器的基本功能。get_encoder_turn函式模擬從旋轉編碼器取得轉動資訊,在實際應用中,您需要根據您的硬體裝置實作這個函式。rotary_encoder函式處理旋轉編碼器的邏輯,根據A相和B相的狀態變化計算結果。

圖表翻譯:

  flowchart TD
    A[開始] --> B[讀取旋轉編碼器狀態]
    B --> C{判斷旋轉方向}
    C -->|順時針| D[計算結果]
    C -->|逆時針| E[計算結果]
    D --> F[更新計數]
    E --> F
    F --> G[列印計數]

此圖表展示了旋轉編碼器的工作流程,從讀取狀態、判斷旋轉方向到計算結果和更新計數。

四相編碼器的工作原理

四相編碼器是一種能夠檢測旋轉方向和位置的感測器。它的工作原理根據兩個接觸點A和B之間的電壓變化。當旋轉編碼器時,接觸點A和B會產生一系列的脈衝,從而可以判斷出旋轉的方向和位置。

四相編碼器的脈衝序列

當旋轉編碼器時,接觸點A和B會產生一系列的脈衝,如下表所示:

相位AB
100
201
311
410

當旋轉方向為順時針(從左到右)時,脈衝序列如下:

相位AB
100
201
311
410

當旋轉方向為逆時針(從右到左)時,脈衝序列如下:

相位AB
410
311
201
100

Python 程式實作

以下是 Python 程式實作的四相編碼器演算法:

def get_encoder_turn():
    global old_a, old_b
    a = GPIO.input(17)
    b = GPIO.input(23)
    if a == old_a and b == old_b:
        return 0
    elif a!= old_a and b!= old_b:
        if a == 1 and b == 1:
            return 1
        else:
            return -1
    else:
        if a == 1 and b == 0:
            return 1
        else:
            return -1
    old_a = a
    old_b = b

這個程式使用兩個全域變數 old_aold_b 來儲存前一次的接觸點A和B的狀態。透過比較當前的狀態和前一次的狀態,可以判斷出旋轉的方向。

測試程式

以下是測試程式:

import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)
GPIO.setup(23, GPIO.IN)

old_a = 0
old_b = 0

while True:
    turn = get_encoder_turn()
    if turn == 1:
        print("順時針旋轉")
    elif turn == -1:
        print("逆時針旋轉")
    time.sleep(0.001)

這個程式會不斷地檢查接觸點A和B的狀態,並判斷出旋轉的方向。如果旋轉方向為順時針,則印出 “順時針旋轉”;如果旋轉方向為逆時針,則印出 “逆時針旋轉”。

圖表翻譯:

  flowchart TD
    A[開始] --> B[檢查接觸點A和B的狀態]
    B --> C[判斷旋轉方向]
    C --> D[印出旋轉方向]
    D --> E[等待1毫秒]
    E --> B

這個圖表顯示了測試程式的流程。首先,檢查接觸點A和B的狀態;然後,判斷出旋轉方向;接著,印出旋轉方向;最後,等待1毫秒後再次檢查接觸點A和B的狀態。

使用Keypad與Raspberry Pi進行互動

問題描述

您想要將Keypad連線到Raspberry Pi,並實作按鍵的讀取功能。

解決方案

Keypad通常由行和列組成,每個交叉點都有一個按鈕。為了判斷哪個按鍵被按下,您需要先將所有行和列連線到Raspberry Pi的GPIO引腳。例如,對於一個4×3的Keypad,您需要4 + 3 = 7個引腳。透過設定引腳為輸出高電平並讀取每個行輸入的值,您可以確定哪個按鍵被按下。

注意:Keypad的引腳排列可能會有所不同,因此在連線前請務必確認您的Keypad的引腳排列。

所需材料

-麵包板和跳線(見“原型設計裝置和套件”)

  • 4×3 Keypad(見“雜項”)
  • 七個男性頭部引腳(見“雜項”)

連線圖

圖12-12顯示了使用SparkFun Keypad的連線圖。Keypad沒有附帶頭部引腳,因此您需要自己將頭部引腳焊接到Keypad上。

程式碼

from gpiozero import Button, DigitalOutputDevice
import time

# 定義行和列引腳
rows = [Button(17), Button(25), Button(24), Button(23)]
cols = [DigitalOutputDevice(27), DigitalOutputDevice(18), DigitalOutputDevice(22)]

# 定義按鍵對映
keys = [
    ['1', '2', '3'],
    ['4', '5', '6'],
    ['7', '8', '9'],
    ['*', '0', '#']
]

def get_key():
    # 初始化按鍵值
    key = 0
    
    # 迭代每個列
    for col_num, col_pin in enumerate(cols):
        # 設定列引腳為低電平
        col_pin.off()
        
        # 迭代每個行
        for row_num, row_pin in enumerate(rows):
            # 如果按鍵被按下,傳回按鍵值
            if row_pin.value == 1:
                key = keys[row_num][col_num]
                return key
    
    # 如果沒有按鍵被按下,傳回None
    return None

# 測試按鍵讀取功能
while True:
    key = get_key()
    if key:
        print(f"按鍵{key}被按下")
    time.sleep(0.1)

注意事項

在執行程式之前,請確保行和列引腳的連線正確。如果必要,請修改rowscols變數中的值。如果不這樣做,可能會導致GPIO輸出短路,從而損壞您的Raspberry Pi。

從使用者互動流程的最佳化角度,本文深入探討了按鈕開關、旋轉編碼器和鍵盤的原理及應用,展現了硬體輸入裝置在人機互動中的重要性。分析段落詳細比較了不同型別按鈕開關的特性,並針對按鈕彈跳問題提供了硬體和軟體的解決方案,體現了務實的工程思維。文章更進一步介紹瞭如何使用外部拉電阻提升系統穩定性,以及如何利用四相編碼器精確偵測旋轉方向和速度,展現了多層次的技術應用。然而,程式碼範例雖有助於理解,但缺乏對不同編碼器硬體規格的相容性考量。展望未來,整合觸控螢幕、語音辨識等多元輸入方式將是人機互動的重要趨勢,開發者應關注如何將這些技術與現有硬體輸入裝置融合,創造更直覺、流暢的使用者經驗。對於追求高效能互動的應用場景,建議優先採用硬體中斷和去彈跳電路,以最大限度降低延遲和誤觸發。玄貓認為,隨著嵌入式系統和物聯網的蓬勃發展,硬體輸入裝置的創新將持續推動人機互動的進化。