GoにいればGoに従え(6) BBC micro:bit (v1.5)で超簡単、温度計よ

Joseph Halfmoon

今回はmicro:bitのマイコンが内蔵している温度センサを読み取ってみます。ICの温度を測るもの、温度計と期待しちゃいけない奴。温度の表示は25個あるLEDを温度に応じて光らせます。0℃なら0個、20℃なら10個、50℃以上なら25個という感じ。2℃あがるごとに1個点灯。前回の表示ルーチンも細かく改良、ホントか?

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

参考文献

今回も以下の御本を参考に、前回のTinyGoプログラムを 改変してみた回です。

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

上記の御本はSeeed社のWio Terminalをターゲットなので、BBC micro:bit に適用する場合は以下のページを参照するとよいと思います。

Machine package / microbit

今回実験のmainプログラム

さて、今回のmainプログラムは前回のものよりだいぶサッパリしました。goroutineによるLED点灯のために「常に回っている」ところをmain()関数内から別ファイルのLED関係の関数のファイルの方にお引越し。その代わりに温度測定用の関数と、測定した温度をLEDの点灯パターンに変換する関数の2個を追加して温度表示できるようにいたしました。

machineパッケージ内でReadTemperature()という温度測定用の関数が用意されているのでそのままでもよいのですが、こいつがint32型でミリ℃単位という桁数の多いやつだったので、ばっさり℃単位に切り捨ててしまいました。IC内部の温度を測るセンサで、4分の1度レゾリューション、校正なしの精度±4℃ということみたいです(切り捨ては乱暴だったか。せめて小数点以下四捨五入?いまとなっては遅いけど。)ついでにint32のままだと不便なので単なるint型にもしてます。このあたりの変換が厳しいのがモダンな言語っぽいっす。

その「測定した」温度をLEDの点灯数に換算してますが、0℃以下は無点灯、50℃以上は全点灯、2℃につき右下から左上に向けて1灯づつ点灯していくという「折り畳み風の」棒温度計スタイルです。なお、センサ自体はマイナス25℃からプラス75℃まで測定可能みたいです。知らんけど。

package main

import (
    "machine"
    "time"
)

func boardTemperatureC() int {
    return int(machine.ReadTemperature() / 1000)
}

func dispBar(arg int) uint32 {
    var retval uint32 = 0
    var cval int = arg / 2
    for i := 0; i < 25; i++ {
        if cval > i {
            retval |= 1
        }
        retval <<= 1
    }
    return retval
}

func main() {
    InitLED()

    temperatureBar := dispBar(boardTemperatureC())

    go DispLoop(&temperatureBar)

    for {
        temperatureBar = dispBar(boardTemperatureC())
        time.Sleep(time.Second * 5)
    }
}
改良?した表示サブルーチン群

さて、上記のmain.goの横に置いてあるサブルーチン用のファイル(mbdisp.go)の内容が以下に。main()関数から表示用のgoroutineで呼び出される関数にちゃんとお名前をつけて一本立ちさせてみました。こんな感じ。

package main

import (
    "machine"
    "time"
)

var row = 1

func DispLoop(arg *uint32) {
    for {
        switch row {
        case 1:
            DispLED1(*arg)
        case 2:
            DispLED2(*arg)
        case 3:
            DispLED3(*arg)
        }
        row++
        if row > 3 {
            row = 1
        }
        time.Sleep(time.Millisecond * 10)
    }
}

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

冒頭のアイキャッチ画像の表示は、普段、熱収縮チューブの収縮に使っている小さいドライヤーでボード裏側を軽く温めてみたときのもの。3段と2個光っているので、だいたい34℃以上にはなったようです。また、写真は掲げてないですが現在保冷剤の上にmicro:bitが載せてありますが、点灯数は1段と2個まで低下しました。14℃くらいね。

まあ一応、温度に反応してLEDが表示されているみたいなのでOK。いい加減だな。いつものことか。

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

GoにいればGoに従え(7) TinyGoのmicro:bit向けI2C関数の挙動を観察 へ進む