目的
マイコンのI/OポートをMCP23017で増設してみる。
ハード・ソフト
- Mac Studio(2022)
- M5StickCPlus
- MCP23017
- VSCode(PlatformIO)
MCP23017とは??
MCP23017とはI2C通信によってI/Oポートの増設及び制御を行えるIC(I/Oエキスパンダ)です。
今回は以下のサイトを参考にして実装してみました。
データシートは以下のサイトに載っています。
こちらはデータシートからの引用になりますが、I/Oポートとして機能するのはGPA[0:7]とGPB[0:7]の計16ポートになります。
回路
今回は以下のような配線で実装しました。
この状態だと LEDはMCP23017からの信号を電源として使用しているので実用的ではありませんがご了承ください。
使用しているマイコンはM5StickCPlusで、I2C通信によってMCP23017を扱っています。
MCP23017側のA0〜2に関してはI2Cのアドレスを設定する部分ですので今回は全てグランドのデフォルト状態(0x20)の状態で実装します。
コード
コードはVSCode内の拡張機能「PlatformIO」を使用して書き込んでいます。こちらの記事を参考にセットアップしましたので参考にどうぞ。
M5StickCPlusのコードについて、MCP23017を用いた解説を行っていた以下の記事を参考に書かせていただいております。(ほぼ変更なし)
#include <Wire.h>
#include <M5StickCPlus.h>
#define MCP23017_IODIRA 0x00
#define MCP23017_IODIRB 0x01
#define MCP23017_IPOLA 0x02
#define MCP23017_IPOLB 0x03
#define MCP23017_GPINTENA 0x04
#define MCP23017_GPINTENB 0x05
#define MCP23017_DEFVALA 0x06
#define MCP23017_DEFVALB 0x07
#define MCP23017_INTCONA 0x08
#define MCP23017_INTCONB 0x09
#define MCP23017_IOCON 0x0a
#define MCP23017_GPPUA 0x0c
#define MCP23017_GPPUB 0x0d
#define MCP23017_INTFA 0x0e
#define MCP23017_INTFB 0x0f
#define MCP23017_INTCAPA 0x10
#define MCP23017_INTCAPB 0x11
#define MCP23017_GPIOA 0x12
#define MCP23017_GPIOB 0x13
#define MCP23017_OLATA 0x14
#define MCP23017_OLATB 0x15
宣言部分になりますが、ほぼMCP23017関連の部分です。
//---------------------------------------------------------
// I2CバスにWriteアクセスする
//---------------------------------------------------------
//[Arguments]
// slave_addr : スレーブデバイスのアドレス
// device_addr : デバイス内部のレジスタアドレス
// data : 書き込むデータ
//[Returns]
// なし
//--------------- https://ss1.xrea.com/tmct.s1009.xrea.com/
void i2cWriteByte(int slave_addr, int device_addr, int data) {
Wire.beginTransmission(slave_addr);
Wire.write(device_addr);
Wire.write(data);
Wire.endTransmission();
}
//---------------------------------------------------------
// I2CバスにReadアクセスする
//---------------------------------------------------------
//[Arguments]
// slave_addr : スレーブデバイスのアドレス
// device_addr : デバイス内部のレジスタアドレス
//[Returns]
// unsigned char : 読みだしたデータ
//--------------- https://ss1.xrea.com/tmct.s1009.xrea.com/
unsigned char i2cReadByte(int slave_addr, int device_addr) {
unsigned char r;
Wire.beginTransmission(slave_addr);
Wire.write(device_addr);
Wire.endTransmission();
Wire.requestFrom(slave_addr, 1);
if (Wire.available()) r = Wire.read();
Wire.endTransmission();
return(r);
}
この箇所は参考にさせていただいた記事のまま、i2cによる書き込み、読み取り関数が書かれています。
void setup(){
Wire.begin(0, 26); // I2C通信端子指定(SDA, SCL)
M5.begin();// m5の初期化
}
この部分ではM5StickCPlusのI2C通信用端子の設定、初期化を行なっています。(初期化を行わなかった際に5Vの出力が得られませんでした。)
void loop(){
// unsigned char work;
//---------------------------------------------------------
// 初期化
//---------------------------------------------------------
// 出力初期値を設定する
// 各ビット 1 = High, 0 = Low になります
// 入力に設定するビットは何でも構いませんが初期値の0に設定します
i2cWriteByte(0x20, MCP23017_OLATA, 0x00); // GPA[7:0] = 'LLLL_LLLL'
i2cWriteByte(0x20, MCP23017_OLATB, 0x00); // GPB[7:0] = 'LLLL_LLLL'
// 入力論理を設定する
// 各ビット 1 = 負論理, 0 = 正論理 になります
// 出力に設定するビットは何でも構いませんが初期値の0に設定します
i2cWriteByte(0x20, MCP23017_IPOLA, 0x00); // GPA[7:0] = 全ビット正論理
i2cWriteByte(0x20, MCP23017_IPOLB, 0x00); // GPB[7:0] = 全ビット正論理
// 入力PullUpを設定する
// 各ビット 1 = PullUp ON, 0 = PullUp OFF になります
// 出力に設定するビットは何でも構いませんが初期値の0に設定します
i2cWriteByte(0x20, MCP23017_GPPUA, 0x00); // GPA[7:0] = 内部PullUp OFF
i2cWriteByte(0x20, MCP23017_GPPUB, 0xff); // GPB[7:0] = 内部PullUp ON
// 入出力方向を設定する
// 各ビット 1 = 入力, 0 = 出力 になります
// 出力ポートの場合、出力に設定した瞬間に出力初期値で設定した論理レベルが出力されます
i2cWriteByte(0x20, MCP23017_IODIRA, 0x00); // GPA[7:0] = 出力
i2cWriteByte(0x20, MCP23017_IODIRB, 0xff); // GPB[7:0] = 全ビット入力
M5.Axp.EnableCoulombcounter();// 5V出力開始
//---------------------------------------------------------
// LEDを点灯
//---------------------------------------------------------
// LEDを点灯
i2cWriteByte(0x20, MCP23017_OLATA, 0xff); // GPA[7:0] = 'HHHH_HHHH'
delay(300); // 300ms wait
// LEDを消灯
i2cWriteByte(0x20, MCP23017_OLATA, 0x00); // GPA[7:0] = 'LLLL_LLLL'
delay(300); // 300ms wait
}
ほとんどの部分が参考にさせていただいた記事のままになっていますが、入出力設定やLEDの点灯部分で改変をした箇所があります。
(GPAポートを全て出力用にしてあり、LEDが繋がっていない箇所もプルアップしていますが実装する際には設定を見直すことをお勧めします。)
これにて複数のLEDが点滅を繰り返すだけのコードが完成しました。

