【ラズパイ】LEDをたくさん点灯させたい!! IOエキスパンダ(MCP23017)によるGPIOポート拡張
「LEDをたくさん点灯させたいけど、ラズパイのGPIOポートでは足りない..さてどうしよう?」
方法を調べてみると、IOエキスパンダ(MCP23017)というデバイスを使えば増設できるということ。 I2Cを使ってラズパイからデータを送ると、16本あるIOエキスパンダのポートをうまいこと制御できる。 さらに、ラズパイ1台に対して最大で8個まで複数接続OK (IOエキスパンダのICアドレスは電流を加えることにより変更可能。それが8通りある) つまり最大、16 x 8 で 128ポート!! これは結構な数です!! 値段も、1個 120円と安価なのがうれしい限り。早速試してみた。
ラズパイ RaspberryPi2(ModelB) I2Cデバイス MCP23017 http://akizukidenshi.com/catalog/g/gI-09486/
ラズパイ側の準備
I2C有効化
#「9 Advanced Options」でI2Cを有効化する $ raspi-config # backlist i2c-bcm2708 が記述してあればコメントアウトする $ cat /etc/modprobe.d/raspi-blacklist.conf # i2c-dev が記述されていること確認(なければ追記する) $ cat /etc/modules
I2C用のコマンドラインツール
$ sudo apt-get install i2c-tools
smbusモジュール(PythonからI2Cを使用するため)
python3対応版があったのでそれを使用
$ sudo apt-get install python3-smbus
$ python3
>> import smbus
ちゃんとimportできること確認
配線
まずは、ラズパイに対してMCP2301が1つの場合の配線。こんな感じになりました。
配線に関してはこちらのサイトを参考にしました。 raspi.tv
I2Cの仕組みについてはここら辺で理解。
実処理は、smbusライブラリに任せるので詳細はなんとなく(←情けないが...)で SCL(Serial Clock)のクロック信号でタイミングを取り、SDA(Serial Data)でデータを通信。 そのときに、SDAでスレーブ側のアドレスとデータを送るということを把握しておきましょうか。
コマンドラインから出力制御
接続デバイスの確認
$ sudo i2cdetect -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: -- -- -- -- -- -- -- --
無事配線が済み、スレーブ側のICアドレスが、0x20であることがわかる。
コマンドラインでデータを送ってみる。以下の形式で実行。
$ sudo i2cset -y 1 [ICアドレス] [レジスタアドレス] [データ]
ICアドレス
上でみた、スレーブ側のICアドレス。今回は、0x20 となる
レジスタアドレス
デバイスのどの機能を使うのかを指定。GPIOポートの初期化や出力など。 レジスタアドレスを指定することによりその機能を使用できる。
ここでデータシートで、各ポートとレジスタアドレスについて確認しておきます。
(引用元:http://akizukidenshi.com/download/ds/microchip/mcp23017_mcp23s17.pdf)
これを踏まえて整理するとこんな感じになります。
使用するレジスタ | 説明 |
---|---|
IODIRA | GPA0(21) 〜 GPA7(28)の出入力設定をする(1:入力、0:出力) IO0 ~ IO7 と GPA0 ~ GPA7 が対応する |
OLATA | GPA0(21) 〜 GPA7(28)の出力制御(出力オン/オフ)を行う OL0 ~ OL7 と GPA0 ~ GPA7 が対応する |
データ
例えば、GPA7, GPA5, GPA3 を出力して、LED点灯を行いたいときは GPA0(21) 〜 GPA7(28) の出力の設定(1:出力する、0:出力しない)をビットで渡してあげれば良いので 0b10101000 となる(GPA7が先頭となる点に注意!!)最終的には、16進数の 0xA8 で渡す。
上記内容をもとにコマンドラインを実行する
使用GPIOピンの初期化
$ sudo i2cset -y 1 0x20 0x00 0x00
LED点灯(GPA7, GPA5, GPA3 を オン)
$ sudo i2cset -y 1 0x20 0x14 0xA8
LED消灯(GPA7, GPA5, GPA3 を オフ)
$ sudo i2cset -y 1 0x20 0x14 0x00
Pythonから制御
シンプルに、指定のピンを5秒点灯したあと消灯するプログラム
基本的には、コマンドでやったことを bus.write_byte_data 関数を使いPythonから行っているのみ。
# -*- coding: utf-8 -*- import smbus import time CHANNEL = 1 # i2c割り当てチャンネル 1 or 0 ICADDR = 0x20 # スレーブ側ICアドレス REG_IODIR = 0x00 # 入出力設定レジスタ REG_OLAT = 0x14 # 出力レジスタ bus = smbus.SMBus(CHANNEL) # ピンの入出力設定 bus.write_byte_data(ICADDR, REG_IODIR, 0x00) # GPA3, GPA5, GPA7 出力オン bus.write_byte_data(ICADDR, REG_OLAT, 0xA8) time.sleep(5) # GPA3, GPA5, GPA7 出力オフ bus.write_byte_data(ICADDR, REG_OLAT, 0x00)
複数接続!!
$ sudo i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: 20 21 -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
スレーブ側のアドレスがきちんと2つになっているのでそれぞれで指定してあげる Pythonのプログラムはこんな感じ
# -*- coding: utf-8 -*- import smbus import time CHANNEL = 1 # i2c割り当てチャンネル 1 or 0 ICADDR1 = 0x20 # スレーブ側ICアドレス1 ICADDR2 = 0x21 # スレーブ側ICアドレス2 REG_IODIR = 0x00 # 入出力設定レジスタ REG_OLAT = 0x14 # 出力レジスタ bus = smbus.SMBus(CHANNEL) # ピンの入出力設定 bus.write_byte_data(ICADDR1, REG_IODIR, 0x00) bus.write_byte_data(ICADDR2, REG_IODIR, 0x00) # GPA3, GPA5, GPA7 出力オン bus.write_byte_data(ICADDR1, REG_OLAT, 0xA8) bus.write_byte_data(ICADDR2, REG_OLAT, 0xA8) time.sleep(5) # GPA3, GPA5, GPA7 出力オフ bus.write_byte_data(ICADDR1, REG_OLAT, 0x00) bus.write_byte_data(ICADDR2, REG_OLAT, 0x00)
これで複数接続ができた。 データシートを読むのはきつかったが実現できました。 さて、たくさんLEDを点灯してみますか♪