[TH] MicroPython : pyb USB_HID/USB_VCP

บทความนี้กล่าวถึงการใช้ความสามารถเกี่ยวกับ USB HID ของบอร์ดไมโครคอนโทรลเลอร์ STM32F411CEU6 ผ่านทาง MicroPython ในคลาส pyb ซึ่งทีมงานเราได้แรงบันดาลใจจากบทความ MicroPython for STM32F411 Black Pill: Embedded Programming Style ของอาจารย์ดร.เรวัต ศิริโภคาภิรมย์ ว่าแล้วมาเริ่มคอมไพล์และอัพโหลดเฟิร์มแวร์กันได้เลยครับ (อ่านรายละเอียดได้จากบทความของอาจารย์ดร.เรวัต ศิริโภคาภิรมย์ ได้เลยครับ) โดยเราใช้บอร์ดเลียนแบบ WeAct STM32F411CEU6 ดังภาพที่ 1 ซึ่งเมื่อติดตั้ง MicroPython จะมีคลาส pyb ให้ใช้งาน

ภาพที่ 1 บอร์ดสำหรับการทดลองในบทความนี้

สวัสดี

มาเริ่มกันด้วยทดสอบรันโปรแกรมสวัสดีที่อ่านรายละเอียดของบอร์ด และทดสอบวนรอบหาจำนวนเฉพาะกันหน่อยดีกว่า โค้ดโปรแกรมเป็นตามนี้ครับ และตัวอย่างผลลัพธ์เป็นดังภาพที่ 2

import os
import gc
import sys
import time as tm
import machine as mc

gc.enable()
gc.collect()

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 = tm.ticks_ms() #tm.monotonic()
    for n in range(2, maxN):
        if isPrime(n):
            counter+=1
    t1 = tm.ticks_ms() #tm.monotonic()
    print("testPrineNumner({}) ... Found {} in {} msecs.".format(maxN,counter,abs(t1-t0)))


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[0])
    print("Version .......:",sys.version)
    print("Frequency")
    print("   CPU ........: {}Hz".format(mc.freq()[0]))
    print("   AHB ........: {}Hz".format(mc.freq()[1]))
    print("   APB1 .......: {}Hz".format(mc.freq()[2]))
    print("   APB2 .......: {}Hz".format(mc.freq()[3]))
    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)

if __name__=='__main__':
    show_hw_info()
    testPrimeNumber(2000)

ภาพที่ 2 ตัวอย่างผลลัพธ์จากโปรแกรม “สวัสดี”

จากภาพที่ 2 จะได้ว่า MicroPython ที่เราติดตั้งเป็นรุ่น 1.17-134-gcv99ca986 ที่คอมไพล์ไปเมื่อวันที่ 2021-11-01 มีหน่วยความจำประเภท SRAM ให้ใช้งาน 85KB ถูกใช้งานไปแล้ว 4.609375KB เหลือใช้งาน 80.375KB ส่วน ROM เหลือให้ใช้เก็บข้อมูลและโปรแกรม 42.0kb

ส่วนกรณีที่ต้องการอ่านข้อมูลในเชิงลึกกว่านั้น เช่น ID, DEVID, REVID หรือค่าตำแหน่งของหน่วยความจำ เป็นต้น สามารถใช้เมธอด info() ของคลาส pyb ได้ดังตัวอย่างต่อไปนี้ และจะได้ตัวอย่างดังผลลัพธ์ภาพที่ 3

import pyb
print(pyb.info())
ภาพที่ 3 ตัวอย่างผลลัพธ์จากเมธอด info() ของคลาส pyb

จากการรายงานในภาพที่ 3 จะพบว่า MicroPython เองใช้ LFS หรือ LittleFS สำหรับบริหารจัดการพาร์ทิชันและดิสค์ใน Flash ROM ซึ่งมีพื้นที่ให้ใช้งาน 43008 ไบต์ ซึ่งตรงกันกับตัวอย่าง ‘สวัสดี’ ส่วนค่า S, H, P1 และ P2 จะพบว่าเป็นค่าความเร็วของสัญญาณนาฬิกาของ CPU, AHB, APB1 และ APB2 และมีเธรดเดียว

เมื่อตรวจสอบดูรายการ modules ที่บอร์ดรองรับด้วยคำสั่งต่อไปนี้

help(“modules”)

จะแสดงรายการคลาสทั้งหมดที่ใช้งานได้ของ PyBoard ดังภาพที่ 4

ภาพที่ 4 โมดูลทั้งหมดของ microPython สำหรับ STM32F411CEU6

รายการคลาส เมธอด และค่าคงที่ภายใน pyb มีดังนี้

object <module 'pyb'> is of type module
  __name__ -- pyb
  fault_debug -- <function>
  bootloader -- <function>
  hard_reset -- <function>
  info -- <function>
  unique_id -- <function>
  freq -- <function>
  repl_info -- <function>
  wfi -- <function>
  disable_irq -- <function>
  enable_irq -- <function>
  stop -- <function>
  standby -- <function>
  main -- <function>
  repl_uart -- <function>
  country -- <function>
  usb_mode -- <function>
  hid_mouse -- (1, 2, 4, 8, b'\x05\x01\t\x02\xa1\x01\t\x01\xa1\x00\x05\t\x19\x01)\x03\x15\x00%\x01\x95\x03u\x01\x81\x02\x95\x01u\x05\x81\x01\x05\x01\t0\t1\t8\x15\x81%\x7fu\x08\x95\x03\x81\x06\xc0\t<\x05\xff\t\x01\x15\x00%\x01u\x01\x95\x02\xb1"u\x06\x95\x01\xb1\x01\xc0')
  hid_keyboard -- (1, 1, 8, 8, b'\x05\x01\t\x06\xa1\x01\x05\x07\x19\xe0)\xe7\x15\x00%\x01u\x01\x95\x08\x81\x02\x95\x01u\x08\x81\x01\x95\x05u\x01\x05\x08\x19\x01)\x05\x91\x02\x95\x01u\x03\x91\x01\x95\x06u\x08\x15\x00%e\x05\x07\x19\x00)e\x81\x00\xc0')
  USB_HID -- <class 'USB_HID'>
  USB_VCP -- <class 'USB_VCP'>
  have_cdc -- <function>
  hid -- <function>
  millis -- <function>
  elapsed_millis -- <function>
  micros -- <function>
  elapsed_micros -- <function>
  delay -- <function>
  udelay -- <function>
  sync -- <function>
  mount -- <function>
  dht_readinto -- <function>
  Timer -- <class 'Timer'>
  RTC -- <class 'RTC'>
  Pin -- <class 'Pin'>
  ExtInt -- <class 'ExtInt'>
  pwm -- <function>
  servo -- <function>
  Servo -- <class 'Servo'>
  Switch -- <class 'Switch'>
  Flash -- <class 'Flash'>
  LED -- <class 'LED'>
  I2C -- <class 'I2C'>
  SPI -- <class 'SPI'>
  UART -- <class 'UART'>
  ADC -- <class 'ADC'>
  ADCAll -- <class 'ADCAll'>

และจากรายการทั้งหมดนี้ ในบทความเราสนใจเฉพาะส่วนของ USB

USB ใน pyb

สิ่งที่เราสนใจในบทความนี้เป็นเรื่องของการใช้งาน USB ของบอร์ดไมโครคอนโทรลเลอร์ STM32F411CEU6 ซึ่งการเข้าถึงคุณสมบัตินี้ต้องเรียกผ่ายคลาส pyb และจะพบว่ามีรายการคลาสและฟังก์ใช้ใช้งานดังรายการต่อไปนี้

  • คลาส
    • USB_HID สำหรับใช้งาน Keyboard หรือ Mouse
    • USB_VCP สำหรับใช้พอร์ต USB เป็นเสมือนพอร์ตอนุกรม (VCP = Virtual COMM Port) โดยไม่ต้องใช้งานโมดูลแปลง USB-to-Serial
  • ฟังก์ชัน
    • usb_mode() สำหรับอ่านค่าโหมดของ USB ซึ่งมีด้วยกัน 5 โหมด คือ
      • ‘VCP’ เปิดการทำงานโหมด VCP หรือโหมดเสมือนพอร์ตอนุกรม ทำให้ใช้งานพอร์ต USB ของบอร์ดเชื่อมต่อเป็นพอร์ตสื่อสารอนุกรมระหว่างบอร์ดกับอุปกรณ์ที่ต่อพ่วงด้วย หรืออีกชื่อเรียกคือโหมด CDC
      • ‘MSC’ ทำงานในโหมด MSC (Mass Storage Class) หรือทำตัวเองเป็นเสมือนที่เก็บข้อมูล หรือที่คุ้นกันในชื่อของ Flash Drive
      • ‘VCP+MSC’ สำหรับทำงานในโหมด VCP และ MSC
      • ‘VCP+HID’ ทำงานในโหมด VCP และ HID (Human Interface Device)
      • ‘VCP+MSC+HID’ ทำงานในโหมด VCP, MSC และ HID
    • usb_mode([modestr, ]port=-1, vid=0xf055, pid=-1, msc=(), hid=pyb.hid_mouse, high_speed=False) สำหรับตั้งค่าโหมดการทำงานของ USB แต่ถ้าต้องการปิดโหมดการทำงาน USB ให้กำหนด modestr=None
      • port เป็นค่าตัวเลขของหมายเลขพอร์ต ปกติมีค่าเป็น 0,1,2,3,… และถ้ากำหนดเป็น -1 จะเป็นค่าหมายเลขพอร์ตที่ถูกเรียกใช้แบบอัตโนมัติ
      • msc เป็นการกำหนดอุปกรณ์ที่ทำงานในโหมด MSC ซึ่งปกติกำหนดเป็น () หมายถึงไม่มีอุปกรณ์ แต่ถ้ากำหนด pyb.Flash() หรือ pyb.SDCard() จะหมายถึงใช้ MSC จากหน่วยความจำ Flash ROM หรือจากพอร์ต SDCard ของบอร์ด (มีมากับ PyB แต่สามารถต่อวงจรเพิ่มได้) หรือใช้ทั้ง 2 แหล่งจะกำหนดเป็น msc=(pyb.flash(), pyb.SDCard())
      • hid สำหรับกำหนดโหมดการทำงานของ HID ซึ่งปกติกำหนดไว้เป็นเมาส์ หรือ pyb.hid_mouse แต่ถ้าต้องการเปลี่ยนเป็นแป้นพิมพ์ให้กำหนดเป็น pyb.hid_keyboard
      • high_speed สำหรับเปิดโหมด USB HS โดยกำหนดค่าให้เป็น True
    • hid((ปุ่ม,x,y,z)) สำหรับส่งข้อมูลปุ่ม และการเคลื่อนที่ของเมาส์ในแกน x,y และ z
    • have_cdc() สำหรับคืนค่า True หรือ False ในกรณีที่ USB ของบอร์ดได้เชื่อมต่อเป็นอุปกรณ์อนุกรม (serial device)
  • ค่าคุณสมบัติของการจำลองตนเองเป็นเมาส์หรือแป้นพิมพ์ ซึ่งเป็นค่าที่ใช้สำหรับกำหนดในพารามิเตอร์ hid ของคำสั่ง usb_mode()
    • hid_mouse ประกอบด้วยข้อมูล HID ของเมาส์
    • hid_keyboard ประกอบด้วยข้อมูล HID ของแป้นพิมพ์

ก่อนอื่นมาทดสอบอ่านค่าโหมดของ USB ด้วยโปรแกรมตัวอย่างต่อไปนี้กันก่อน

import pyb

print("CDC/VCP support = {}".format(pyb.have_cdc()))
print("USB Mode = {}".format(pyb.usb_mode()))

เมื่อรันโปรแกรมจะได้ตัวอย่างของผลการทำงานเป็นดังภาพที่ 5

ภาพที่ 5 ตัวอย่างผลลัพธ์จากการอ่านโหมดของ USB

ใช้งาน VCP

ส่วนการตั้งค่านั้นทำงานไม่ได้เมื่ออยู่ในโหมด REPL หรือโหมดการทำงาน MicroPython แบบรันชุดคำสั่ง เนื่องจากต้องใช้งานพอร์ต USB สำหรับสื่อสาร และ Flash ROM เป็นพื้นที่เก็บข้อมูล และเมื่อทำงานในโหมดนี้ ส่วนของ USB_VCP จะถูกใช้งานด้วยเช่นกัน ทำให้การส่งข้อมูลออก   VCP ทำงานเหมือนการใช้คำสั่ง print เพียงแต่ข้อมูลนำออกจะต้องเป็นสตริงเท่านั้น ดังนั้น การส่งข้อความ “Hello, I’m” ตามด้วยชื่อ platform สามารถเขียนได้ดังนี้

import pyb
import math
import sys
from pyb import Pin

usb = pyb.USB_VCP()
usb.write("Hello, I'm {}\n".format(sys.platform))
usb.write("Press [UKEY] to exit!\n")

sw = Pin('PA0', Pin.IN)
while not (1-sw.value()):
    pyb.delay(20)
usb.write("End of Program.")

ตัวอย่างของผลลัพธ์เป็นดังภาพที่ 6

ภาพที่ 6 ตัวอย่างผลลัพธ์จากการใช้ pyb.USB_VCP.write()

จำลองแป้นพิมพ์

สำหรับการให้ USB_VCP ทำงานเต็มหน้าที่ หรือเปลี่ยนโหมด USB จะต้องปรับแก้ในไฟล์ boot.py เพื่อให้มีการเปลี่ยนการทำงานตั้งแต่เริ่มระบบ เข่น ต้องการให้ทำงานในโหมด VCP+HID เพื่อจำลองตัวเองเป็นแป้นพิมพ์ สามารถแก้ไขโค้ดเป็นดังนี้

import pyb
#pyb.usb_mode('VCP+MSC')
pyb.usb_mode('VCP+HID',hid=pyb.hid_keyboard)

ส่วนการส่งข้อมูลออกไปสามารถทำได้ด้วยตัวอย่างของชุดคำสั่งต่อไปนี้

import pyb
hid = pyb.USB_HID()
buf = bytearray(8)
buf[2] = รหัสแป้น
hid.send(buf) # ส่งรหัสแป้นพิมพ์ออกไป
buf[2] = 0
hid.send(buf) # ยกเลิกการส่ง

สำหรับการส่งข้อมูลแบบ 2 คีย์ สามารถเขียนได้ดังนี้

import pyb
hid = pyb.USB_HID()
buf = bytearray(8)
buf[0] = รหัสคีย์1
buf[2] = รหัสคีย์2
hid.send( buf )
buf[0] = 0
buf[2] = 0
hid.send( buf )

ค่าของแป้นพิมพ์มีดังนี้

KEY_NONE = 0x00
KEY_ERRORROLLOVER = 0x01
KEY_POSTFAIL = 0x02
KEY_ERRORUNDEFINED = 0x03
KEY_A = 0x04
KEY_B = 0x05
KEY_C = 0x06
KEY_D = 0x07
KEY_E = 0x08
KEY_F = 0x09
KEY_G = 0x0A
KEY_H = 0x0B
KEY_I = 0x0C
KEY_J = 0x0D
KEY_K = 0x0E
KEY_L = 0x0F
KEY_M = 0x10
KEY_N = 0x11
KEY_O = 0x12
KEY_P = 0x13
KEY_Q = 0x14
KEY_R = 0x15
KEY_S = 0x16
KEY_T = 0x17
KEY_U = 0x18
KEY_V = 0x19
KEY_W = 0x1A
KEY_X = 0x1B
KEY_Y = 0x1C
KEY_Z = 0x1D
KEY_1_EXCLAMATION_MARK = 0x1E
KEY_2_AT = 0x1F
KEY_3_NUMBER_SIGN = 0x20
KEY_4_DOLLAR = 0x21
KEY_5_PERCENT = 0x22
KEY_6_CARET = 0x23
KEY_7_AMPERSAND = 0x24
KEY_8_ASTERISK = 0x25
KEY_9_OPARENTHESIS = 0x26
KEY_0_CPARENTHESIS = 0x27
KEY_ENTER = 0x28
KEY_ESCAPE = 0x29
KEY_BACKSPACE = 0x2A
KEY_TAB = 0x2B
KEY_SPACEBAR = 0x2C
KEY_MINUS_UNDERSCORE = 0x2D
KEY_EQUAL_PLUS = 0x2E
KEY_OBRACKET_AND_OBRACE = 0x2F
KEY_CBRACKET_AND_CBRACE = 0x30
KEY_BACKSLASH_VERTICAL_BAR = 0x31
KEY_NONUS_NUMBER_SIGN_TILDE = 0x32
KEY_SEMICOLON_COLON = 0x33
KEY_SINGLE_AND_DOUBLE_QUOTE = 0x34
KEY_GRAVEACCENTANDTILDE = 0x35
KEY_COMMA_AND_LESS = 0x36
KEY_DOT_GREATER = 0x37
KEY_SLASH_QUESTION = 0x38
KEY_CAPSLOCK = 0x39
KEY_F1 = 0x3A
KEY_F2 = 0x3B
KEY_F3 = 0x3C
KEY_F4 = 0x3D
KEY_F5 = 0x3E
KEY_F6 = 0x3F
KEY_F7 = 0x40
KEY_F8 = 0x41
KEY_F9 = 0x42
KEY_F10 = 0x43
KEY_F11 = 0x44
KEY_F12 = 0x45
KEY_PRINTSCREEN = 0x46
KEY_SCROLLLOCK = 0x47
KEY_PAUSE = 0x48
KEY_INSERT = 0x49
KEY_HOME = 0x4A
KEY_PAGEUP = 0x4B
KEY_DELETE = 0x4C
KEY_END1 = 0x4D
KEY_PAGEDOWN = 0x4E
KEY_RIGHT_ARROW = 0x4F
KEY_LEFT_ARROW = 0x50
KEY_DOWN_ARROW = 0x51
KEY_UP_ARROW = 0x52
KEY_KEYPAD_NUM_LOCK_AND_CLEAR = 0x53
KEY_KEYPAD_SLASH = 0x54
KEY_KEYPAD_ASTERIKS = 0x55
KEY_KEYPAD_MINUS = 0x56
KEY_KEYPAD_PLUS = 0x57
KEY_KEYPAD_ENTER = 0x58
KEY_KEYPAD_1_END = 0x59
KEY_KEYPAD_2_DOWN_ARROW = 0x5A
KEY_KEYPAD_3_PAGEDN = 0x5B
KEY_KEYPAD_4_LEFT_ARROW = 0x5C
KEY_KEYPAD_5 = 0x5D
KEY_KEYPAD_6_RIGHT_ARROW = 0x5E
KEY_KEYPAD_7_HOME = 0x5F
KEY_KEYPAD_8_UP_ARROW = 0x60
KEY_KEYPAD_9_PAGEUP = 0x61
KEY_KEYPAD_0_INSERT = 0x62
KEY_KEYPAD_DECIMAL_SEPARATOR_DELETE = 0x63
KEY_NONUS_BACK_SLASH_VERTICAL_BAR = 0x64
KEY_APPLICATION = 0x65
KEY_POWER = 0x66
KEY_KEYPAD_EQUAL = 0x67
KEY_F13 = 0x68
KEY_F14 = 0x69
KEY_F15 = 0x6A
KEY_F16 = 0x6B
KEY_F17 = 0x6C
KEY_F18 = 0x6D
KEY_F19 = 0x6E
KEY_F20 = 0x6F
KEY_F21 = 0x70
KEY_F22 = 0x71
KEY_F23 = 0x72
KEY_F24 = 0x73
KEY_EXECUTE = 0x74
KEY_HELP = 0x75
KEY_MENU = 0x76
KEY_SELECT = 0x77
KEY_STOP = 0x78
KEY_AGAIN = 0x79
KEY_UNDO = 0x7A
KEY_CUT = 0x7B
KEY_COPY = 0x7C
KEY_PASTE = 0x7D
KEY_FIND = 0x7E
KEY_MUTE = 0x7F
KEY_VOLUME_UP = 0x80
KEY_VOLUME_DOWN = 0x81
KEY_LOCKING_CAPS_LOCK = 0x82
KEY_LOCKING_NUM_LOCK = 0x83
KEY_LOCKING_SCROLL_LOCK = 0x84
KEY_KEYPAD_COMMA = 0x85
KEY_KEYPAD_EQUAL_SIGN = 0x86
KEY_INTERNATIONAL1 = 0x87
KEY_INTERNATIONAL2 = 0x88
KEY_INTERNATIONAL3 = 0x89
KEY_INTERNATIONAL4 = 0x8A
KEY_INTERNATIONAL5 = 0x8B
KEY_INTERNATIONAL6 = 0x8C
KEY_INTERNATIONAL7 = 0x8D
KEY_INTERNATIONAL8 = 0x8E
KEY_INTERNATIONAL9 = 0x8F
KEY_LANG1 = 0x90
KEY_LANG2 = 0x91
KEY_LANG3 = 0x92
KEY_LANG4 = 0x93
KEY_LANG5 = 0x94
KEY_LANG6 = 0x95
KEY_LANG7 = 0x96
KEY_LANG8 = 0x97
KEY_LANG9 = 0x98
KEY_ALTERNATE_ERASE = 0x99
KEY_SYSREQ = 0x9A
KEY_CANCEL = 0x9B
KEY_CLEAR = 0x9C
KEY_PRIOR = 0x9D
KEY_RETURN = 0x9E
KEY_SEPARATOR = 0x9F
KEY_OUT = 0xA0
KEY_OPER = 0xA1
KEY_CLEAR_AGAIN = 0xA2
KEY_CRSEL = 0xA3
KEY_EXSEL = 0xA4
KEY_KEYPAD_00 = 0xB0
KEY_KEYPAD_000 = 0xB1
KEY_THOUSANDS_SEPARATOR = 0xB2
KEY_DECIMAL_SEPARATOR = 0xB3
KEY_CURRENCY_UNIT = 0xB4
KEY_CURRENCY_SUB_UNIT = 0xB5
KEY_KEYPAD_OPARENTHESIS = 0xB6
KEY_KEYPAD_CPARENTHESIS = 0xB7
KEY_KEYPAD_OBRACE = 0xB8
KEY_KEYPAD_CBRACE = 0xB9
KEY_KEYPAD_TAB = 0xBA
KEY_KEYPAD_BACKSPACE = 0xBB
KEY_KEYPAD_A = 0xBC
KEY_KEYPAD_B = 0xBD
KEY_KEYPAD_C = 0xBE
KEY_KEYPAD_D = 0xBF
KEY_KEYPAD_E = 0xC0
KEY_KEYPAD_F = 0xC1
KEY_KEYPAD_XOR = 0xC2
KEY_KEYPAD_CARET = 0xC3
KEY_KEYPAD_PERCENT = 0xC4
KEY_KEYPAD_LESS = 0xC5
KEY_KEYPAD_GREATER = 0xC6
KEY_KEYPAD_AMPERSAND = 0xC7
KEY_KEYPAD_LOGICAL_AND = 0xC8
KEY_KEYPAD_VERTICAL_BAR = 0xC9
KEY_KEYPAD_LOGIACL_OR = 0xCA
KEY_KEYPAD_COLON = 0xCB
KEY_KEYPAD_NUMBER_SIGN = 0xCC
KEY_KEYPAD_SPACE = 0xCD
KEY_KEYPAD_AT = 0xCE
KEY_KEYPAD_EXCLAMATION_MARK = 0xCF
KEY_KEYPAD_MEMORY_STORE = 0xD0
KEY_KEYPAD_MEMORY_RECALL = 0xD1
KEY_KEYPAD_MEMORY_CLEAR = 0xD2
KEY_KEYPAD_MEMORY_ADD = 0xD3
KEY_KEYPAD_MEMORY_SUBTRACT = 0xD4
KEY_KEYPAD_MEMORY_MULTIPLY = 0xD5
KEY_KEYPAD_MEMORY_DIVIDE = 0xD6
KEY_KEYPAD_PLUSMINUS = 0xD7
KEY_KEYPAD_CLEAR = 0xD8
KEY_KEYPAD_CLEAR_ENTRY = 0xD9
KEY_KEYPAD_BINARY = 0xDA
KEY_KEYPAD_OCTAL = 0xDB
KEY_KEYPAD_DECIMAL = 0xDC
KEY_KEYPAD_HEXADECIMAL = 0xDD
KEY_LEFTCONTROL = 0xE0
KEY_LEFTSHIFT = 0xE1
KEY_LEFTALT = 0xE2
KEY_LEFT_GUI = 0xE3
KEY_RIGHTCONTROL = 0xE4
KEY_RIGHTSHIFT = 0xE5
KEY_RIGHTALT = 0xE6
KEY_RIGHT_GUI = 0xE7

จำลองเมาส์

กรณีที่ต้องการจำลองตัวเองเป็นเมาส์ ให้แก้ไข boot.py เป็นดังนี้

import pyb
pyb.usb_mode('VCP+HID',hid=pyb.hid_mouse)

การส่งข้อมูลเพื่อจำลองเป็นเมาส์ใช้คำสั่งดังต่อไปนี้

import pyb
mouse = pyb.USB_HID()
hid.send((ปุ่ม, จำนวนค่าในแกน x, จำนวนค่าในแกน y, จำนวนค่าของการ scroll))

สรุป

จากบทความนี้จะพบว่าบอร์ดไมโครคอนโทรลเลอร์ที่ใช้หน่วยประมวลผล ARM ตระกูลเดียวกับ PyBoard ที่เป็นต้นแบบของบอร์ดสำหรับ MicroPython สามารถใช้งานพอร์ต USB ที่มากับบอร์ดได้ 3 โหมด คือ VCP, MSC และ HID ทำให้สามารถจำลองการทำงานของบอร์ดให้เป็นพอร์ตสื่อสารอนุกรม หน่วยความจำสำรอง (storage) และอุปกรณ์เชื่อมประสานกับผู้ใช้ในโหมดจำลองการเป็นแป้นพิมพ์หรือเมาส์ ดังนั้น ถ้าเพิ่มโมดูลเกี่ยวกับ Gyro เข้าไป เราสามารถใช้ค่า x,y,z จากโมดูลมาแทน x,y,scroll ของเมาส์ ทำให้บอร์ดของเรากลายเป็นอุปกรณ์นำเข้าที่แตกต่างกันออกไปได้ เป็นต้น สุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ

แหล่งอ้างอิง

  1. เรวัต ศิริโภคาภิรมย์. (2020).MicroPython for STM32F411 Black Pill: Embedded Programming Style
  2. MicroPython : pyb
  3. MicroPython : pyb -> USB_HID
  4. MicroPython : pyb -> USB_VCP
  5. [MicroPython] Use python to perform USB-HID test of BadUSB (include wireless control)

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-11-02