การเขียนโปรแกรม MicroPython สำหรับบอร์ด BBC Micro:bit V2#

Keywords: Python 3, MicroPython, BBC Micro:bit v2 (nRF52833)


ไมไครไพธอนสำหรับไมโครบิต#

บอร์ดไมโครบิต (อ่านบทความแนะนำบอร์ด Micro:bit) สามารถนำมาใช้งานได้กับเฟิร์มแวร์ของไมโครไพธอน (MicroPython) ดังนั้นผู้ใช้สามารถเขียนโค้ดด้วยภาษา Python ได้ บทความนี้จะกล่าวถึง การทดลองใช้งานไมโครไพธอนสำหรับบอร์ดไมโครบิต เจาะจงเฉพาะ "เวอร์ชัน 2" (BBC Micro:bit v2) ซึ่งมีชิป nRF52833 เป็นตัวประมวลผลหลัก

รูป: บอร์ดไมโครบิต v2

รูป: ตัวอย่างโมดูล Edge Connector ที่สามารถนำมาใช้กับบอร์ดไมโครบิต

 

ไฟล์เฟิร์มแวร์ของไมโครไพธอน (MicroPython Firmware: .hex) สำหรับบอร์ด MicroPython Micro:bit v2 สามารถดาวน์โหลดได้จาก

เวอร์ชันที่ได้ลองใช้ในขณะเขียนบทความนี้ คือ MicroPython for Micro:bit v2.1.1 ซึ่งใช้โค้ดของไมโครไพธอน MicroPython v1.18 เป็นพื้นฐานในการทำงาน

การติดตั้งเฟิร์มแวร์ของไมโครไพธอน ก็ทำได้ง่าย

  • วิธีแรก: เมื่อเสียบสาย USB เข้ากับบอร์ดไมโครไพธอนแล้ว จะมองเห็น USB Flash Drive ที่มีชื่อว่า MICROBIT จากนั้นให้ลากไฟล์เฟิร์มแวร์ .hex ไปยังไดร์ฟดังกล่าว บอร์ดไมโครบิตจะทำการติดตั้งเฟิร์มแวร์โดยอัตโนมัติ
  • วิธีที่สอง: เปิดใช้งาน MicroPython Editor (v3) และผู้ใช้สามารถลองเขียนโค้ดโดยใช้เว็บเบราว์เซอร์ได้ และสามารถจำลองการทำงานของโค้ดได้ โดยยังไม่จำเป็นต้องมีอุปกรณ์ฮาร์ดแวร์จริง และเมื่อเชื่อมต่อกับบอร์ดไมโครบิตกับคอมพิวเตอร์ของผู้ใช้ผ่านทางพอร์ต USB ก็สามารถติดตั้งเฟิร์มแวร์ได้เช่นกัน (ใช้วิธีการที่เรียกว่า WebUSB)

หากต้องการดูรายละเอียดเกี่ยวกับคำสั่งต่าง ๆ สำหรับการเขียนโค้ดไมโครไพธอน สามารถดูได้จาก

 


ขั้นตอนการคอมไพล์ซอร์สโค้ด MicroPython for Micro:bit v2#

โดยปรกติแล้ว ผู้ใช้สามารถดาวน์โหลดไฟล์เฟิร์มแวร์ของไมโครไพธอนเพื่อนำมาใช้และติดตั้งใช้งานกับบอร์ดไมโครคอนโทรลเลอร์ได้ง่าย แต่สำหรับผู้ที่อยากจะลองคอมไพล์ซอร์สโค้ดของไมโครไพธอน (โดยใช้ Ubuntu Linux) ก็มีขั้นตอนดังนี้

1) ทำคำสั่งติดตั้งโปรแกรมที่จำเป็น และตรวจสอบเวอร์ชันของโปรแกรม

$ cat /etc/os-release | head -5
PRETTY_NAME="Ubuntu 22.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.2 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy

$ sudo apt update -y
$ sudo apt install -y python3 python3-dev 
$ sudo apt install -y build-essential git mercurial cmake ninja-build
$ sudo apt install -y gcc-arm-none-eabi binutils-arm-none-eabi

$ python3 -V
Python 3.10.6

$ ninja --version
1.10.1

$ cmake --version
cmake version 3.22.1

$ arm-none-eabi-gcc --version
arm-none-eabi-gcc (15:10.3-2021.07-4) 10.3.1 20210621 (release)

2) ทำคำสั่งดาวน์โหลดซอร์สโค้ดของไมโครไพธอนสำหรับไมโครบิตจาก Github Repo

$ mkdir $HOME/MicroPython && cd $HOME/MicroPython
$ git clone https://github.com/microbit-foundation/micropython-microbit-v2
$ cd micropython-microbit-v2/

3) ทำคำสั่งดาวน์โหลดโมดูลไลบรารีต่าง ๆ ที่จำเป็นต่าง ๆ สำหรับไมโครไพธอน ได้แก่ lib/codal และ /lib/micropython

# Download the following modules
# -> https://github.com/lancaster-university/codal/
# -> https://github.com/micropython/micropython/
$ git submodule update --init

4) ทำคำสั่งเพื่อสร้างไฟล์เฟิร์มแวร์ของไมโครไพธอนสำหรับบอร์ดไมโครบิต v2 ถ้าทำได้สำเร็จ จะได้ไฟล์ MICROBIT.hex อยู่ภายใต้ไดเรกทอรี ./src

# Build the mpy-cross program
$ make -C lib/micropython/mpy-cross
# Build the MicroPython firmware for Micro:bit v2
$ cd src
$ make

รูป: ตัวอย่างข้อความเอาต์พุต (บางส่วน) จากการทำคำสั่งเพื่อสร้างไฟล์เฟิร์มแวร์ของไมโครไพธอนสำหรับบอร์ดไมโครบิต v2

 


การใช้งาน MicroPython Editor for Micro:bit V2#

เปิดใช้งานเว็บเบราว์เซอร์ไปยัง https://python.microbit.org/v/3 และจะเห็นได้ว่า มีการสร้างโปรเจกต์ (Project) พร้อมโค้ดตัวอย่างไว้ให้แล้ว ซึ่งอยู่ในไฟล์ main.py ผู้ใช้สามารถกดปุ่ม Simulator เพื่อเปิดใช้งานตัวจำลองการทำงานของโค้ด ซึ่งจะมองเห็นรูปบอร์ดไมโครบิตเสมือนจริง ถ้ากดปุ่ม Play / Run บอร์ดไมโครบิตก็จะเริ่มทำงานตามคำสั่งของโค้ดตัวอย่าง

รูป: โปรเจกต์และโค้ดตัวอย่างในไฟล์ main.py เพื่อเริ่มต้นใช้งาน

รูป: การใช้งาน Simulator เพื่อจำลองการทำงานของบอร์ดไมโครบิต

รูป: การเชื่อมต่อระหว่างบอร์ดไมโครบิตกับ MicroPython Editor ผ่านทาง WebUSB

รูป: การอัปโหลดเฟิร์มแวร์และโค้ดตัวอย่างไปยังบอร์ดไมโครบิตที่เชื่อมต่อกับคอมพิวเตอร์ของผู้ใช้

ข้อสังเกต: การอัปโหลดโค้ดไปยังบอร์ดไมโครบิตในครั้งแรก จะใช้เวลานานกว่าครั้งถัดไป เนื่องจากจะต้องมีการติดตั้งไฟล์เฟิร์มแวร์ของไมโครไพธอน (.hex) ในครั้งแรก แล้วจึงอัปโหลดโค้ดในไฟล์ main.py ไปยังระบบไฟล์ของไมโครไพธอนที่อยู่ในหน่วยความจำ Flash ของชิปไมโครคอนโทรลเลอร์

 


โค้ดตัวอย่างที่ 1: การแสดงรูปกราฟบน 5x5 LED Matrix Display#

from microbit import *

# Code in a 'while True:' loop repeats forever
while True:
    display.show( Image.HEART )
    sleep( 1000 )
    display.scroll( 'Hello' )

ตัวอย่างโค้ดนี้ เริ่มต้นด้วยประโยคคำสั่งในบรรทัดแรกที่จะใช้คำสั่งต่าง ๆ ของไลบรารี (หรือโมดูล) ที่มีชื่อว่า microbit ซึ่งสามารถดูคำสั่ง คลาส และโมดูลต่าง ๆ ที่เกี่ยวข้องได้จาก microbit

from microbit import *

ถัดไปเป็นประโยคคำสั่ง while True: ซึ่งจะทำคำสั่งภายในบล็อกของโค้ดที่เกี่ยวข้องซ้ำไปเรื่อย ๆ ได้แก่

  • display.show(Image.HEART) ที่แสดงรูปสัญลักษณ์ "หัวใจ" (Heart) บนจอแสดงผลแบบ 5x5 LED Matrix ของบอร์ดไมโครบิต
  • ถัดไปเป็นคำสั่ง sleep(1000) เพื่อหน่วงเวลาไว้ประมาณ 1000 มิลลิวินาที
  • ทำคำสั่ง display.scroll('Hello') ที่จะแสดงข้อความ Hello บนส่วนที่แสดงผลแบบเมทริกซ์ขนาด 5x5 LEDs และให้ข้อความดังกล่าว เลื่อนไปทางซ้ายจนครบทุกตัวอักขระ

ในภาษาไพธอน ข้อความใด ๆ ที่ตามหลังสัญลักษณ์ # ในบรรทัดเดียวกัน จะถือว่าเป็นคำอธิบายโค้ด (Code Comment) ไม่มีผลต่อการทำงานของโค้ด

ถ้าต้องการบันทึกไฟล์ main.py มายังคอมพิวเตอร์ของผู้ใช้ ให้กดปุ่ม Save ... Save Python script (แต่ถ้ากดปุ่ม Save จะได้ไฟล์ .hex)

ไฟล์ .py ที่ได้ดาวน์โหลดมา สามารถนำไปเปิดใช้งานได้อีกครั้งใน MicroPython Editor บนหน้าเว็บเบราว์เซอร์ โดยกดปุ่ม Open แล้วคลิกเลือกไฟล์ที่ต้องการเปิดใช้งานและอยู่ในเครื่องคอมพิวเตอร์ของผู้ใช้

ข้อสังเกต: Image.HEART ในคลาส Image ได้มีการกำหนดค่าพิกเซลไว้แล้ว สำหรับการแสดงรูปสัญลักษณ์ "หัวใจ" ด้วยคำสั่ง display.show(...) และรูปสัญลักษณ์อื่นที่สามารถเลือกใช้ได้ สามารถดูรายการได้จาก Images เช่น รูปกราฟิกแสดงอารมณ์ความรู้สึก

  • Image.HAPPY (รู้สึกมีความสุข)
  • Image.SMILE (รูปหน้ายิ้ม)
  • Image.SAD (รู้สึกเศร้า)
  • Image.ANGRY (รู้สึกโกรธ)
  • Image.SURPRISED (รู้สึกประหลาดใจ)

 


โค้ดตัวอย่างที่ 2#

โค้ดตัวอย่างถัดไปสาธิตการใช้คำสั่งจากโมดูล machine และ gc เช่น

  • machine.unique_id() อ่านค่าหมายเลขของบอร์ด (Unique Board ID) ซึ่งจะได้เป็นอาร์เรย์ของข้อมูลไบต์
  • machine.freq() อ่านค่าความถี่ของซีพียูที่ใช้ในการประมวลผล (หน่วยเป็น Hz)
  • gc.enable() เปิดใช้งานการตรวจสอบและจัดการหน่วยความจำประเภท Heap
  • gc.mem_alloc() ตรวจสอบดูว่า มีหน่วยความจำประเภท Heap ถูกใช้ไปแล้วกี่ไบต์
  • gc.mem_free() ตรวจสอบดูว่า มีหน่วยความจำประเภท Heap ที่ยังไม่ได้ใช้เหลืออยู่กี่ไบต์
  • gc.collect() ตรวจสอบและทำการคืนพื้นที่ของหน่วยความจำใน Heap ที่มีการนำไปใช้งานเมื่อทำคำสั่งต่าง ๆ ของโปรแกรม แต่ไม่ได้ใช้แล้ว
import machine
import gc

# Enable automatic garbage collection (GC)
gc.enable() 

# Show the free heap memory (in bytes)
print( "Heap memory (free): %d" % gc.mem_free())

# Get free heap memory (in bytes) 
heap_free = gc.mem_free()

# Set the threshold for the GC: a half of free heap memory
threshold = heap_free//2
gc.threshold(threshold)

# Get the threshold for GC
print( "GC threshold: %d"  % gc.threshold() )

# Get the machine ID (a bytearray, converted to a hex string)
id = "".join([hex(b)[2:] for b in machine.unique_id()] )
print( "Board ID: %s" % id)

# Get the CPU frequency in MHz
print( "CPU freq:. %d MHz" % int(machine.freq()/1e6) )

# Get the allocated heap memory (in bytes)
print( "Heap memory (allocated): %d bytes" % gc.mem_alloc() )

# Run a garbage collector to free some heap memory
gc.collect() 

# Show the free heap memory (in bytes)
print( "Heap memory (free): %d" % gc.mem_free() )

ถ้าอัปโหลดโค้ดตัวอย่างนี้ไปยังบอร์ดไมโครบิต (กดปุ่ม Send to micro:bit) แล้วเปิดรับข้อความผ่านทาง Serial (กดปุ่ม show | hide serial) จะมองเห็นข้อความเอาต์พุตจากการทำงานของไมโครไพธอน

ส่วนที่รับส่งข้อความได้เรียกว่า MicroPython REPL ผู้ใช้สามารถพิมพ์และทำคำสั่งของไมโครไพธอนได้ ถ้ากดปุ่ม Ctrl+D เป็นการรีเซตการทำงานของไมโครไพธอน แต่ถ้ากดปุ่ม Ctrl+C เป็นการหยุดการทำงานของไมโครไพธอนในขณะที่กำลังทำคำสั่งในไฟล์ main.py

รูป: ตัวอย่างข้อความเอาต์พุตที่ได้รับจากบอร์ดไมโครบิตผ่านทาง WebUSB - Serial

รูป: ตัวอย่างการทำคำสั่ง help("modules") ในช่อง MicroPython REPL

การใช้ฟังก์ชันสำหรับการเขียนโค้ดไมโครบิต ได้มีการแบ่งออกเป็นกลุ่มคำสั่งดังนี้

microbit accelerometer audio bluetooth button compass log display filesystem i2c image machine microphone music neopixel power radio random speaker speech spi uart utime

 


โค้ดตัวอย่างที่ 3#

โค้ดตัวอย่างถัดไปสาธิตการใช้คำสั่งของโมดูล microbit เช่น

  • microbit.display.set_pixel( x, y, brightness ) เพื่อกำหนดค่าของพิกเซลที่ตำแหน่ง (x,y) บนแผงแสดงผลแบบเมทริกซ์ 5x5 พิกเซล และให้มีค่า brightness อยู่ในช่วง 0..9 ซึ่งเป็นระดับของความสว่างของ LED ที่ตำแหน่งดังกล่าว
  • microbit.display.clear() กำหนดให้ค่าพิกเซลทั้งหมดเป็น 0
from microbit import *

# Set brightness to 9 (maximum).
brightness = 9 

while True:
    # For each position: 0..24
    for pos in range(25): 
        # Compute the (x,y) coordinate from the position value.
        y = pos // 5 # row index
        x = pos % 5  # column index
        # Turn on the pixel at (x,y).
        display.set_pixel( x, y, brightness )
        sleep( 100 )
    # Clear the LED matrix display.
    display.clear()

 


โค้ดตัวอย่างที่ 4#

โค้ดตัวอย่างถัดไปสาธิตการใช้คำสั่งของโมดูล random และ microbit เช่น

  • microbit.pin0.read_analog() อ่านค่าตัวเลขจำนวนเต็มจากขา P0 ของไมโครบิต เมื่อใช้งานเป็นขาแอนะล็อก-อินพุต
  • random.seed( value ) กำหนดค่าเริ่มต้น (Seed Value) เพื่อใช้งานการสร้างตัวเลขจำนวนเต็มแบบสุ่ม
  • random.randint( m, n ) สร้างเลขสุ่มที่เป็นเลขจำนวนเต็มที่มีค่าอยู่ในช่วง m ถึง n

โค้ดในตัวอย่างนี้ เริ่มต้นด้วยการกำหนดค่าที่เรียกว่า Seed Value สำหรับการสร้างเลขสุ่ม โดยใช้ค่าที่ได้จากการอ่านขาอินพุตแบบแอนะล็อกที่ขา P0 แต่ไม่ได้ต่อใช้งาน (และอาจมีการใช้นิ้วมือสัมผัสที่บริเวณ Pad ของขาดังกล่าว)

ถัดจากนั้นจะสุ่มตัวเลขสำหรับพิกัด (x,y) ในช่วงตัวเลข 0 ถึง 4 และความสว่าง brightness (เลือกตัวเลขให้อยู่ในช่วง 3 ถึง 9) เพื่อทำให้พิกเซลที่พิกัดดังกล่าวสว่างขึ้น ถ้ามีค่าเดิมของพิเซลนั้นเป็น 0

from microbit import *
import random 

# Use the analog value read from Pin0 to 
# set the seed for the pseudo-random number generator.
value = pin0.read_analog()
random.seed( value )

on_pixel_count = 0
display.clear()
while True:
    # Select randomly a value from 0..4 for x and y, respectively.
    x = random.randint( 0, 4 )
    y = random.randint( 0, 4 )
    # Select randomly a value from 3..9 for the LED brightness.
    brightness = random.randint( 3, 9 )
    # Check whether the LED at (x,y) is OFF.
    if display.get_pixel(x,y) == 0:
        print( 'Turn on the pixel (%d,%d)' % (x,y) )
        display.set_pixel(x, y, brightness)
        on_pixel_count += 1
        if on_pixel_count == 25:
            print( 'Clear LED matrix display' )
            display.clear()
            on_pixel_count = 0
        sleep(100)

รูป: ตัวอย่างการจำลองการทำงานของโค้ด

 


โค้ดตัวอย่างที่ 5#

โค้ดตัวอย่างถัดไปสาธิตการแสดงค่าพิกเซลบนแผงแสดงผลแบบเมทริกซ์ (LED Matrix Display) ขนาด 5x5 โดยการสุ่มค่าตัวเลขที่ได้กำหนดไว้แล้วในอาร์เรย์ bits เพื่อสร้างเป็นรูปกราฟิก (Image) และใช้ในการแสดงผล

การสุ่มค่าพิกเซลและอัปเดตสถานะจะเกิดขึ้นเมื่อมีการเขย่าบอร์ดไมโครบิต ในการตรวจสอบเหตุการณ์ดังกล่าว จะใช้คำสั่ง accelerometer.was_gesture('shake') แต่ถ้าไม่มีการเขย่า ระดับความสว่าง (LED Brightness) หรือค่าของพิกเซลที่มีค่ามากกว่า 0 จะค่อย ๆ ลดลงเป็น 0

การอ่านและกำหนดค่าของพิกเซลที่พิกัด (x,y) จะใช้คำสั่งต่อไปนี้

  • display.get_pixel(x,y)
  • display.set_pixel(x,y,brightness)
from microbit import *
import random

bits = ["90000", "09000", "00900", "00090", "00009"]

def shuffle( choices ):
    n = len(choices)
    result = []
    while True:
        p = random.randint(0,n-1)
        if choices[p] not in result:
            result.append(choices[p])
            if len(result) == n:
                break
    return result

def reduce_brightness():
    for x in range(5):
        for y in range(5):
            brightness = display.get_pixel(x,y)
            if brightness > 0:
                display.set_pixel(x,y,brightness-1)

last_update = running_time()
while True:
    if accelerometer.was_gesture('shake'):
        bits = shuffle( bits )
        display.show( Image( ":".join(bits) ) )
    else:
        now = running_time()
        if now - last_update >= 200:
            last_update = now
            reduce_brightness()

 

หากจะแสดงรูปกราฟิก โดยเปลี่ยนไปตามระยะเวลาที่กำหนด เช่น แสดงรูปหัวใจขนาดปรกติ (Image.HEART) และขนาดเล็กลง (Image.HEART_SMALL) ก็มีตัวอย่างดังนี้

from microbit import *

# Create an array of two Image objects.
images = [ Image.HEART, Image.HEART_SMALL ]

# Add an additional Image object (single-dot image).
images.append(
    Image('00000:'
          '00000:'
          '00900:'
          '00000:'
          '00000') )

while True:
    for image in images:
        display.show(image)
        sleep(250)

หรือเขียนโค้ดในอีกรูปแบบหนึ่งดังนี้ ก็ได้ผลเหมือนกัน

from microbit import *

# Create an array of three Image objects.
images = [ 
    Image('09090:99999:99999:09990:00900'), # Heart
    Image('00000:09090:09990:00900:00000'), # Small Heart
    Image('00000:00000:00900:00000:00000')  # Single Centered Dot 
]

while True:
    for image in images:
        display.show(image)
        sleep(250)

 


โค้ดตัวอย่างที่ 6#

โค้ดตัวอย่างถัดไปสาธิตการใช้คำสั่งของโมดูล microbit เช่น

  • microbit.temperature() อ่านค่าอุณหภูมิภายในชิปไมโครคอนโทรลเลอร์ (หน่วยเป็นองศาเซลเซียส)
  • microbit.running_time() อ่านค่าเวลาของระบบตั้งแต่ไมโครไพธอนเริ่มทำงาน (หน่วยเป็นมิลลิวินาที)
  • microbit.sleep(...) หยุดรอให้เวลาผ่านไปตามาระยะเวลาที่กำหนด (หน่วยเป็นมิลลิวินาที)
  • microbit.run_every(...) เปิดให้มีการเรียกฟังก์ชันซ้ำไปเรื่อย ๆ เว้นระยะเวลาตามที่กำหนดไว้ (หน่วยเป็นมิลลิวินาที)
  • microbit.button_a.was_pressed() ตรวจสอบดูว่า ได้มีการกดปุ่ม A บนบอร์ดไมโครบิตหรือไม่
  • microbit.display.show(...) แสดงสัญลักษณ์ เช่น Image.HEART หรือ รูปหัวใจบนเมทริกซ์ของ LEDs ขนาด 5x5
  • microbit.display.clear() เคลียร์การแสดงผลบนแผงเมทริกซ์ LEDs ขนาด 5x5
from microbit import *

# Read on-chip temperature
temp_celsius = temperature()
print( "CPU temperature: %d deg°C" % temp_celsius )

blinking = True

def heart_blink():
    global blinking
    if blinking: # If heart blinking is enabled...
        # show elapsed time in msec
        print("Timestamp: %d msec" % running_time() )
        display.show(Image.HEART)
        sleep(500)
        display.clear()

# Start a periodic task which calls the heart_blink() function
# every 1000 msec.
run_every(heart_blink, ms=1000)

while True:
    if button_a.was_pressed():
        print("Button A was pressed.")
        # Toggle the blinking status
        blinking = not blinking
    sleep(1000)

รูป: ตัวอย่างข้อความเอาต์พุตที่ได้รับจากบอร์ดไมโครบิตผ่านทาง Serial

 


โค้ดตัวอย่างที่ 7: การตรวจสอบการตั้งขึ้นของบอร์ดไมโครบิต#

ถ้าจะแสดงรูปลูกศร (Arrows) ซึ่งมีทิศทางทั้งหมด 8 ทิศ แล้วให้แสดงรูปสัญลักษณ์ลูกศรไปตามลำดับ ก็มีตัวอย่างโค้ดดังนี้

from microbit import *

# Create an array of Image objects.
images = Image.ALL_ARROWS  # There are 8 arrow images in total.
print( "Number of arrows: %d" % len(images) )

while True:
    for image in images:
        display.show(image)
        sleep(200)

ถัดไปลองเขียนโค้ดใหม่ โดยกำหนดเงื่อนไขว่า ถ้าบอร์ดอยู่ในแนวตั้งฉากกับระนาบหรือพื้นราบ แล้วให้แสดงสัญลักษณ์ Arrow หรือ ลูกศรในทิศทางชี้ลงพื้น ก็มีตัวอย่างการเขียนโค้ดดังนี้ เริ่มต้นด้วยการอ่านค่าจากเซนเซอร์วัดความเร่งแบบสามแกน (3-axis Accelerometer) ของบอร์ดไมโครบิตในแกน x, y, z ตามลำดับ โดยใช้คำสั่งต่อไปนี้

  • accelerometer.get_x()
  • accelerometer.get_y()
  • accelerometer.get_z()

ค่าที่อ่านได้ในแต่ละแกน จะอยู่ในช่วง +/-2g และได้เป็นเลขจำนวนเต็มในช่วง -2000 .. +2000 (มีหน่วยเป็น milli-g หรือ หนึ่งในพันของค่า ) แล้วนำมาเปรียบเทียบค่าตามเงื่อนไขที่ได้กำหนดไว้เป็นตัวอย่าง

from microbit import *

while True:
   # Read data from the 3-axis accelerometer.
   x = accelerometer.get_x()
   y = accelerometer.get_y()
   z = accelerometer.get_z()
   print( "Accel %d %d %d" % (x,y,z) )
   if abs(x) < 250 and y > 750 and abs(z) < 250:
       display.show( Image.ARROW_S)
   else:
       display.clear()
   sleep(200)

หรือจะลองเปรียบเทียบกับการใช้คำสั่ง accelerometer.current_gesture() ซึ่งจะได้ข้อความระบุทิศทางของบอร์ดไมโครบิต เช่น "up", "down", "left", "right", "face up", "face down" เป็นต้น และนำมาตรวจสอบในเงื่อนไขดูว่า ตรงกับ "up" (บอร์ดอยู่ในลักษณะ "ตั้งขึ้น") หรือไม่

from microbit import *

while True:
   x = accelerometer.get_x()
   y = accelerometer.get_y()
   z = accelerometer.get_z()
   print( "Accel %d %d %d" % (x,y,z) )
   gesture = accelerometer.current_gesture()
   if gesture == "up":
       display.show( Image.ARROW_S )
   else:
       display.clear()
   sleep(200)

รูป: บอร์ดไมโครบิตแสดงรูปกราฟิกเป็นสัญลักษณ์ "ลูกศรชี้ลง"

 


โค้ดตัวอย่างที่ 8: การสร้างสัญญาณเสียงดนตรี (Melody Sound Effect)#

บอร์ดไมโครบิต เวอร์ชันสอง มีวงจรสร้างสัญญาณเสียง (Speaker) และสำหรับการเขียนโค้ดด้วยไมโครไพธอน ก็มีคำสั่งในโมดูล audio และ speaker ให้ใช้งาน เช่น การสร้างสัญญาณเสียงดนตรีเป็นเมโลดี้ และมีการสร้างเสียงตัวอย่าง (Builtin Sound Effects) ไว้แล้ว เช่น

  • Sound.GIGGLE
  • Sound.HAPPY
  • Sound.HELLO
  • Sound.MYSTERIOUS
  • Sound.SAD
  • Sound.SLIDE
  • Sound.SOARING
  • Sound.SPRING
  • Sound.TWINKLE
  • Sound.YAWN

โค้ดตัวอย่างต่อไปนี้ สาธิตการสร้างสัญญาณเสียงดนตรี เมื่อมีการเขย่าบอร์ด และสุ่มเลือกจากรายการเสียงดนตรีในอาร์เรย์

from microbit import *
from random import choice

sound_list = [ Sound.GIGGLE, Sound.HAPPY, Sound.HELLO,
    Sound.MYSTERIOUS, Sound.SAD, Sound.SLIDE, Sound.SOARING,
    Sound.SPRING, Sound.TWINKLE, Sound.YAWN ]

# Turn on speaker
speaker.on()

while True: 
    if accelerometer.was_gesture("shake"): 
        sound = choice(sound_list)
        audio.play( sound )

ถ้าจะลองสร้างเสียงเป็นสัญญาณแจ้งเตือน (Alarm Sound) ก็ลองใช้คำสั่งเพื่อสร้างชุดข้อมูลเสียงในรูปแบบของ AudioFrame (ข้อมูลเสียงหนึ่งเฟรม) ซึ่งจะประกอบด้วยข้อมูลขนาด 8 บิต (Unsigned Bytes) จำนวน 32 ตัวเลข

ในโค้ดตัวอย่างต่อไปนี้ มีการสร้างฟังก์ชัน audio_frame() เพื่อกำหนดค่าให้ข้อมูลในหนึ่งเฟรม โดยใช้รูปแบบฟังก์ชันรูปคลื่นไซน์

from microbit import *
import math

# Turn on speaker
speaker.on()

# Create an AudioFrame object with 32 unsigned bytes.
def audio_frame(f=11):
    frame = audio.AudioFrame()
    n = len(frame)
    for i in range(n):
        value = int(127.5*(1+math.sin(math.pi*f*i/16)))
        frame[i] = value
    return frame

# Create a list of 64 audio frames
samples = [ audio_frame(11)] * 64

alarm = True  # Enable sound alarm.
while True: 
    # Press the button A to enable/disable alarm.
    if button_a.was_pressed(): 
        alarm = not alarm     # Toggle alarm mode.
    if alarm:
        audio.play( samples ) # Play sound effect.
        sleep(1000)

 


โค้ดตัวอย่างที่ 9: การวัดระดับเสียง (Ambient Sound Level Measurement)#

ถ้าจะลองอ่านค่าอินพุตจากไมโครโฟนของบอร์ดไมโครบิต ก็มีคำสั่งจากโมดูล
microphone ของ microbit ให้ใช้งาน ลองมาดูตัวอย่างถัดไปซึ่งสาธิตการวัดระดับเสียงด้วยไมโครโฟนของบอร์ดไมโครบิต โดยใช้คำสั่ง microbit.microphone.sound_level() แล้วแสดงระดับเสียงที่วัดได้ โดยใช้รูปกราฟิกบนส่วนแสดงผล 5x5 LED Matrix

from microbit import *

SQUARE_LARGE = Image.SQUARE_SMALL + Image.SQUARE

while True: 
    sound_level = microphone.sound_level() 
    display.clear()
    if sound_level < 5:
        display.set_pixel( 2, 2, 9 )
    elif sound_level < 20:
        display.show( Image.SQUARE_SMALL )
    elif sound_level < 40:
        display.show( Image.SQUARE )
    else:
        display.show( SQUARE_LARGE )
    sleep(50)

 


โค้ดตัวอย่างที่ 10: การใช้งานโมดูล NeoPixel / RGB LED (WS2812B)#

โค้ดในตัวอย่างนี้สาธิตการกำหนดสีแบบ RGB (สีแดง-เขียว-น้ำเงิน) ให้กับโมดูลที่เรียกว่า "NeoPixel" ซึ่งใช้ชิป WS2812B เป็นตัวควบคุมและให้แสงจาก RGB LED โดยเลือกใช้เพียงหนึ่งพิกเซลเท่านั้น

โมดูล NeoPixel สามารถใช้แรงดันไฟเลี้ยง +3.3V (ขา 3V) จากบอร์ดไมโครบิตได้ (ถ้ามีจำนวนพิกเซลไม่มากและใช้ปริมาณกระแสน้อย โดยรวมไม่เกิน 100mA)

ในการต่อวงจร ได้เลือกใข้ขา Pin0 เป็นขา GPIO นำไปเชื่อมต่อกับขา DIN (Data Input) ของ WS2812B เพื่อใช้ในการส่งข้อมูลบิตจำนวน (24 บิต) และกำหนดสี RGB (อย่างละ 8 บิต) ให้กับโมดูลดังกล่าว

ในการเขียนโค้ดไมโครไพธอน เพื่อกำหนดสีให้พิกเซลของ NeoPixel ก็มีคำสั่งจากโมดูล neopixel และคลาสชื่อ NeoPixel ให้ใช้งานได้

from microbit import *
import neopixel

# Use Pin0 to control the NeoPixel module
NEOPIXEL_PIN = pin0

# Use a single-pixel NeoPixel module
NUM_PIXELS = 1

# Create a NeoPixel object
# and use bpp=3 for RGB mode (red,green,blue)
np = neopixel.NeoPixel(NEOPIXEL_PIN, NUM_PIXELS, bpp=3)
np.clear()

# Create a list of three predefined colors (tuples)
colors = [ (255,0,0), (0,255,0), (0,0,255) ]

while True:
    for color in colors:
        # Set the new color 
        np.fill( color ) 
        # Send the color bits to NeoPixel
        np.write()
        sleep(1000)

ถ้าจะลองกำหนดสี RGB แบบสุ่มตัวเลขจำนวนเต็มในช่วง 0 ถึง 255 จากเซตหรืออาร์เรย์ของค่าตัวเลข เช่น [255, 191, 127, 63, 31, 0] ก็มีแนวทางดังนี้

from microbit import *
import neopixel
from random import *

# Use Pin0 to control the NeoPixel module
NEOPIXEL_PIN = pin0

# Use a single-pixel NeoPixel module
NUM_PIXELS = 1

# Create a NeoPixel object
# and use bpp=3 for RGB mode (red,green,blue)
np = neopixel.NeoPixel(NEOPIXEL_PIN, NUM_PIXELS, bpp=3)
np.clear()

# Create a lambda function to randomly select a value from a list.
rand_value = lambda choices: choices[randrange(0,len(choices))]

# Create a list of predefined values
values = [255,191,127,63,31,0]

while True:
    # Select random values for RGB
    red   = rand_value( values )
    green = rand_value( values )
    blue  = rand_value( values )
    # Write a tuple of RGB value to the pixel buffer
    np[0] = color = (red,green,blue)
    print( color )
    # Update the color of the NeoPixel module
    np.write()
    sleep(1000)

รูป: ตัวอย่างการใช้งานโมดูล NeoPixel / WS2812B ร่วมกับบอร์ดไมโครบิต

 

ถ้าจะลองเปลี่ยนมาใช้โมดูล RGB แบบที่ไม่ใช้ไอซี WS2812B แต่มีขาควบคุม 3 ขา ก็จะต้องใช้วิธีการสร้างสัญญาณเอาต์พุตแบบ PWM (Pulse Width Modulation) ซึ่งเป็นสัญญาณดิจิทัลที่มีความถี่หรือคาบคงที่ แต่ปรับเลือกความกว้างของพัลส์ช่วงที่มีลอจิกเป็น High ได้ (High Pulse Width ก็คือ ความกว้างของพัลส์ช่วงที่มีลอจิกเป็น High หรือมีค่าลอจิกเป็น 1)

ในตัวอย่างนี้ ได้เลือกใช้ขา Pin0, Pin1, Pin2 สำหรับการสร้างสัญญาณที่มีรูปแบบ PWM จำนวน 3 ช่องสัญญาณ (สำหรับแต่ละสีของ RGB) แล้วนำไปใช้กับโมดูล RGB ที่ทำงานงานแบบ Active-High ความกว้างของพัลส์ของสัญญาณ PWM ทั้งสามช่อง จะเป็นตัวกำหนดระดับความสว่างของแต่ละสี และเกิดการผสมสี RGB ที่แตกต่างกันได้

ตัวอย่างการเขียนโค้ดไมโครไพธอนมีดังนี้ โดยจะสุ่มตัวเลขจำนวนเต็มในช่วง 0..1023 (ความละเอียดเท่ากับ 10 บิต) จากอาร์เรย์ที่ได้กำหนดค่าไว้เป็นตัวอย่าง (ใช้คำสั่ง random.choice()) แล้วนำไปใช้กำหนดค่าที่เรียกว่า Pulse Width ของสัญญาณ PWM โดยใช้คำสั่ง write_analog(...) ของแต่ละขา GPIO ที่ได้เลือกมาใช้งาน

from microbit import *
import neopixel
import random

# Specify the GPIO pins for PWM outputs
RGB_PINS = [pin0,pin1,pin2]

# A list of predefined PWM values (10-bit): 0..1023
values = [1023,511,255,0]

while True:
    for pin in RGB_PINS:
        # Choose randomly a value from the list
        value = random.choice( values )
        # Update the PWM pin
        pin.write_analog( value )
    sleep(1000)

รูป: ตัวอย่างการใช้งานโมดูล RGB LED ร่วมกับบอร์ดไมโครบิต

 


โค้ดตัวอย่างที่ 11: การอ่านค่าจากโมดูล Rotary Encoder#

ตัวอย่างถัดไปสาธิตการอ่านค่าจากโมดูล Rotary Encoder ซึ่งจะได้สัญญาณแบบพัลส์ จำนวน 2 ช่อง เมื่อมีการหมุนเปลี่ยนตำแหน่งของด้ามจับหรือแกนหมุน (Rotating Shaft) สัญญาณทั้งสองช่อง (ตั้งชื่อว่า A และ B) จะมีลักษณะต่างเฟสกันประมาณ 90 องศา ความกว้างของพัลส์จะขึ้นอยู่กับความเร็วในการหมุนที่ด้ามจับของโมดูล

การตรวจสอบการเปลี่ยนแปลงของพัลส์ สามารถใช้คำสั่ง machine.time_pulse_us(...) เพื่อวัดความกว้างของพัลสที่เกิดขึ้นและมีค่าลอจิกเป็น High ได้ (ค่า Pulse Level เท่ากับ 1) ค่าที่วัดได้จะมีหน่วยเป็นไมโครวินาที และสามารถกำหนดระยะเวลาสูงสุดในการรอให้เกิดพัลส์ได้ (เช่น กำหนดค่า Timeout ให้ไม่เกิน 50000 ไมโครวินาที)

ในการตรวจสอบการเกิดการพัลส์ในแต่ละครั้งจากโมดูล Rotary Encoder จะเลือกใช้สัญญาณจากขา A และดูว่า สัญญาณที่ขา B มีค่าลอจิกเป็นอย่างไรเมื่อเกิดเหตุการณ์ดังกล่าว แล้วนำมากำหนดเป็นเงื่อนไข เพื่อเพิ่มหรือลดค่าของตัวแปรที่เป็นตัวนับ (count) และให้มีค่าอยู่ในช่วง 0..9 เท่านั้น

ในโค้ดตัวอย่างนี้ได้เลือกใช้ขา Pin12 และ Pin16 นำไปต่อกับขา A และ B ของโมดูล Rotary Encoder ตามลำดับ และใช้แรงดันไฟเลี้ยง 3.3V จากบอร์ดไมโครบิต

from microbit import *
import machine
from micropython import const
import time

# Set min. and max. pulse width values.
PW_MIN = const(5000)  # value in microseconds
PW_MAX = const(50000) # value in microseconds

# Use Pin12 and Pin12 for A and B signals respectively.
PIN_A = pin12
PIN_B = pin16

# Disable pull-up/pull-down on the A and B pins.
PIN_A.set_pull( PIN_A.NO_PULL )
PIN_B.set_pull( PIN_B.NO_PULL )

MAX_COUNT = 10
count = 0
display.show( str(count) )

while True:
    # Measure the pulse width (with timeout).
    t_pw = machine.time_pulse_us( PIN_A, 1, PW_MAX )
    # Detect a pulse with a valid pulse width.
    if t_pw >= PW_MIN and t_pw < PW_MAX:
        if PIN_B.read_digital():
            # Increment the counter value.
            count = count+1
        else:
            # Decrement the counter value.
            count = count-1
        # Limit the counter value to 0..(MAX_COUNT-1).
        count = (MAX_COUNT+count) % MAX_COUNT
        # Send the counter value as a string to the serial.
        print(count)
        # Show the digit on the LED matrix display.
        display.show( str(count) )

รูป: ตัวอย่างการต่อวงจรใช้งานโมดูล Rotary Encoder ร่วมกับบอร์ดไมโครบิต

 


ตัวอย่างโค้ดไมโครไพธอน#

นอกจากโค้ดตัวอย่างเพื่อการสาธิตการเขียนไมโครไพธอนสำหรับไมโครบิตและได้นำเสนอไปแล้วนั้น ก็มีไฟล์ตัวอย่างโค้ดเอาไว้ศึกษาเพิ่มเติมดังต่อไปนี้

  • demo_show_all_predefined_images.py: แสดงรูปกราฟิกของไมโครไพธอนบนส่วนแสดงผลแบบ 5x5 LED Matrix
  • demo_dice_shake.py: ตรวจสอบการเขย่าบอร์ด แล้วแสดงสัญลักษณ์เหมือนการทอยลูกเต๋าอิเล็กทรอนิกส์ ซึ่งมีค่าที่เป็นไปได้ 1-6
  • demo_create_chessboard_image.py: กำหนดค่าให้พิกเซลบน 5x5 LED Matrix ที่มีลักษณะเหมือนตารางหมากรุก
  • demo_draw_lower_upper_triangular_matrix.py: แสดงรูปกราฟิกบนส่วนแสดงผลแบบ 5x5 LED Matrix ที่มีลักษณะเป็นเมทริกซ์สามเหลี่ยมล่างหรือเมทริกซ์สามเหลี่ยมบน
  • demo_buttons_touch_logo_rotate_arrow.py: ตรวจสอบการสัมผัสที่บริเวณ Logo หรือ กดปุ่ม A หรือ B ของบอร์ดไมโครบิต แล้วแสดงรูปลูกศร (Arrow) และหมุนไปในทิศทางทวนหรือตามเข็มนาฬิกาตามเงื่อนไขที่ได้กำหนดไว้
  • demo_adc_pin0_bar_graph.py: อ่านค่าจากอินพุตแบบแอนะล็อกที่ขา Pin0 แล้วนำมาแสดงผลในรูปแบบกราฟแท่ง (Bargraph) บนส่วนแสดงผลแบบ 5x5 LED Matrix
  • demo_light_sensor_bar_graph.py: อ่านค่าจากเซนเซอร์แสงบนบอร์ดไมโครบิต แล้วนำมาแสดงผลบนส่วนแสดงผลแบบ 5x5 LED Matrix ในลักษณะรูปกราฟแท่ง

 


กล่าวสรุป#

บทความนี้ได้นำเสนอตัวอย่างการเขียนโค้ดไมโครไพธอน (MicroPython) สำหรับบอร์ดไมโครบิต "เวอร์ชันสอง" (BBC Micro:bit v2) และสาธิตการเขียนโค้ด โดยใช้ซอฟต์แวร์ Web-based MicroPython Editor (v3) ซึ่งสามารถจำลองการทำงานได้เสมือนจริง และอัปโหลดโค้ดไปยังบอร์ดไมโครบิตที่เชื่อมต่อกับคอมพิวเตอร์ของผู้ใช้ ผ่านทาง WebUSB

 


This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Created: 2023-03-12 | Last Updated: 2023-04-04