Joseph Halfmoon
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バスについては以下に解説があります。
Use of the I2C bus
今回のメイン・プログラム
今回のメインプログラムは、前回使用の「チョイ直し」です。前回のおさらいをすると、
goルーチン(コルーチン?による並行動作機構)によりLED Matrixは動的点灯する(パターン指定されれば)
キーをプッシュすると割り込みでうけする。AキーとBキーで異なるパターンを設定する(それによってLED表示パターンが即座に変わる)
メインループは上記とかかわりなく無限ループしながら、10秒置きに温度を測定して標準出力(USBシリアル)に温度を出力する
今回は3のメインループ部分に、「測定した温度をI2C1に接続した外部LCD(AQM1602)に表示する」という機能を追加してみました。前回同様氷点下の温度には対応してないっす。手抜き。
func boardTemperatureC () int {
return int ( machine. ReadTemperature () / 1000 )
var msg1 [] byte = [] byte ( "Temperature" )
var msg2 [] byte = [] byte ( "00" )
0x00000000 , 0x01151151 , 0x00E8C62E , 0x01FFFFFF ,
go DispLoop ( dispPattern [ : ])
keyA. Configure ( machine. PinConfig { Mode: machine. PinInput })
keyB. Configure ( machine. PinConfig { Mode: machine. PinInput })
keyA. SetInterrupt ( machine. PinFalling , func ( machine. Pin ) {
keyB. SetInterrupt ( machine. PinFalling , func ( machine. Pin ) {
temp = boardTemperatureC ()
fmt. Printf ( "TEMP: %d\r\n" , temp )
msg2 [ 1 ] = byte (( temp % 10 ) + 0x30 )
msg2 [ 0 ] = byte (( temp / 10 ) + 0x30 )
fmt. Printf ( "CHR: %02x %02x\r\n" , msg2 [ 0 ] , msg2 [ 1 ])
time. Sleep ( time. Second * 10 )
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)
}
}
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が見つけてビルドしてくれます。
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 )
i2c. Configure ( machine. I2CConfig {
Frequency: machine. TWI_FREQ_100KHZ ,
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 ])
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])
}
}
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マトリックスの駆動コード
以下のファイルは前回とまったく同じものですが、念のため掲げておきます。
func DispLoop ( dispPattern [] uint32 ) {
DispLED1 ( dispPattern [ pat ])
DispLED2 ( dispPattern [ pat ])
DispLED3 ( dispPattern [ pat ])
DispLED4 ( dispPattern [ pat ])
DispLED5 ( dispPattern [ pat ])
time. Sleep ( time. Millisecond * 7 )
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 })
func SetLED ( arg uint32 ) {
if ( arg & 0x01084210 ) != 0 {
if ( arg & 0x00842108 ) != 0 {
if ( arg & 0x00421084 ) != 0 {
if ( arg & 0x00210842 ) != 0 {
if ( arg & 0x00108421 ) != 0 {
func DispLED1 ( arg uint32 ) {
if ( arg & 0x01F00000 ) != 0 {
func DispLED2 ( arg uint32 ) {
if ( arg & 0x000F8000 ) != 0 {
func DispLED3 ( arg uint32 ) {
if ( arg & 0x00007C00 ) != 0 {
func DispLED4 ( arg uint32 ) {
if ( arg & 0x000003E0 ) != 0 {
func DispLED5 ( arg uint32 ) {
if ( arg & 0x0000001F ) != 0 {
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()
}
}
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の回路図を以前読んでいた筈なのだけれど完全に忘れてましたな。年寄の忘却力デス。
GoにいればGoに従え(12) TinyGo、micro:bit v2、キーと温度センサ確認 へ戻る
GoにいればGoに従え(14) TinyGo、micro:bit v2、CDSセンサ読み取り へ進む