GoにいればGoに従え(4) micro:bitのLED、goroutineで動的駆動じゃ

Joseph Halfmoon

前回TinyGoを使って mico:bit(v1.5)のLEDに所望のパターンを光らせることができました。しかしダイナミック駆動のためにプログラムが回り続けています。光らせるだけ。これでは何もできませぬ。しかしTinyGoの御本を読んだので知っています。goroutineを使えばLED駆動関数を並行処理できるっと。

※「GoにいればGoに従え」Go関連記事の総Index

TinyGoでもコンカレント処理ができる

パソコン上の「フルサイズ」のGoは勿論、TinyGoでも goroutine というものが使えるようです。多分「コンテンポラリー」な言語処理系でありがちな「コルーチン」使った「プリエンプティブでない」並行処理じゃないかと思います。知らんけど。

最近頼り切りの以下の御本を参考に、前回のTinyGoプログラムを goroutine化してみましたぜ。

高砂様著、「TinyGoの組み込み開発」

コンカレント処理化したmain関数

折角の並行処理化なので、メインループ内で4つのパターンを5秒おきに切り替えるようにしてみました。

    1. 第1パターン、暗黒(全消灯)
    2. 第2パターン、バッテン
    3. 第3パターン、マル(ちょっと四角いケド)
    4. 第4パターン、全点灯

そして goroutine化したディスプレイドライバ?関数の中で3個のROW信号を次々にファイヤして5x5のディスプレイをダイナミック駆動、見掛け上はちゃんとパターンが光っているように見せようというのです。なお、ROW信号の駆動周期は前回同様 10ms にしてみました。実際 15ms にしたらちょっとチラツキが気になったからです。前回の設定、意外といい線行っていた?

main関数のファイルが以下に。

package main

import (
    "time"
)

func main() {
    InitLED()
    var dispPattern [4]uint32
    dispPattern[0] = 0x00000000
    dispPattern[1] = 0x01151151
    dispPattern[2] = 0x00E8C62E
    dispPattern[3] = 0x01FFFFFF
    var pat = 0
    var row = 1

    go func() {
        for {
            switch row {
            case 1:
                DispLED1(dispPattern[pat])
            case 2:
                DispLED2(dispPattern[pat])
            case 3:
                DispLED3(dispPattern[pat])
            }
            row++
            if row > 3 {
                row = 1
            }
            time.Sleep(time.Millisecond * 10)
        }
    }()

    for {
        pat++
        if pat > 3 {
            pat = 0
        }
        time.Sleep(time.Second * 5)
    }
}
コンカレント処理対応版のLEDインタフェース関数群

main関数のファイルの「横に」同じパッケージのファイルとしておいてあるものが以下に。前回と大きく異なるのは、DispLED関数をDispLED1, 2, 3 という3つの関数に分離したことです。これは並行処理される点灯処理内で各ROWを順に呼び出すため。

ファイルが以下に。

package main

import (
    "machine"
)

func InitLED() {
    machine.LED_ROW_1.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_ROW_2.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_ROW_3.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_1.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_2.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_3.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_4.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_5.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_6.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_7.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_8.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_COL_9.Configure(machine.PinConfig{Mode: machine.PinOutput})
    machine.LED_ROW_1.Low()
    machine.LED_ROW_2.Low()
    machine.LED_ROW_3.Low()
}

func SetLED(arg uint32) {
    if (arg & 0x0404001) != 0 {
        machine.LED_COL_1.Low()
    } else {
        machine.LED_COL_1.High()
    }
    if (arg & 0x1000404) != 0 {
        machine.LED_COL_2.Low()
    } else {
        machine.LED_COL_2.High()
    }
    if (arg & 0x0101010) != 0 {
        machine.LED_COL_3.Low()
    } else {
        machine.LED_COL_3.High()
    }
    if (arg & 0x0080022) != 0 {
        machine.LED_COL_4.Low()
    } else {
        machine.LED_COL_4.High()
    }
    if (arg & 0x0040048) != 0 {
        machine.LED_COL_5.Low()
    } else {
        machine.LED_COL_5.High()
    }
    if (arg & 0x0820080) != 0 {
        machine.LED_COL_6.Low()
    } else {
        machine.LED_COL_6.High()
    }
    if (arg & 0x0210100) != 0 {
        machine.LED_COL_7.Low()
    } else {
        machine.LED_COL_7.High()
    }
    if (arg & 0x0008200) != 0 {
        machine.LED_COL_8.Low()
    } else {
        machine.LED_COL_8.High()
    }
    if (arg & 0x0002800) != 0 {
        machine.LED_COL_9.Low()
    } else {
        machine.LED_COL_9.High()
    }
}

func DispLED1(arg uint32) {
    machine.LED_ROW_1.Low()
    machine.LED_ROW_2.Low()
    machine.LED_ROW_3.Low()
    if (arg & 0x00F8815) != 0 {
        SetLED(arg & 0x00F8815)
        machine.LED_ROW_1.High()
    }
}

func DispLED2(arg uint32) {
    machine.LED_ROW_1.Low()
    machine.LED_ROW_2.Low()
    machine.LED_ROW_3.Low()
    if (arg & 0x0A0540A) != 0 {
        SetLED(arg & 0x0A0540A)
        machine.LED_ROW_2.High()
    }
}

func DispLED3(arg uint32) {
    machine.LED_ROW_1.Low()
    machine.LED_ROW_2.Low()
    machine.LED_ROW_3.Low()
    if (arg & 0x15023E0) != 0 {
        SetLED(arg & 0x15023E0)
        machine.LED_ROW_3.High()
    }
}
実機実行結果

例によって BBC micro:bit (V1.5) をUSBポートに接続し、

$ tinygo flash -target=microbit

これで4つのパターンが点灯するようになりました。

GoRoutineDUT

 

goroutine便利。

GoにいればGoに従え(3) micro:bitのLED、ダイナミック駆動じゃね へ戻る

GoにいればGoに従え(5) micro:bitのA,Bキーを割り込み受けね。へ進む