前回TinyGoを使って mico:bit(v1.5)のLEDに所望のパターンを光らせることができました。しかしダイナミック駆動のためにプログラムが回り続けています。光らせるだけ。これでは何もできませぬ。しかしTinyGoの御本を読んだので知っています。goroutineを使えばLED駆動関数を並行処理できるっと。
※「GoにいればGoに従え」Go関連記事の総Index
TinyGoでもコンカレント処理ができる
パソコン上の「フルサイズ」のGoは勿論、TinyGoでも goroutine というものが使えるようです。多分「コンテンポラリー」な言語処理系でありがちな「コルーチン」使った「プリエンプティブでない」並行処理じゃないかと思います。知らんけど。
最近頼り切りの以下の御本を参考に、前回のTinyGoプログラムを goroutine化してみましたぜ。
高砂様著、「TinyGoの組み込み開発」
コンカレント処理化したmain関数
折角の並行処理化なので、メインループ内で4つのパターンを5秒おきに切り替えるようにしてみました。
-
- 第1パターン、暗黒(全消灯)
- 第2パターン、バッテン
- 第3パターン、マル(ちょっと四角いケド)
- 第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つのパターンが点灯するようになりました。
goroutine便利。