gobot I2CでLチカ


1.はじめに

goとgobotを使って、RaspberryPiのI2Cに接続したIOエキスパンダ(MCP23017)を操作してみます。

公式にMCP23017がサポートされてるので、チュートリアルチャレンジで終わるかと思ったら、なんと、サンプルコードが書かれてなかったので、覚え書きを兼ねて簡単にまとめてみました。

実行環境

ハードウェア Raspberry Pi 4
OS Raspbian Buster
go Ver.1.14.3
IOエキスパンダ MCP23017
→これを、RaspberryPiのI2C端子に接続済
$ uname -a
Linux raspi4 4.19.97-v7l+ #1294 SMP Thu Jan 30 13:21:14 GMT 2020 armv7l GNU/Linux
$ go version
go version go1.14.3 linux/arm
$ sudo i2cdetect -r -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --    

2.準備

インストールは別記事で解説しているので、詳細はそちらをご覧下さい。

3.LEDの点滅例

MCP23017のポートAのピン0~7につないだLEDを、流れるように点灯する例です。
こちらのドキュメントを参考12に書いてみました。

重要な関数は以下の通りです。

  • i2c.NewMCP23017Driver
i2c.WithBus(1) ラズパイのi2cは1です。(1を指定している例:$ sudo i2cdetect -r -y 1
i2c.WithAddress(0x20) MCP23017の設定にあわせます。(ここでは0x20)
  • WriteGPIO(ピン番号, 値, ポート名)
    • 値は0:消灯、1:点灯
    • ポート名は文字列で指定、"A"あるいは"B"
raspi_blink_i2c.go
package main

import (
    "time"

    "gobot.io/x/gobot"
    "gobot.io/x/gobot/drivers/i2c"
    "gobot.io/x/gobot/platforms/raspi"
)

func main() {
    //初期化
    raspiAdaptor := raspi.NewAdaptor()
    //MCP23017の初期化
    //I2Cバス1番、アドレス0x20
    i2cexp := i2c.NewMCP23017Driver(raspiAdaptor,
        i2c.WithBus(1),
        i2c.WithAddress(0x20))

    //LEDを流れるように点灯するための制御変数
    //pin: ピン番号0から開始
    //val: 点灯1状態から開始
    var pin, val uint8
    pin, val = 0, 1

    //定期実行
    work := func() {
        //100ms毎にループ
        gobot.Every(100*time.Millisecond, func() {

            //ポートAのピンを点灯/消灯
            i2cexp.WriteGPIO(pin, val, "A")

            //ピン番号を次に移動
            pin++
            if pin > 7 {
                //ピン番号7になったら、ピン番号を0に戻す
                pin = 0
                if val == 1 {
                    //現在が点灯1状態なら、次は消灯0状態に
                    val = 0
                } else {
                    //次は点灯1状態に
                    val = 1
                }
            }
        })
    }

    robot := gobot.NewRobot("bot",
        []gobot.Connection{raspiAdaptor},
        //デバイスに追加
        []gobot.Device{i2cexp},
        work,
    )

    robot.Start()
}

実行

コマンドライン
$ go run raspi_blink_i2c.go 
2020/05/31 20:56:29 Initializing connections...
2020/05/31 20:56:29 Initializing connection RaspberryPi-308BFB50 ...
2020/05/31 20:56:29 Initializing devices...
2020/05/31 20:56:29 Initializing device MCP23017-6301D4B5 ...
2020/05/31 20:56:29 Robot bot initialized.
2020/05/31 20:56:29 Starting Robot bot ...
2020/05/31 20:56:29 Starting connections...
2020/05/31 20:56:29 Starting connection RaspberryPi-308BFB50...
2020/05/31 20:56:29 Starting devices...
2020/05/31 20:56:29 Starting device MCP23017-6301D4B5...
2020/05/31 20:56:29 Starting work...
2020/05/31 20:58:30 Stopping Robot bot ...
[Ctrl-C]
$

下記の動画、下の方の8つのLEDが、左から右へ流れています。

4.おわりに

残課題としては、[Ctrl-C]で止めたときに、IOエキスパンダを全て消灯することです。

現状のままだと、制御が止まった時点の点灯が残ってしまいます。
こちら3を参考に、SIGINT捕捉後にIOエキスパンダのピン番号全てにLを送って消灯するプログラムを試しましたが、どうやらwork := func() {の実行が生きている間に消灯処理を入れないとダメなようです。(今の所、解決できてません)

参考資料