在 ESP32/ESP8266 MicroPython 使用 USB 傳輸線與電腦上的程式互動

codemee - Jul 8 '20 - - Dev Community

在 ESP32/ESP8266 上撰寫 MicroPython 程式時, 你可能會希望可以讓 控制板透過 USB 傳輸線和電腦上的其他程式互動, 例如可以從 PuTTY 輸入指令控制控制板上內建的 LED 燈。要做到這件事, 最簡單的方式就是使用 Python 內建的 input 來讀取輸入資料, 不過這個方式必須要在輸入資料後按下 Enter, 有點麻煩, 我們希望的是可以直接按下例如 O/X 就點亮/熄滅 LED 的方式。

對於習慣使用 Arduino 的人可能會想到這不就開啟序列通訊就好了?沒錯, MicroPython 在 machine 模組中也提供了 UART 類別, 可以使用控制板上的 UART, 可惜的是 UART0 已經被 REPL (互動介面) 佔用了, 無法在程式中使用。難道這樣就沒輒了嗎?

還好, 山不轉路轉, 由於 REPL 的輸入就是 Python 的 sys.stdin 資料流, 所以我們可以直接操作 sys.stdin 來獲取輸入的資料, 在 Python 中也提供有標準的 select 機制, 可以偵測輸入用的資料流是否已經有資料等待讀取?結合以上, 我們就可以讀取輸入的指令來做出回應了。

以下就是一個簡單的程式, 可以從電腦端透過 USB 傳輸線輸入 O/X 指令到控制板點亮/熄滅內建的 LED:

import sys
import select
import time
from machine import Pin

p = select.poll()     # 建立偵測物件
p.register(
    sys.stdin,        # 偵測標準輸入 (REPL)
    select.POLLIN     # 偵測是否有資料待讀取
) 

led = Pin(2, Pin.OUT) # 控制內建的 LED
led.value(0)          # 預設熄燈

while 1:
  time.sleep(0.1)

  while p.poll(0):   # 測試是否有資料待讀取並等待 0 毫秒
    ch = sys.stdin.read(1) # 讀取資料
    if ch == 'O':    # 輸入指定 O
        print('點亮')
        led.value(1) # 點亮 (esp8266 是熄滅)
    elif ch == 'X':  # 輸入指令 X
        print('熄滅')
        led.value(0) # 熄滅 (esp8266 是點亮)
Enter fullscreen mode Exit fullscreen mode

其中 poll(0) 就是偵測是否有資料待讀取?傳入的參數代表要等待多少毫秒?如果超過時間仍然沒有資料可讀取, 就會傳回一個空的串列, 否則就會傳回一個由元素組 (tuple) 組成的串列。因此只要判斷傳回值就可以知道是否有資料待讀取了。這裡傳入 0 表示不等待, 這樣可以在沒有輸入資料時去做別的事情, 不用枯等 (block) 資料進來。

要測試這個程式, 必須將程式儲存成 main.py, 放到控制板上重開機讓它自動執行, 如果直接在 thonny 之類的環境執行, 輸入資料會被 REPL 搶走。接著, 就可以開啟 PuTTY 之類的終端機軟體連接控制板下指令控制 LED 了:

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player