บทความนี้เป็นการแนะนำบอร์ด Maker Pi PICO ของ Cytron (ภาพที่ 1) ที่ติดตั้งไมโครคอนโทรเลอร์ Raspberry Pi PICO พร้อมทั้งบอร์ดขยายการใช้งานที่มีอุปกรณ์พื้นฐานที่จำเป็นต่อการฝึกฝนเขียนโปรแกรมและใช้งานจริง เช่น หลอดแอลอีดี ช่องอ่านการ์ดหน่วยความจำ (micro SD-Card) หรือ ลำโพง เป็นต้น ซึ่งนอกเหนือจากการแนะนำบอร์ดแล้ว บทความนี้กล่าวถึงการติดตั้งและใช้งาน CircuitPython ซึ่งเป็นไพธอนที่นำ MicroPython มาปรับปรุงเพื่อใช้งานกับอุปกรณ์ของ Adafruite และของบริษัทอื่น ๆ ส่วนผู้ที่วนใจบทความที่ใช้กับ MicroPython ทางทีมงานขอแนะนำให้ศึกษาจากเว็บของอาจารย์ดร.เรวัต ศิริโภคาภิรมย์ ต่อไปนี้ซึ่งมีรายละเอียดที่ครบครันกว่าพวกเรามาก
- MicroPython for RP2040 Pico
- RPi Pico RP2040 Code Examples
- PIO Programming
- PIO Signaling and Measurement
- นอกจากนี้มีบทความส่วนของ CircuitPython ด้วยเช่นกันในบทความ CircuitPython for Pico RP2040
บอร์ด Maker Pi PICO
บอร์ด Maker Pi PICO ของ Cytron ประกอบไปด้วย 2 ส่วน คือ
- ตัวบอร์ดไมโครคอนโทรลเลอร์ Raspberry Pi Pico (ดังภาพที่2)
- บอร์ดขยายพอร์ตของบอร์ดไมโครคอนโทรลเลอร์ Raspberry Pi Pico
บนตัวบอร์ขยายมีสวิตช์ RUN ดังภาพที่ 3 สำหรับใช้กดเมื่อต้องการให้เริ่มรันโปรแกรมใหม่ หรือทำการรีเซ็ตระบบใหม่ ซึ่งมีประโยชน์เวลาต้องการอัพโหลดโปรแกรมเข้าบอร์ด โดยปกติต้องถอดสายและเสียบใหม่ แต่ด้วยการมีปุ่มนี้ทำให้สามารถกดปุ่ม BOOT0 บนบอร์ดไมโครคอนโทรลเลอร์ค้างไว้ แล้วกดปุ่ม RUN เพื่อเริ่มทำงานใหม่เข้าโหมดโปรแกรมชิพ
นอกจากสวิตช์ RUN ยังมีสวิตช์สำหรับให้ใช้งานโดยเชื่อมต่อกับ GP20, GP21 และ GP22 ดังภาพที่ 4 โดยแต่ละปุ่มเป็นแบบ Active Low เนื่องจากต่อวงจร Pull-up เอาไว้
ส่วนที่พวกเราชอบมากที่สุดคือ การมีคอนเน็กเตอร์สำหรับ ESP-01 อยู่บนบอร์ด ดังภาพที่ 5 ซึ่งสื่อสารผ่านทาง UART2 ด้วยขาGP17 และ GP16
ส่วนถัดมาคือปลอดแอลอีดีแบบ RGB ที่ต่ออยู่กับขา GP28 ดังภาพที่ 6 ทำให้สามารถเขียนโปรแกรมสั่งเปิดหรือปิดหลอดแอลอีดี โดยกำหนดค่าสีของการแสดงผลได้
ทางด้านล่างของบอร์ดมีลำโพงแบบบัซเซอร์มาให้ พร้อมสวิตช์เปิด/ปิดการทำงานของลำโพงดังภาพที่ 7 โดยต่ออยู่กับ GP18
ช่องเสียบหูฟังแบบสเตอริโอดังภาพที่ 8 ที่ต่อเข้ากับขา GP18 และ GP19
สุดท้าย คือ มีช่องอ่าน micro SD ติดตั้งมาให้เป็นที่เรียบร้อยดังภาพที่ 9 ซึ่งต่อผ่านบัส SPI ด้วยขา GP10, GP11, GP12, GP13, GP14 และ GP15 ดังรายละเอียดต่อไปนี้
- GP10 ทำหน้าที่ SCK1 สำหรับส่งสัญญาณนาฬิกาในการสื่อสารระหว่างกัน
- GP11 ทำหน้าที่ SDO1 หรือ CMD สำหรับส่งข้อมูลออก
- GP12 ทำหน้าที่ SDI1 หรือ DAT0 สำหรับรับข้อมูลเข้า
- GP13 ทำหน้าที่ DAT1
- GP14 ทำหน้าที่ DAT2
- GP15 ทำหน้าที่ CSn1 หรือ CD/DAT3 สำหรับขา CS เพื่อใช้เริ่มต้นหรือสิ้นสุดการสื่อสาร
ติดตั้ง CircuitPython
CircuitPython เป็นไพธอนที่พัฒนาต่อจาก MicroPython ซึ่งสามารถเข้าไปดาวน์โหลดได้จากเว็บ CircuitPython จะแสดงหน้าหลักดังภาพที่ 10
จากหน้าหลักให้คลิกที่ตัวเลือก Downloads เพื่อเข้าสู่หน้าดาวน์โหลดโปรแกรมดังภาพที่ 11
จากภาพที่ 11 จะพบว่า ในหน้านี้มีรายการบอร์ดให้เลือกมากมาย หรือถ้าไม่ต้องการเลื่อนเพื่อหาบอร์ดที่ต้องการ ผู้ใช้สามารถพิมพ์ชื่อของบอร์ดที่ใช้งาน และระบบจะทำการค้นหา ถ้าพบหมายความว่าบอร์ดนั้นสามารถใช้ CircuitPython ได้ โดยในที่นี้เลือกบอร์ด Pico
เมื่อคลิกเข้าหน้าของ Pico By Raspberry Pi จะมีรายการรุ่นของ CircuitPython ให้ดาวน์โหลด โดยเวลาที่ผู้เขียนเข้าถึงเป็นรุ่น 7.0.0 ให้คลิกดาวน์โหลดเพื่อดาวน์โหลดไฟล์ .UF2 ดังภาพที่ 11
เมื่อดาวน์โหลดเก็บไว้ในเครื่องเป็นที่เรียบร้อยให้ทำการรีบูตเข้าโหมดโปรแกรมชิพ ด้วยการกดปุ่ม BOOTSEL ในภาพที่ 12 แล้วกด Run หลังจากนั้นปล่อยปุ่ม RUN ตามด้วยปุ่ม BOOTSEL
เมื่อเข้าโหมดโปรแกรมชิพ ระบบจะแสดงโฟลเดอร์ RPI-RP2 ดังภาพที่ 13 ให้ลากไฟล์ที่ดาวน์โหลดมาไปวางในโฟลเดอร์ดังาภที่ 14 เพื่อเป็นการส่งไฟล์ไปให้ไมโครคอนโทรเลอร์เพื่อโปรแกรมตัวเอง
เมื่อลากเสร็จและชิพถูกโปรแกรมเรียบร้อยจะถูกเปลี่ยนเป็นโหมดรันโปรแกรมจะแสดงโฟลเดอร์สำหรับเก็บข้อมูลที่มีพื้นที่ประมาณ 1.0MB ใช้เก็บโปรแกรมหรือข้อมูลดังภาพที่ 14
ขั้นตอนต่อไปเป็นการใช้ thonny เขียนโปรแกรมเพื่อทดลองหาค่าจำนวนเฉพาะและอ่านข้อมูลเกี่ยวกับบอร์ดมาแสดงผล โดยในโปรแกรม Thonny ให้กำหนดการทำงานเป็น CircuitPython (generic) และเลือกพอร์ตสื่อสารให้ถูกต้อง ซึ่งปกติพอร์ตสื่อสารของบอร์ดจะชื่อ Pico – CircuitPython.CDC control ดังภาพที่ 15
โค้ดตัวอย่างโปรแกรมเป็นดังนี้ และผลลัพธ์ของการทำงานเป็นดังภาพที่ 16
##################################################################################
# coreInfo
# esp8266/esp32/rp2/stm32f4/stm32f7/micro:bit information
##################################################################################
import gc
import os
import sys
import time
##################################################################################
# system setting
##################################################################################
gc.enable()
gc.collect()
##################################################################################
# function
##################################################################################
def isPrime(x):
i = 2
while (i < x):
if x%i == 0:
return False
i = i+1
if (i == x):
return True
return False
def testPrimeNumber(maxN):
counter = 0
t0 = time.monotonic_ns()
for n in range(2, maxN):
if isPrime(n):
counter+=1
t1 = time.monotonic_ns()
print("Found {} in {} milliseconds.".format(counter,abs(t1-t0)/1000000))
def show_hw_info():
uname = os.uname()
mem_total = gc.mem_alloc()+gc.mem_free()
free_percent = "("+str((gc.mem_free())/mem_total*100.0)+"%)"
alloc_percent = "("+str((gc.mem_alloc())/mem_total*100.0)+"%)"
stat = os.statvfs('/flash')
block_size = stat[0]
total_blocks = stat[2]
free_blocks = stat[3]
rom_total = (total_blocks * block_size)/1024
rom_free = (free_blocks * block_size)/1024
rom_usage = (rom_total-rom_free)
rfree_percent = "("+str(rom_free/rom_total*100.0)+"%)"
rusage_percent = "("+str(rom_usage/rom_total*100.0)+"%)"
print("Platform ......:",sys.implementation)
print("Version .......:",sys.version)
print("Memory")
print(" total ......:",mem_total/1024,"KB")
print(" usage ......:",gc.mem_alloc()/1024,"KB",alloc_percent)
print(" free .......:",gc.mem_free()/1024,"KB",free_percent)
print("ROM")
print(" total ......:", rom_total,"KB" )
print(" usage ......:", rom_usage,"KB",rfree_percent )
print(" Free .......:", rom_free,"KB",rusage_percent )
print("system name ...:",uname.sysname)
print("node name .....:",uname.nodename)
print("release .......:",uname.release)
print("version .......:",uname.version)
print("machine .......:",uname.machine)
##################################################################################
# main program
##################################################################################
if __name__=='__main__':
try:
testPrimeNumber(2000)
show_hw_info()
except KeyboardInterrupt:
pass
print("end of program")
สรุป
จากบทความนี้จะพบว่า ถึงแม้จะเป็นภาษาไพธอนเหมือนกันแต่คลังไลบรารีมีความแตกต่างกัน ดังนั้น ต้องศึกษารายละเอียดการใช้งานเพิ่มเติม แต่อย่างไรก็ดี ถ้าเขียนโปรแกรมด้วยตนเองเป็นหลักจะสามารถนำโค้ดนั้นกลับมาใช้ได้โดยไม่ต้องกังวลเรื่องการขึ้นอยู่กับแพลตฟอร์มการทำงาน เช่นเดียวกับฟังก์ขันการหาค่าจำนวนเฉพาะที่พวกเรานำมาใช้ในตัวอย่างโปรแกรมเป็นต้น ส่วนการใช้งานกับ I/O สามารถอ่านเพิ่มเติมได้จากบทความที่ได้ระบุไว้ข้างต้น และในส่วนของแหล่งอ้างอิง สุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ
แหล่งอ้างอิง
(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อวันที่ 2021-09-23, 2021-12-13