MCP23017 "I2C"のピン配置と配線
No. | Name | Type | Function | Type | Name | No. | |
---|---|---|---|---|---|---|---|
1 | GPB0 | I/O | 双方向入出力ピンです。 "変更時割り込み"(IOC:Interrupt-on-change)または内臓の微弱なプルアップ抵抗、あるいはその両方を有効化出来ます。 |
I/O | GPA7 | 28 | |
2 | GPB1 | GPA6 | 27 | ||||
3 | GPB2 | GPA5 | 26 | ||||
4 | GPB3 | GPA4 | 25 | ||||
5 | GPB4 | GPA3 | 24 | ||||
6 | GPB5 | GPA2 | 23 | ||||
7 | GPB6 | GPA1 | 22 | ||||
8 | GPB7 | GPA0 | 21 | ||||
9 | VDD | P | 電源 1.8〜5.5V | PORTA B 割り込み出力 |
O | INTA | 20 |
10 | VSS | グランド | INTB | 19 | |||
11 | NC | 未接続 | ハードウェアリセット | I | RESET | 18 | |
12 | SCL | I | シリアルクロック入力 | ハードウェア アドレスピン |
I | A2 | 17 |
13 | SDA | I/O | シリアルデータ入出力 | A1 | 16 | ||
14 | NC | 未接続 | A0 | 15 |
A、Bの各GPIOは8個なので1byte(8bit)単位で管理しやすいのと、8bitのみのMCP23008という製品もあるので、その辺りも兼ね合いがあるのかもですけどね。
では、実際の配線を見ながら確認。
SCLSDAは、ざっくり10kΩの抵抗でプルアップ。正確を喫するなら要抵抗値計算。
A0A1A2の3つは、以下の様にプルアップ、プルダウンして4 ビット固定アドレスに続くハードウェアアドレスビットを定義するために用います。この計7ビットがスレーブアドレスとなります。
D7 | D6 | D5 | D4 | D3 | D2 | D1 |
---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | A2 | A1 | A0 |
0 | 1 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 0 | 0 | 1 |
0 | 1 | 0 | 0 | 0 | 1 | 0 |
0 | 1 | 0 | 0 | 0 | 1 | 1 |
0 | 1 | 0 | 0 | 1 | 0 | 0 |
0 | 1 | 0 | 0 | 1 | 0 | 1 |
0 | 1 | 0 | 0 | 1 | 1 | 0 |
0 | 1 | 0 | 0 | 1 | 1 | 1 |
以上で検証に必要な配線は完了。
MivroPythonでMCP23017へI2Cで接続
ここから先は、NodeMCU DevKitでの作業。データシートでは、スレーブアドレスに以下のようにR/Wビットを続けて制御バイトとして送信する旨記載されていますが、MicroPythonでは直接指定しないのでスルー。
制御バイト | |||||||||
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | ||
---|---|---|---|---|---|---|---|---|---|
Start bit | 0 | 1 | 0 | 0 | A2 | A1 | A0 | R/W | ACK bit |
スレーブアドレス | Read : 1 Write : 0 |
||||||||
NodeMCUを起動して、必要となるI2CとPinクラスををインポート。
Ctrl + eを押してからコピペしてCtrl + d。
MicroPython v1.10-8-g8b7039d7d on 2019-01-26; ESP module with ESP8266
Type "help()" for more information.
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
===
=== from machine import I2C, Pin
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000) # I2C、Pinクラスのインポート
# I2Cオブジェクトの作成
===
>>>
freqは、400kHzで指定していますが、MCP23017では、1.7MHzでも稼働出来るようです。ただし、電圧が4.5~5.5V必要となるためNodeMCU(3.3V駆動)では使用しません。Type "help()" for more information.
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
===
=== from machine import I2C, Pin
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000) # I2C、Pinクラスのインポート
# I2Cオブジェクトの作成
===
>>>
I2Cでの接続確認は、以下。
>>>
i2c.scan()
[32]
>>>
正常に接続されていればスレーブアドレスが10進数で表示。"32"は、16進数だと"0x20"。[32]
>>>
下記は、以降で使用するI2Cの主だったメソッド。
I2C.readfrom_mem(addr, memaddr, nbytes, *, addrsize=8)
addr:スレーブアドレス - 0x20〜0x27
memaddr:メモリアドレス / レジスタアドレス
nbytes:読み込むデータサイズをbyte単位で指定
addrsize:アドレスサイズ(ESP8266では8bit固定で使用不可)
addr:スレーブアドレス - 0x20〜0x27
memaddr:メモリアドレス / レジスタアドレス
nbytes:読み込むデータサイズをbyte単位で指定
addrsize:アドレスサイズ(ESP8266では8bit固定で使用不可)
I2C.writeto_mem(addr, memaddr, buf, *, addrsize=8)
addr:スレーブアドレス - 0x20〜0x27
memaddr:メモリアドレス / レジスタアドレス
buf:バッファ / byte型 - コマンド/データ
addrsize:アドレスサイズ(ESP8266では8bit固定で使用不可)
bufは、コマンドとデータをまとめて書く事も可能ですが、ここでは理解しやすいように分けて書くようにしています。興味のある方は試してみて下さい。
addr:スレーブアドレス - 0x20〜0x27
memaddr:メモリアドレス / レジスタアドレス
buf:バッファ / byte型 - コマンド/データ
addrsize:アドレスサイズ(ESP8266では8bit固定で使用不可)
MivroPythonでMCP23017の操作
MCP23017の操作は、基本的に以下のレジスタアドレスを呼び出して読み書きするだけです。それ以上も以下も出来ません。MCP23017のレジスタアドレス | |||
---|---|---|---|
Access to: | Address IOCON.BANK = 0 |
Address IOCON.BANK = 1 |
Function |
IODIRA | 0x00(0b00000) | 0x00(0b00000) | I/O方向レジスタ 0:OUTPUT/1:INPUT |
IODIRB | 0x01(0b00001) | 0x10(0b10000) | |
IPOLA | 0x02(0b00010) | 0x01(0b00001) | 入力極性ポートレジスタ 0:same logic state/1:opposite logic state |
IPOLB | 0x03(0b00011) | 0x11(0b10001) | |
GPINTENA | 0x04(0b00100) | 0x02(0b00010) | 状態変化割り込みピン設定レジスタ 0:Disable/1:Enable |
GPINTENB | 0x05(0b00101) | 0x12(0b10010) | |
DEFVALA | 0x06(0b00110) | 0x03(0b00011) | 状態変化割り込み用の既定値
コンペアレジスタ 7〜0 bitに比較値を設定 |
DEFVALB | 0x07(0b00111) | 0x13(0b10011) | |
INTCONA | 0x08(0b01000) | 0x04(0b00100) | 状態変化割り込み制御レジスタ 0:ピンの変化のみ参照/1:DEFVAL設定値との比較参照 |
INTCONB | 0x09(0b01001) | 0x14(0b10100) | |
IOCON | 0x0A(0b01010) | 0x05(0b00101) | I/Oエクスパンダコンフィグレーションレジスタ 7〜1 bitで設定 |
IOCON | 0x08(0b01011) | 0x15(0b10101) | |
GPPUA | 0x0C(0b01100) | 0x06(0b00110) | GPIOプルアップ抵抗レジスタ 0:無効化 / 1:有効化 |
GPPUB | 0x0D(0b01101) | 0x16(0b10110) | |
INTFA | 0x0E(0b01110) | 0x07(0b00111) | 割り込みフラグレジスタ ※読込みのみ 0:割り込み無し/1:割り込みを発生 |
INTFNB | 0x0F(0b01111) | 0x17(0b10111) | |
INTCAPA | 0x10(0b10000) | 0x08(0b01000) | 割り込み発生ポート値レジスタ ※読込みのみ 0:Low / 1:High |
INTCAPB | 0x11(0b10001) | 0x18(0b11000) | |
GPIOA | 0x12(0b10010) | 0x09(0b01001) | 汎用I/Oポ ートレジスタ 0:Low / 1:High |
GPIOB | 0x13(0b10011) | 0x19(0b11001) | |
OLATA | 0x14(0b10100) | 0x0A(0b01010) | 出力ラッチレジスタ 0:Low / 1:High |
OLATNB | 0x15(0b10101) | 0x0A(0b11010) |
これは、A、B二つのグループのレジスタアドレスを連続して(16bit)管理するか、分割して(8bit)管理するのかの違いです。BANK 1のアドレスは一見バラバラに見えますがBANK 0を右ビットローテーション(環状シフト)した値に統一されています。
ちなみに、ビットローテーションとは以下の様な働き。
この辺りの設定はコンフィグレーションレジスタ(IOCON)で行い、標準でBank0になるように設定されています。
話が外れはじめたので、実際にレジスタアドレスを読み込んで値を確認。
>>>
i2c.readfrom_mem(0x20, 0x00, 1)
b'\xff'
>>>
I/O方向レジスタレジスタ(IODIRA)の値を取得してみました。b'\xff'
>>>
結果b'\xff'('0b11111111')の戻り値。
IODIRAは、0:OUTPUT/1:INPUTなので、全てのGPIOが入力に設定されているようです。
取得された値の上位ビットから下位ビットへの並びは、GPIOポートGPx7〜GPx0の並びに対応しています。
書込みも試してみます。
>>>
>>> i2c.writeto_mem(0x20, 0x00, b'\x55')
i2c.readfrom_mem(0x20, 0x00, 1)
b'\x55'
>>>
IODIRAへ0x55(0b01010101)の値を書き込み、戻り値を確認。>>> i2c.writeto_mem(0x20, 0x00, b'\x55')
i2c.readfrom_mem(0x20, 0x00, 1)
b'\x55'
>>>
ちょっと動作がわかりづらいのでLEDを繋いでみましょう。
MivroPythonとMCP23017でLチカ
まずは、ブレッドボードを増設してLEDを配線。ちゃんと抵抗値を計算して接続しましょう!
って事で、Lチカコード。
from time import sleep from machine import I2C, Pin i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000) i2c.writeto_mem(0x20, 0x00, b'\x00') for i in range(10) : i2c.writeto_mem(0x20, 0x12, b'\xFF') sleep(0.5) i2c.writeto_mem(0x20, 0x12, b'\x00') sleep(0.5)8個のLEDがまとまって点滅するので、眩しいです。
続いて、もう少しヒネったLチカ。
from time import sleep from machine import I2C, Pin i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000) i2c.writeto_mem(0x20, 0x00, b'\x00') b = 0xFF for i in range(10) : i2c.writeto_mem(0x20, 0x12, b'\xFF') sleep(0.5) i2c.writeto_mem(0x20, 0x12, b'\x00') sleep(0.5) for i in range(7) : i2c.writeto_mem(0x20, 0x12, b.to_bytes(1, 'big')) sleep(0.5) b = b >> 1 for i in range(9) : i2c.writeto_mem(0x20, 0x12, b.to_bytes(1, 'big')) sleep(0.5) b = b << 110回点滅したあと、一つづつ点灯しているLEDが現象し、残った1つが左方向に移動して消灯するだけのコード。
0 件のコメント:
コメントを投稿