返回文章列表

MicroPython硬體互動與視覺化應用

本文探討 MicroPython 在硬體互動和視覺化方面的應用,涵蓋 NeoPixels LED 燈條控制、micro:bit 顯示屏操作,以及 PyBoard 彩色 LCD 顯示技術。文章提供豐富的程式碼範例,詳細說明如何控制

嵌入式系統 Web 開發

MicroPython 簡潔易學的特性,使其成為嵌入式系統開發的理想選擇,尤其在硬體互動和視覺化應用方面更具優勢。本文將以 NeoPixels、micro:bit 和 PyBoard 的 LCD160CR 為例,展示 MicroPython 如何控制 LED、顯示文字、影像和動畫,以及如何處理按鈕輸入。透過程式碼範例和詳細的解說,讀者可以快速掌握 MicroPython 的核心概念,並將其應用於實際專案中。此外,文章也探討了事件迴圈和暫停機制的重要性,以及如何避免在處理快速輸入事件時出現錯誤。對於想要深入學習 MicroPython 的開發者來說,本文提供了豐富的實用技巧和參考資訊。

NeoPixels:閃爍燈光的進階應用

NeoPixels 是 MicroPython 和 CircuitPython 中用於控制 LED 燈串的強大工具。它們可以顯示多種顏色,並透過簡單的程式碼控制。在本章中,我們將探討如何使用 NeoPixels 來實作各種視覺效果。

NeoPixels 的基本操作

要使用 NeoPixels,首先需要匯入 neopixel 模組,並例項化 NeoPixel 類別。這個類別需要兩個主要引數:連線 NeoPixels 的針腳和 NeoPixels 的數量。以 Circuit Playground Express 為例,程式碼如下:

import neopixel
from board import NEOPIXEL
np = neopixel.NeoPixel(NEOPIXEL, 10, auto_write=False)

內容解密:

  1. import neopixel:匯入 neopixel 模組,用於控制 NeoPixels。
  2. from board import NEOPIXEL:從 board 模組匯入 NEOPIXEL,它代表連線 NeoPixels 的針腳。
  3. np = neopixel.NeoPixel(NEOPIXEL, 10, auto_write=False):例項化 NeoPixel 類別,設定 NeoPixels 的數量為 10,並將 auto_write 設為 False,表示需要手動更新 NeoPixels 的狀態。

控制單個 NeoPixel

NeoPixels 可以像列表一樣被存取和修改。使用下標符號([])可以取得或設定特定位置的 NeoPixel 的顏色。

>>> np[0]
(0, 0, 0)
>>> np[0] = (32, 0, 32)
>>> np.write()

內容解密:

  1. np[0]:取得第一個 NeoPixel 的當前顏色,傳回一個包含三個整數的元組,代表紅、綠、藍三種顏色的強度。
  2. np[0] = (32, 0, 32):將第一個 NeoPixel 的顏色設定為紫色(紅色和藍色強度為 32,綠色強度為 0)。
  3. np.write():手動更新 NeoPixels 的狀態,使更改生效。

同時控制所有 NeoPixels

可以使用 fill 方法一次性設定所有 NeoPixels 的顏色。

>>> np.fill((0, 32, 32)) # 將所有 NeoPixels 設定為青色
>>> np.write()

內容解密:

  1. np.fill((0, 32, 32)):將所有 NeoPixels 的顏色設定為青色(綠色和藍色強度為 32,紅色強度為 0)。
  2. np.write():更新 NeoPixels 的狀態,使更改生效。

視覺回饋:點亮NeoPixels與micro:bit顯示

NeoPixels的色彩魔法

NeoPixels是一種能夠呈現絢麗色彩的LED燈條,透過簡單的程式控制即可創造出令人驚豔的視覺效果。以下是一個結合NeoPixels與迴圈控制,使裝置看起來像活著的範例:

import neopixel
import random
import time
from board import NEOPIXEL

np = neopixel.NeoPixel(NEOPIXEL, 10, auto_write=False)
step = 32

while True:
    for i in range(10):
        for j in range(10):
            np[j] = tuple((max(0, val - step) for val in np[j]))
        r = random.randint(0, 255)
        g = random.randint(0, 255)
        b = random.randint(0, 255)
        np[i] = (r, g, b)
        np.write()
        time.sleep(0.05)

內容解密:

  1. 初始化NeoPixels:使用neopixel.NeoPixel類別初始化10個NeoPixels,並設定auto_write=False以避免每次更改都立即寫入。
  2. 迴圈控制:進入無限迴圈,遍歷每個NeoPixel。
  3. 調暗其他LED:對每個NeoPixel,將其目前的RGB值降低step(32),確保不會低於0,以實作漸暗效果。
  4. 隨機色彩:為目前選中的NeoPixel生成隨機的RGB色彩值。
  5. 寫入並延遲:將新的色彩值寫入NeoPixels,並暫停0.05秒以控制效果速度。

這個範例創造了一個隨機變色的迴圈燈效,可以透過調整time.sleep的值來改變效果的速度,或是修改step的值來控制燈光漸暗的速度和「尾巴」的長度。

micro:bit的文字、影像與動畫

micro:bit擁有一個5x5的紅色LED矩陣顯示屏,可以用來呈現文字、影像和簡單的動畫。

滾動文字

from microbit import display, Image

display.scroll("Hello, World!")

內容解密:

  1. display.scroll方法:用於在micro:bit的顯示屏上滾動顯示文字。
  2. 引數控制:可以透過delay引數控制滾動速度,wait引數決定是否等待滾動完成,loop引數設定是否迴圈滾動,monospace引數控制字元寬度。

例如,以下程式碼實作了一個快速、迴圈滾動的單空格訊息:

display.scroll("Hello!", delay=80, wait=False, loop=True, monospace=True)

顯示靜態文字

如果希望文字一個接一個地顯示而不是滾動,可以使用display.show方法:

display.show("Danger!")

內容解密:

  1. display.show方法:用於在micro:bit的顯示屏上顯示文字或影像。
  2. 引數控制:支援與scroll方法類別似的引數,如waitclear,但不包含monospace

影像顯示

micro:bit內建了一個Image類別,可以用來顯示預設或自定義的影像。

顯示預設影像

display.show(Image.HAPPY)

內容解密:

  1. Image類別:提供了多種預設影像,如HAPPYSAD等。
  2. display.show方法:用於顯示選定的影像。

自定義影像

你可以透過建立Image例項來建立自定義影像:

my_picture = Image(
    '33333:'
    '36663:'
    '36963:'
    '36663:'
    '33333:')
display.show(my_picture)

內容解密:

  1. 字串表示法:使用數字(0-9)代表LED的亮度,冒號(:)表示行結束。
  2. 自定義影像:根據字串描述生成對應的影像,並顯示在micro:bit上。

這些範例展示瞭如何利用micro:bit和NeoPixels創造出豐富的視覺效果,從簡單的文字滾動到複雜的影像和動畫,都能為你的專案增添更多的互動性和趣味性。

使用 micro:bit 的 Image 類別建立與操作影像

micro:bit 的 Image 類別提供了一個強大的方式來建立和操作影像,使其能夠在 micro:bit 的 LED 顯示屏上顯示。一個 Image 例項不一定要受限於顯示屏的尺寸,這使得它可以用於建立更大尺寸的遊戲或應用程式。

建立 Image 物件

建立 Image 物件有兩種主要方法:使用字串和使用 bytearray

使用字串建立 Image

from microbit import display, Image

# 建立一個 5x5 的影像
image = Image("00000:"
              "90009:"
              "09090:"
              "90009:"
              "00000")

display.show(image)

使用 bytearray 建立 Image

from microbit import display, Image

# 使用 bytearray 建立一個 10x10 的影像
buf = bytearray(x % 10 for x in range(100))
image = Image(10, 10, buf)

display.show(image.crop(3, 4, 5, 5))

內容解密:

  1. bytearray(x % 10 for x in range(100)):這行程式碼生成了一個包含 100 個元素的 bytearray,每個元素的值在 0 到 9 之間,代表了影像中每個畫素的亮度。
  2. Image(10, 10, buf):利用生成的 bytearray,建立了一個 10x10 的影像。
  3. image.crop(3, 4, 5, 5):從原始影像中裁剪出一個 5x5 的子影像,並將其顯示在 micro:bit 的 LED 顯示屏上。

操作 Image 物件

Image 物件提供了多種方法來操作影像,包括:

  • copy():傳回影像的副本。
  • invert():傳回一個新影像,其畫素亮度與原始影像相反。
  • fill(value):將所有畫素設定為指定的亮度值。
  • get_pixel(x, y):取得指定位置畫素的亮度。
  • set_pixel(x, y, value):設定指定位置畫素的亮度。
  • shift_left(n)shift_right(n)shift_up(n)shift_down(n):將影像向指定方向移動 n 個畫素。
  • blit(src, x, y, w, h):將源影像的一部分複製到當前影像中。

使用 shift 方法實作滾動效果

from microbit import display, Image

# 建立一個影像
image = Image("00000:"
              "90009:"
              "09090:"
              "90009:"
              "00000")

# 向右滾動影像
for _ in range(5):
    display.show(image)
    image = image.shift_right(1)

內容解密:

  1. image.shift_right(1):將影像向右移動 1 個畫素。
  2. 在迴圈中不斷顯示和更新影像,實作滾動效果。

製作動畫

透過使用迭代器物件傳回一系列 Image 物件,可以在 micro:bit 上建立動畫。

使用內建的動畫幀列表

from microbit import display, Image

display.show(Image.ALL_CLOCKS, delay=50, wait=False, loop=True)

自定義動畫

from microbit import display, Image
import random
import array

def animation():
    while True:
        blinkenlights = array.array('b', [random.randint(0, 9) for _ in range(25)])
        yield Image(5, 5, blinkenlights)

display.show(animation())

內容解密:

  1. animation() 函式是一個生成器,不斷生成新的隨機影像。
  2. display.show(animation()) 將生成器傳回的影像序列顯示為動畫。

PyBoard 彩色 LCD 顯示技術詳解

LCD160CR 顯示控制基礎

在 MicroPython 的世界中,控制 LCD160CR 這類別彩色 LCD 顯示幕是一項有趣且實用的技術。首先,我們需要使用 LCD160CR 類別來例項化一個代表實體 LCD 裝置的物件,並指定裝置的連線方式(“X” 或 “Y”)。一旦例項化,裝置就會啟動並顯示 MicroPython 的標誌,表示它正在運作。

import lcd160cr
lcd = lcd160cr.LCD160CR('X')
lcd.erase()

內容解密:

  • lcd160cr.LCD160CR('X'):例項化 LCD160CR 物件,指定連線埠為 ‘X’。
  • lcd.erase():清除螢幕上的內容。

REPL 輸出重定向至 LCD 顯示

將 REPL(Read-Eval-Print Loop)輸出重定向至 LCD 顯示,可以讓開發者直接在 LCD 上與 MicroPython 互動。

import pyb
uart = pyb.UART('XA', 115200)
pyb.repl_uart(uart)

內容解密:

  • pyb.UART('XA', 115200):設定 UART 通訊埠 ‘XA’,波特率為 115200。
  • pyb.repl_uart(uart):將 REPL 輸出重定向至指定的 UART。

字型設定與文字輸出

LCD160CR 提供了多種字型和文字輸出的控制方法。可以使用 set_font 方法來改變字型大小和樣式。

lcd.set_font(3, scale=0, bold=1, trans=0, scroll=1)
lcd.write("Hello, World!")

內容解密:

  • lcd.set_font(3, scale=0, bold=1, trans=0, scroll=1):設定字型為 3 號,縮放比例為 0,加粗效果為 1,背景透明度為 0,並啟用平滑滾動效果。
  • lcd.write("Hello, World!"):在 LCD 上輸出 “Hello, World!"。

文字顏色與背景顏色設定

可以透過 set_text_color 方法來改變文字和背景的顏色。

text_colour = lcd.rgb(255, 128, 0)
background = lcd.rgb(0, 128, 255)
lcd.set_text_color(text_colour, background)
lcd.write("Hello, World!")

內容解密:

  • lcd.rgb(255, 128, 0)lcd.rgb(0, 128, 255):分別生成文字顏色和背景顏色的 RGB 值。
  • lcd.set_text_color(text_colour, background):設定文字和背景的顏色。

圖形輸出與基本繪圖

LCD160CR 不僅支援文字輸出,也提供了基本的圖形繪製功能,如設定畫素、繪製矩形和線條。

lcd.set_pixel(x, y, colour)
lcd.rect(20, 20, 40, 40)

內容解密:

  • lcd.set_pixel(x, y, colour):在座標 (x, y) 處設定畫素的顏色。
  • lcd.rect(20, 20, 40, 40):繪製一個矩形,其左上角座標為 (20, 20),寬度和高度均為 40。

簡易 Mondrian 風格繪圖範例

下面是一個簡單的範例,展示如何使用 LCD160CR 繪製 Mondrian 風格的圖案。

import lcd160cr
from random import randint, choice, uniform

# 省略部分程式碼...

class Node:
    # 省略部分程式碼...

    def draw(self, x, y, w, h):
        # 省略部分程式碼...

內容解密:

  • 使用遞迴的方式繪製 Mondrian 風格的圖案。
  • Node 類別代表圖案中的一個節點,具有顏色、深度和子節點等屬性。

輸入與感測:裝置互動的核心

在裝置與使用者互動的過程中,輸入與感測扮演著至關重要的角色。不同於傳統的計算裝置,如鍵盤、滑鼠或觸控螢幕,嵌入式裝置通常需要透過其他方式與使用者進行互動。MicroPython 為這些裝置提供了豐富的輸入與感測功能,使得裝置能夠對外部環境變化做出反應。

按鈕與電容式觸控

按鈕是最常見的輸入裝置之一。不同裝置具有不同數量的按鈕,有些裝置甚至支援電容式觸控功能。以 micro:bit 為例,其具有兩個按鈕(A 和 B),分別對應 button_abutton_b 物件。這些按鈕物件具有相同的方法,使得開發者能夠輕鬆地處理按鈕事件。

事件迴圈與暫停

在處理輸入事件時,事件迴圈(event loop)是至關重要的。事件迴圈是一種不斷迴圈的程式碼,用於等待和處理輸入事件。然而,由於事件迴圈的執行速度遠快於人類的反應速度,因此需要加入暫停機制,以避免多次觸發同一事件。

from microbit import *

position = 2
while True:  # 事件迴圈
    sleep(60)  # 暫停
    if button_a.is_pressed():
        display.clear()
        position = max(0, position - 1)
    elif button_b.is_pressed():
        display.clear()
        position = min(4, position + 1)
    display.set_pixel(position, 2, 9)

程式碼解析

  1. while True:建立一個無限迴圈,作為事件迴圈的主體。
  2. sleep(60):在每次迴圈中暫停 60 毫秒,降低迴圈的執行頻率,以適應人類的反應速度。
  3. if button_a.is_pressed():elif button_b.is_pressed()::檢查按鈕 A 和 B 是否被按下,並根據按下的按鈕調整 position 的值。
  4. display.set_pixel(position, 2, 9):在指定的位置顯示一個畫素點。

為何需要暫停?

如果沒有 sleep(60) 這行程式碼,事件迴圈將會以極快的速度執行。這意味著在你按下按鈕的短暫時間內,事件迴圈已經執行了多次,從而導致 position 的值被多次修改,最終可能只能將畫素點移動到最左邊或最右邊的位置。加入暫停後,事件迴圈的執行速度變慢,能夠正確地捕捉到每次按鈕按下事件。