
micro:bitボードをv1.5からv2.0に機材変更するのにともない、v1.5で動作していたプログラムがv2.0でも動くのか確認作業中です。前回はキー割り込みとオンボードの温度センサは問題なく動作OK。I2Cも大丈夫だろ、と甘くみたらばダメでした。ここにもv1.5とv2.0の違いがあったのね。今回はその変更点をば。
※「GoにいればGoに従え」Go関連記事の総Index
micro:bit のI2Cバス、v1.5とv2.0の違い
結論から言うと以下のようでした。
-
- micro:bit v1.5、オンボードペリフェラルとカードエッジの端子で1本のI2Cバスをシェアしていた。
- micro:bit v2.0、オンボードペリフェラル用の内部I2Cバスと、カードエッジ用の外部I2Cバスが分離された。TinyGo上では、I2C0というバスが内部用で、I2C1というバスが外部用になった。また、I2C用のピン名も変更されている。
つまり、v1.5用のTinyGoソースをそのままコンパイルするとコンパイルはノーエラーですが、ピクりともバスは動きませぬ。外部用のI2C1に行先を向けなおした上に、ピン名も変更せねばなりません。
つまり、下記のように外部用I2Cを使う場合は以下のようにI2C1を指定した上で
v1.5のころは、SCL_PINとかで良かったピン名をSCL1_PINなどと変更する必要がありました。こんな感じ。
なお、micro:bitのI2Cバスについては以下に解説があります。
今回のメイン・プログラム
今回のメインプログラムは、前回使用の「チョイ直し」です。前回のおさらいをすると、
-
- goルーチン(コルーチン?による並行動作機構)によりLED Matrixは動的点灯する(パターン指定されれば)
- キーをプッシュすると割り込みでうけする。AキーとBキーで異なるパターンを設定する(それによってLED表示パターンが即座に変わる)
- メインループは上記とかかわりなく無限ループしながら、10秒置きに温度を測定して標準出力(USBシリアル)に温度を出力する
今回は3のメインループ部分に、「測定した温度をI2C1に接続した外部LCD(AQM1602)に表示する」という機能を追加してみました。前回同様氷点下の温度には対応してないっす。手抜き。
package main
import (
"fmt"
"machine"
"time"
)
var pat = 0
func boardTemperatureC() int {
return int(machine.ReadTemperature() / 1000)
}
func main() {
var msg1 []byte = []byte("Temperature")
var msg2 []byte = []byte("00")
var temp int
dispPattern := []uint32{
0x00000000, 0x01151151, 0x00E8C62E, 0x01FFFFFF,
}
InitLED()
go DispLoop(dispPattern[:])
InitAQM1602()
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 {
temp = boardTemperatureC()
fmt.Printf("TEMP: %d\r\n", temp)
if temp < 99 {
msg2[1] = byte((temp % 10) + 0x30)
msg2[0] = byte((temp / 10) + 0x30)
}
fmt.Printf("CHR: %02x %02x\r\n", msg2[0], msg2[1])
DispStrOnLCD(msg1, msg2)
time.Sleep(time.Second * 10)
}
}
I2C経由のAQM1602インタフェースのコード
以下のコードは、『GoにいればGoに従え(8)』のメインプログラムだったソースを流用して改造したものです。上記のmain.goのお隣にこっそり置いておけばTinyGoが見つけてビルドしてくれます。
package main
import (
"machine"
"time"
)
const AQM1602 = 0x3E
var i2c = machine.I2C1 //micro-bit v2 only
func WriteAQM1602Data(dat byte) {
i2c.WriteRegister(AQM1602, 0x40, []byte{dat})
time.Sleep(1 * time.Millisecond)
}
func WriteAQM1602Command(cmd byte) {
i2c.WriteRegister(AQM1602, 0x00, []byte{cmd})
time.Sleep(20 * time.Millisecond)
}
// micro-bit v2 only
func InitAQM1602() {
i2c.Configure(machine.I2CConfig{
Frequency: machine.TWI_FREQ_100KHZ,
SCL: machine.SCL1_PIN,
SDA: machine.SDA1_PIN,
})
time.Sleep(100 * time.Millisecond)
WriteAQM1602Command(0x38)
WriteAQM1602Command(0x39)
WriteAQM1602Command(0x14)
WriteAQM1602Command(0x77)
WriteAQM1602Command(0x56)
WriteAQM1602Command(0x6C)
WriteAQM1602Command(0x38)
WriteAQM1602Command(0x01)
WriteAQM1602Command(0x0C)
}
func DispStrOnLCD(arg1 []byte, arg2 []byte) {
WriteAQM1602Command(0x01) // Clear Display
WriteAQM1602Command(0x80) // Go to TOP LINE HOME
WriteAQM1602Command(0x00) // End of Command, Data bytes will follow
for i := 0; i < len(arg1); i++ {
WriteAQM1602Data(arg1[i])
}
WriteAQM1602Command(0xC0) // Go to BOTTOM LINE HOME
WriteAQM1602Command(0x00) // End of Command, Data bytes will follow
for i := 0; i < len(arg2); i++ {
WriteAQM1602Data(arg2[i])
}
}
念のためLEDマトリックスの駆動コード
以下のファイルは前回とまったく同じものですが、念のため掲げておきます。
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()
}
}
実機動作確認
例によって以下のようにしてビルド&フラッシュ書き込みします。
$ tinygo flash -target=microbit-v2
microbit v2機でI2C経由でLCDに文字が書けました。
micro:bitのv1.5とv2.0の回路図を以前読んでいた筈なのだけれど完全に忘れてましたな。年寄の忘却力デス。