การเขียนโปรแกรม 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