micro:bitボード をv1.5からv2.0に機材変更したのにともない、前回はLEDマトリックスの表示部分をv2.0対応に変更しました。v1.5用の他の関数などは「そのまま動くだろ」とは思ったものの、動作確認は未です。「動くだろ」と思っても「動かない」ことはままあり、今回は第5回、第6回あたりのコードをv2.0で復習。
※「GoにいればGoに従え」Go関連記事の総Index
マイコン用のプログラムが「動く筈」が「動かしてみたらば動かない」経験は多々あり、それどころか「動いた」けれども「問題だった」経験も大ありであります。現物が現場(の環境で)ちゃんと動くと確認できるまではマイコンが動いたなどとはつゆほどに信じませぬ。マイコンもこの世の物理現象であるので、世の理の中で動いており、神ならぬ人の心の中の期待とは違うっと。知らんけど。
さて、TinyGo で micro:bit のADコンバータを使うには、v2.x系のボードが必要なことが分かり、当初 v1.5 で始めていたTinyGoの練習を v2.0 ボードに変更しました。機材を変更すればいろいろ問題が出るのは必定、前回はボード表面のLED Matrix部分を書きなおして対応しました。今回は「多分動く」筈の以下の2点の確認であります。
-
- キー割り込み、ボード表面のAとBのキーを割り込み受けすること
- 温度センサ、マイコン内蔵の温度センサを読み取ること
また前回動作するようになったLED Matrixの動的駆動も併用します。動作はこんな感じ。
-
- goルーチン(コルーチン?による並行動作機構)をつかってLED Matrixは動的点灯をつづける
- キーをプッシュした時点で割り込みでうけする。AキーとBキーで異なる値を立て、それによってLED表示パターンを即座に変更する
- メインルーチンは上記とかかわりなく無限ループしながら、10秒置きに温度を測定して標準出力(USBシリアル)に温度を出力する
今回のメインルーチン
今回のメインルーチンのソースが以下に。キーボード割り込みの設定が増えましたが、LED表示関係の関数をほぼほぼ別ファイルに追い出したので、前回よりはスッキリかと。
package main import ( "fmt" "machine" "time" ) var pat = 0 func boardTemperatureC() int { return int(machine.ReadTemperature() / 1000) } func main() { dispPattern := []uint32{ 0x00000000, 0x01151151, 0x00E8C62E, 0x01FFFFFF, } InitLED() go DispLoop(dispPattern[:]) keyA := machine.BUTTONA keyB := machine.BUTTONB keyA.Configure(machine.PinConfig{Mode: machine.PinInput}) keyB.Configure(machine.PinConfig{Mode: machine.PinInput}) keyA.SetInterrupt(machine.PinFalling, func(machine.Pin) { pat = 1 }) keyB.SetInterrupt(machine.PinFalling, func(machine.Pin) { pat = 2 }) for { fmt.Printf("TEMP: %d\r\n", boardTemperatureC()) time.Sleep(time.Second * 10) } }
LEDのダイナミック表示ルーチン
別ファイルに追い出した マトリックスLEDにパターンを動的表示するための関数群が以下に。DispLoopがgoルーチン化されて、メインとは関わりなく勝手に「回り続ける」ものです。また、表示は割り込みハンドラの中で pat 変数に代入されたインデックスのパターンとなります。
package main import ( "machine" "time" ) var row = 1 func DispLoop(dispPattern []uint32) { for { switch row { case 1: DispLED1(dispPattern[pat]) case 2: DispLED2(dispPattern[pat]) case 3: DispLED3(dispPattern[pat]) case 4: DispLED4(dispPattern[pat]) case 5: DispLED5(dispPattern[pat]) } row++ if row > 5 { row = 1 } time.Sleep(time.Millisecond * 7) } } 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_ROW_4.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.LED_ROW_5.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_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() } func SetLED(arg uint32) { if (arg & 0x01084210) != 0 { machine.LED_COL_1.Low() } else { machine.LED_COL_1.High() } if (arg & 0x00842108) != 0 { machine.LED_COL_2.Low() } else { machine.LED_COL_2.High() } if (arg & 0x00421084) != 0 { machine.LED_COL_3.Low() } else { machine.LED_COL_3.High() } if (arg & 0x00210842) != 0 { machine.LED_COL_4.Low() } else { machine.LED_COL_4.High() } if (arg & 0x00108421) != 0 { machine.LED_COL_5.Low() } else { machine.LED_COL_5.High() } } func DispLED1(arg uint32) { machine.LED_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() if (arg & 0x01F00000) != 0 { SetLED(arg & 0x01F00000) machine.LED_ROW_1.High() } } func DispLED2(arg uint32) { machine.LED_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() if (arg & 0x000F8000) != 0 { SetLED(arg & 0x000F8000) machine.LED_ROW_2.High() } } func DispLED3(arg uint32) { machine.LED_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() if (arg & 0x00007C00) != 0 { SetLED(arg & 0x00007C00) machine.LED_ROW_3.High() } } func DispLED4(arg uint32) { machine.LED_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() if (arg & 0x000003E0) != 0 { SetLED(arg & 0x000003E0) machine.LED_ROW_4.High() } } func DispLED5(arg uint32) { machine.LED_ROW_1.Low() machine.LED_ROW_2.Low() machine.LED_ROW_3.Low() machine.LED_ROW_4.Low() machine.LED_ROW_5.Low() if (arg & 0x0000001F) != 0 { SetLED(arg & 0x0000001F) machine.LED_ROW_5.High() } }
実機動作確認
冒頭のアイキャッチ画像のようにBボタンを押すと〇が表示され、Aボタンを押すと×が表示されます。割り込みで受けているので瞬間的に反応。
上記とはかかわりないタイミングで10秒に1回温度を測ってUSBシリアルに報告してきます。仮想端末のTeraTerm Proに報告された温度の羅列が以下に。
今回は特別の問題もなく、v1.5用のソースは流用できたみたい。