ESP-WROOM-02でMicroPythonを使い開発(並行処理編)

〔ESP32-WROOM-32E〕 〔マイコンのトップに戻る〕
[準備編] [module編] [GPIO編] [通信編] [ファイル編] [OLED編] [WiFi編] [メール編]   [色々編]


このページでは”非同期 I/O”モジュールを使って並行処理のコードを書いてみます。
この話は、”非同期 I/O スケジューラ”とここを参照してください。
又、peterhinch氏著(英語)のこちらも参考にしましょう。

ヘルプ(uasyncio)

《uasyncio》

@ ESP-WROOM-02ボードに2個のLEDを取り付けます。
  ここでは1個のLED2はボード内臓(GPIO16)を使っています、LOWでLED2点灯なので
  LED1と論理を合わせる為に"Signal()"関数を使っています。
A ESP-WROOM-02ボードをUSBでPCに繋ぎます。
B "PyCharm"を起動させ、こちらのCを操作する必要が有ります。(起動時最初のみ設定)
C "main.py"を新規登録して下記スクリプトを"main.py"に貼り付けましょう。
  (登録済みなら上書き貼り付けでも行いましょう)
D ESP8266に書き込みます
  左側プロジェクトウインドウから"main.py"の文字を右クリックをして、[実行(U)'Flash main.py']を
  クリックします。
--------------------------------------------------------------------------------
import uasyncio
from machine import Pin, Signal

async def blink(led, period_ms):
    # LEDの点滅をくりかえすタスク
    while True:
        led.on()
        await uasyncio.sleep_ms(5)
        led.off()
        await uasyncio.sleep_ms(period_ms)

async def main(led1, led2):
    # 新しいタスク(blink)を作成し、実行をスケジューリングする
    uasyncio.create_task(blink(led1, 700))
    uasyncio.create_task(blink(led2, 400))
    # 10秒したら終了
    await uasyncio.sleep_ms(10_000)

led1 = Pin(4, Pin.OUT)              # ピン4番(GPIO4)をLED出力で割り付ける
led2 = Pin(16, Pin.OUT)             # ピン16番(GPIO16)をLED出力で割り付ける
led2 = Signal(led2, invert=True)    # LED2の出力論理を合わせる
# 新しいタスク(main)を作成し、完了するまで待つ
uasyncio.run(main(led1, led2))
--------------------------------------------------------------------------------
この動作はLED2個が其々の点滅タイミングで10秒間点滅します。
並行に動作するタスクは3個です、[main()タスク]と[blink(led1)タスク]に[blink(led2)タスク]です。
"blink"タスクを生成した"main"タスクが終了すると"blink"タスクも終了していますね。
それとぉ、"sleep()"関数は"uasyncio"が実装する物を使わないとダメですよ。

タスクの同期

タスク同しを同期させたい場合のサンプルです。
--------------------------------------------------------------------------------
import uasyncio
from machine import Pin, Signal

async def blink(led, period_ms):
    # LEDの点滅をくりかえすタスク
    while True:
        led.on()
        await uasyncio.sleep_ms(5)
        led.off()
        await uasyncio.sleep_ms(period_ms)

led1 = Pin(4, Pin.OUT)              # ピン4番(GPIO4)をLED出力で割り付ける
led2 = Pin(16, Pin.OUT)             # ピン16番(GPIO16)をLED出力で割り付ける
led2 = Signal(led2, invert=True)    # LED2の出力論理を合わせる
# タスクの同期スケジュールと実行に使うイベントループを得る
event_loop = uasyncio.get_event_loop()
# タスクの作成
event_loop.create_task(blink(led1, 700))
event_loop.create_task(blink(led2, 400))
# stop()が呼ばれるまでイベントループを実行
event_loop.run_forever()
--------------------------------------------------------------------------------
ここの動作は点滅はしっぱなしです、壊れるまで実行する事でしょう。
サーバーの並行処理

上のサンプルにサーバーがクライアントの接続待ちを行うタスクを追加したスクリプトです。
サーバーの動作は、受信メッセージの表示と"HTTP/1.1 200 OK"と"Hello"のレスポンスを返すだけです。
--------------------------------------------------------------------------------
import uasyncio
from machine import Pin, Signal

async def blink(led, period_ms):
    # LEDの点滅をくりかえすタスク
    while True:
        led.on()
        await uasyncio.sleep_ms(5)
        led.off()
        await uasyncio.sleep_ms(period_ms)

async def serve(reader, writer):
    # クライアントが接続して来たら実行されます
    print('\r\n--- client connected ---')
    print(reader, writer)
    while True:
        bMsg = await reader.readline()
        print(bMsg)
        if not bMsg or bMsg == b'\r\n':
            break
    await writer.awrite(b'HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n')
    await writer.awrite(b'Hello\r\n')
    print('Response write')
    await writer.aclose()
    print('Finished request\r\n')

led1 = Pin(4, Pin.OUT)            # ピン4番(GPIO4)をLED出力で割り付ける
led2 = Pin(16, Pin.OUT)           # ピン16番(GPIO16)をLED出力で割り付ける
led2 = Signal(led2, invert=True)  # LED2の出力論理を合わせる
# 並行処理タスクの起動
event_loop = uasyncio.get_event_loop()
event_loop.create_task(blink(led1, 700))
event_loop.create_task(blink(led2, 400))
event_loop.create_task(uasyncio.start_server(serve, '0.0.0.0', 80))
event_loop.run_forever()
--------------------------------------------------------------------------------
@ ESP-WROOM-02ボードに書き込みを行いましょう。
A LED1とLED2は点滅していますね。
B "MicroPython-14c2b9"へPCのアクセスポイントを切り替えます。
C ブラウザーを開き[192.168.4.1]とURL(アドレス)バーに入力します。
D "Hello"と表示されるでしょう。

クライアントの並行処理

今度はクライアントをやってみます、これは前の[WiFi編]のクライアントの章と同じ物です。

--------------------------------------------------------------------------------
import uasyncio
from machine import Pin, Signal
import network


async def blink(led, period_ms):
    # LEDの点滅をくりかえすタスク
    while True:
        led.on()
        await uasyncio.sleep_ms(5)
        led.off()
        await uasyncio.sleep_ms(period_ms)


async def client(host, port):
    global writer
    # 指定されたサーバーとポートに接続する
    reader, writer = await uasyncio.open_connection(host, port)
    # データをダウンロードしてREPLに表示(スターウォーズの始まり始まり)
    while True:
        data = await reader.read(500)
        print(str(data, 'utf8'), end='')


led1 = Pin(4, Pin.OUT)  # ピン4番(GPIO4)をLED出力で割り付ける
led2 = Pin(16, Pin.OUT)  # ピン16番(GPIO16)をLED出力で割り付ける
led2 = Signal(led2, invert=True)  # LED2の出力論理を合わせる
# Wi-Fiに接続
ESSID = "BBUser"
Password = ""
# Wi-Fi 接続を設定する為にクライアントオブジェクトのインターフェースを作成する
sta_if = network.WLAN(network.STA_IF)
if not sta_if.isconnected():
    sta_if.active(True)
    sta_if.connect(ESSID, Password)  # ステーションインターフェイスを有効にする
    while not sta_if.isconnected():  # WiFiネットワークに接続する
        pass
print('\r\n[network config]\r\n', sta_if.ifconfig())

# 並行処理タスクの起動
event_loop = uasyncio.get_event_loop()
event_loop.create_task(blink(led1, 700))
event_loop.create_task(blink(led2, 400))
event_loop.create_task(client("towel.blinkenlights.nl", 23))
try:
    # stop()が呼ばれるまでイベントループを実行
    event_loop.run_forever()
finally:
    writer.aclose()       # ソケットをクローズする
    sta_if.active(False)  # サーバーを切断する
    print('\r\nFin\r\n')
--------------------------------------------------------------------------------------------------
try/finally
例外が発生した場合や[CTRL]+[C]で中断させた場合等に最後に実行する処理を行わせたい場合、
"finally:"節に記述しましょう。
又、”8. エラーと例外”や”組み込み例外”を参考にすると良いかもね。



[メール編へ] [ページ上へ] [色々編へ]


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2021 Shigehiro Kimura All Rights Reserved.