ℹ️ 関連記事
本記事はESP32での実装例です。Arduino Uno R4での実装やループバックテストによる動作検証を知りたい方はこちら:
👉 【Arduinoで電子工作】MCP23017で「16本の足」を生やす完全ガイド & 自己診断テスト
はじめに
ESP32やArduinoで電子工作をしていると、「ピンが足りない!」という状況に直面することがあります。LEDを大量に制御したい、スイッチ入力が多い、センサーを複数接続したい…そんな時に活躍するのがI/Oエキスパンダーです。
本記事では、I2C通信で簡単に16ピンを追加できるMCP23017の使い方を回路図付き実装例とともに詳しく解説します。最新のAdafruit_MCP23X17ライブラリのサンプルコードも掲載しているので、すぐに動作確認できます。
この記事で学べること
- MCP23017の使い方・基本仕様とピンアサイン
- I2Cアドレス設定と複数デバイス接続(最大8個、128ピン)
- MCP23017の回路図付き実装例(LED出力+スイッチ入力)
- 最新Adafruit_MCP23X17ライブラリの使い方とサンプルコード
- 入出力制御のプログラミング手法とトラブルシューティング
MCP23017とは?GPIO拡張の主な用途と基礎知識
I/Oエキスパンダーが必要な理由
マイコンを使った電子工作では、以下のような場面でピン不足に悩まされます:
- LED制御: マトリクスLEDや7セグメントLEDで多数のピンが必要
- スイッチ入力: ボタンやセンサーの入力点数が多い
- 複合プロジェクト: ディスプレイ + センサー + モーターなど複数デバイス制御
I/Oエキスパンダーを使えば、この問題を簡単に解決できます:
| 用途 | 担当デバイス |
|---|---|
| 単純な入出力 | I/Oエキスパンダー(MCP23017) |
| AD変換、PWM制御 | マイコン本体のピン |
このように用途に応じて使い分けることで、効率的なシステム設計が可能になります。
MCP23017の特徴
Amazon でも入手できます。
※本記事にはアフィリエイトリンク(Amazon アソシエイト)が含まれます。
MCP23017は、Microchip Technology社製の16ビットI/O GPIOエキスパンダーです。I2C通信を使って簡単に制御できるため、ESP32やArduinoとの相性が抜群です。
MCP23017の仕様と回路設計
データシートから読み解く基本仕様
MCP23017ピンアサイン
主要仕様
| 項目 | 仕様 |
|---|---|
| 通信方式 | I2C(400kHz対応) |
| 動作電圧 | 1.8V~5.5V(ESP32の3.3Vで動作可) |
| 入出力ピン数 | 16ピン(GPA0~GPA7 / GPB0~GPB7) |
| 最大駆動電流 | 25mA/ピン |
| 同時接続数 | 最大8個(I2Cアドレス設定により) |
I2Cアドレス設定の仕組み
MCP23017は3本のアドレスピン(A0, A1, A2)の組み合わせで、最大8個のデバイスを1つのI2Cバスに接続できます。
アドレス設定表
| A2 | A1 | A0 | I2Cアドレス | 旧ライブラリでの指定値(現行では使用しません) |
|---|---|---|---|---|
| 0 | 0 | 0 | 0x20 | 0(デフォルト) |
| 0 | 0 | 1 | 0x21 | 1 |
| 0 | 1 | 0 | 0x22 | 2 |
| 0 | 1 | 1 | 0x23 | 3 |
| 1 | 0 | 0 | 0x24 | 4 |
| 1 | 0 | 1 | 0x25 | 5 |
| 1 | 1 | 0 | 0x26 | 6 |
| 1 | 1 | 1 | 0x27 | 7 |
ライブラリの世代によって、指定する値が違うためです。
- 現行の
Adafruit_MCP23X17:mcp.begin_I2C(0x20)のように、I2Cアドレス(0x20〜0x27)をそのまま渡します。 本記事のサンプルコードもこの方式です。 - 旧
Adafruit_MCP23017:0〜7 のインデックスで指定する方式でした。右端の列は、古い記事やコードを読むときの対応表として残してあります。
これから書くコードでは、右端の0〜7ではなく、「I2Cアドレス」列の値(0x20〜0x27)を使ってください。
重要: A0~A2ピンは0(GND)または1(VDD)に接続します。フローティング(未接続)は避けましょう。
驚異の拡張性:最大128ピン
- 1個のMCP23017 → 16ピン
- 8個接続 → 128ピン
これだけあれば、ほとんどのプロジェクトでピン不足に悩むことはありません。
MCP23017のその他の機能
- 内部プルアップ抵抗: 100kΩのプルアップを各ピンに設定可能
- 割り込み機能: ピンの状態変化を検出してマイコンに通知
- ポート単位の制御: 8ビットまとめて読み書き可能
実装回路例:スイッチ入力とLED出力(MCP23017の主な用途)
回路の構成
今回は、MCP23017の機能を検証するために以下の構成で回路を作成しました:
- 入力: スイッチ 3個(GPB0~GPB2)
- 出力: LED 8個(GPA0~GPA7)
- アドレス設定: A0, A1, A2すべてGND(アドレス0x20)
MCP23017テスト回路図
回路のポイント
- アドレス設定ピン: A0, A1, A2にプルダウン抵抗を接続してGNDに固定
- スイッチ入力: プルダウン抵抗付きで、押すとHIGH入力
- LED出力: 電流制限抵抗を介してLEDを接続
ブレッドボード実装
ブレッドボードへの実装例
ESP32との接続
| ESP32 | MCP23017 |
|---|---|
| 3.3V | VDD |
| GND | VSS, A0, A1, A2 |
| GPIO21 (SDA) | SDA |
| GPIO22 (SCL) | SCL |
重要: I2Cプルアップ抵抗(4.7kΩ程度)をSDA、SCL両方に接続してください。
Adafruit_MCP23X17ライブラリのセットアップ
ライブラリのインストール
Arduino IDEのライブラリマネージャーから「Adafruit MCP23017」で検索し、Adafruit MCP23XXX libraryをインストールします。
または、以下のコマンドでもインストール可能:
ライブラリマネージャー → "Adafruit MCP23XXX" → インストール
必要な依存ライブラリ
Adafruit_MCP23X17ライブラリは、以下のライブラリも自動的にインストールします:
- Adafruit BusIO
- Wire(標準ライブラリ)
サンプルプログラム:スイッチでLEDパターン切替
完全なコード
#include <Wire.h>
#include <Adafruit_MCP23X17.h>
Adafruit_MCP23X17 mcp;
int sw1, sw2, sw3;
void setup() {
delay(1000);
Serial.begin(115200);
// MCP23017の初期化
if (!mcp.begin_I2C(0x20)) { // アドレス0x20で初期化
Serial.println("MCP23017 not found!");
while (1);
}
Serial.println("MCP23017 initialized");
// GPA0~GPA7を出力に設定(LED用)
for (int i = 0; i < 8; i++) {
mcp.pinMode(i, OUTPUT);
}
// GPB0~GPB2を入力に設定(スイッチ用)
mcp.pinMode(8, INPUT);
mcp.pinMode(9, INPUT);
mcp.pinMode(10, INPUT);
delay(1000);
}
void loop() {
// スイッチの状態を読み取り
sw1 = mcp.digitalRead(8);
sw2 = mcp.digitalRead(9);
sw3 = mcp.digitalRead(10);
Serial.print("SW1:"); Serial.print(sw1);
Serial.print(" SW2:"); Serial.print(sw2);
Serial.print(" SW3:"); Serial.println(sw3);
// スイッチの組み合わせでLEDパターンを変更
if (sw1 == 1 && sw2 == 0 && sw3 == 0) {
// モード1: 前半4つ点灯
Serial.println("Mode 1: Front LEDs ON");
for (int i = 0; i < 4; i++) mcp.digitalWrite(i, HIGH);
for (int i = 4; i < 8; i++) mcp.digitalWrite(i, LOW);
} else if (sw1 == 0 && sw2 == 1 && sw3 == 0) {
// モード2: 後半4つ点灯
Serial.println("Mode 2: Back LEDs ON");
for (int i = 0; i < 4; i++) mcp.digitalWrite(i, LOW);
for (int i = 4; i < 8; i++) mcp.digitalWrite(i, HIGH);
} else if (sw1 == 0 && sw2 == 0 && sw3 == 1) {
// モード3: 全点灯
Serial.println("Mode 3: All LEDs ON");
for (int i = 0; i < 8; i++) mcp.digitalWrite(i, HIGH);
} else {
// モード0: 全消灯
Serial.println("Mode 0: All LEDs OFF");
for (int i = 0; i < 8; i++) mcp.digitalWrite(i, LOW);
}
delay(100);
}
Adafruit_MCP23X17ライブラリ関数リファレンス
-
mcp.begin_I2C(addr):I2C通信の開始
MCP23017とのI2C通信を開始します。( )内には、A0〜A2ピンの配線に応じたI2Cアドレス(0x20〜0x27)を指定します。どの値になるかは、上の「アドレス設定表」を参照してください。 例:A0〜A2をすべてGNDに接続した場合(0x20) mcp.begin_I2C(0x20); A0のみVDDに接続した場合(0x21) mcp.begin_I2C(0x21); 本記事のサンプルコードはA0〜A2をすべてGNDに落としているためmcp.begin_I2C(0x20)としています。チップから応答がない場合はfalseを返すので、うまく動かないときはまずこの戻り値を確認してください。 -
mcp.pinMode(pin, mode):ピンのモード設定(0〜7がGPA0〜GPA7, 8〜15がGPB0〜GPB7)
それぞれのピンの入出力モードを設定します。 pinにはピン番号を設定します。GPA0〜GPA7は0〜7に、GPB0〜GPB7は8〜15にそれぞれ対応しています。 modeにはピン番号に対する入出力モードを設定します。出力なら"OUTPUT"を、入力なら"INPUT"を入力します。ピン番号によって入出力の向きが決まるわけではなく、どのピンもOUTPUT/INPUTを自由に設定できます。 本記事で0〜7を出力、8〜10を入力にしているのは、LEDとスイッチをそのように配線した回路側の都合です。 -
mcp.digitalRead(pin):入力状態の取得(1=HIGH, 0=LOW)
指定ピン番号の入力状態を確認します。HIGHが入力されていたら1を、LOWが入力されていたら0を返します。 -
mcp.digitalWrite(pin, val):ピンに出力(1=HIGH, 0=LOW)
指定ピン番号の出力を設定します。val = 0ならLOWを、val = 1ならHIGHを出力します。
実際の動作
実際に動作させると以下の動画のようになります。
スイッチの状態に応じて、LEDの点灯パターンがリアルタイムで変化しています。これでMCP23017の基本的な入出力制御が実現できました。
動作の詳細
- スイッチ1のみON: 前半4個のLED(GPA0~GPA3)が点灯
- スイッチ2のみON: 後半4個のLED(GPA4~GPA7)が点灯
- スイッチ3のみON: 全8個のLEDが点灯
- 全スイッチOFF: 全LEDが消灯
MCP23017の主な用途・応用例(LEDマトリクス・リレー・センサー集約)
MCP23017の16ピン拡張を活用したプロジェクト例を紹介します。
1. 大型LEDマトリクス制御
8×8のLEDマトリクスなら、MCP23017を1個使って行列制御が可能です。さらに複数接続すれば、16×16以上の大型ディスプレイも実現できます。
2. 多ボタン入力システム
最大16個のボタンやスイッチを1つのMCP23017で管理。内部プルアップ機能を使えば、外付け抵抗も不要です。
3. リレー制御ボード
8個のリレーを制御して、家電製品やモーターの ON/OFF を自動化。スマートホームプロジェクトに最適です。
4. センサー集約システム
複数のデジタルセンサー(温湿度、人感、ドア開閉など)の入力をMCP23017に集約し、ESP32のピンを節約します。
トラブルシューティング
MCP23017が認識されない
症状: begin_I2C()がfalseを返す
チェック項目:
- I2Cプルアップ抵抗: SDA、SCLに4.7kΩのプルアップを接続
- 電源電圧: VDDに3.3Vまたは5Vが正しく供給されているか確認
- アドレス設定: A0, A1, A2が正しく接続されているか(フローティングNG)
- 配線: SDA/SCLが逆接続されていないか確認
I2Cスキャナーで確認:
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(115200);
Serial.println("I2C Scanner");
for (byte address = 1; address < 127; address++) {
Wire.beginTransmission(address);
if (Wire.endTransmission() == 0) {
Serial.print("Device found at 0x");
Serial.println(address, HEX);
}
}
}
void loop() {}
LEDが正しく点灯しない
チェック項目:
- 電流制限抵抗: 各LEDに330Ωまたは適切な抵抗を接続
- 電流容量: MCP23017の最大駆動電流は25mA/ピン
- プログラム:
pinMode()で正しくOUTPUTに設定されているか確認
スイッチ入力が不安定
対策:
- プルアップ/プルダウン: 内部プルアップを有効化
pinMode(pin, INPUT_PULLUP) - チャタリング除去: ソフトウェアでデバウンス処理を追加
- 配線: 入力ピンがフローティングになっていないか確認
他のマイコンでの使い方
MCP23017はI2C通信で動作するため、ESP32以外のマイコンでも同様に使用できます。
| マイコン | 接続先ピン | 参考 |
|---|---|---|
| ESP32 | GPIO21 (SDA) / GPIO22 (SCL) | 本記事 |
| Arduino Uno R4 | A4 (SDA) / A5 (SCL) | Arduino実装例・ループバックテスト |
| Raspberry Pi | GPIO2 (SDA) / GPIO3 (SCL) | smbus2 または RPi.GPIO ライブラリで制御可能 |
そもそも GPIO の本数に余裕があるチップを選んでおく、という手もあります。ESP32 系はモデルによって GPIO 本数が19本から55本まで幅があるので、これから設計するなら ESP32 シリーズの選び方|S3・C3・C6・H2・P4 の違いと使い分け で本数を確かめてから決めると、拡張ICを足さずに済むことがあります。
最近は GPIO の本数だけでなく、チップ側に載る機能そのものが増えています。Espressif が発表した ESP32-S31 は、RISC-V デュアルコアに Wi-Fi 6 と Ethernet MAC まで統合してきました。拡張ICを足すか、はじめから余裕のあるチップに移るかで迷っているなら、ESP32-S31 発表|Wi-Fi 6・イーサネット搭載、ESP32-S3と何が違うのか で ESP32-S3 との違いを確認しておくと判断しやすくなります。
Raspberry Pi の場合は Python の smbus2 ライブラリを使って I2C 通信を行います。i2cdetect -y 1 コマンドで 0x20〜0x27 のアドレスが検出されれば接続成功です。基本的なレジスタ操作(IODIR, GPIO レジスタ)はデータシートに準拠しており、マイコンが変わっても原理は同じです。
まとめ
ESP32とMCP23017を使ったI/O拡張の実装方法を解説しました。
本記事のポイント
- MCP23017は16ピンをI2C通信で追加できる強力なI/Oエキスパンダー
- 最新Adafruit_MCP23X17ライブラリで簡単に制御可能
- 最大8個接続で128ピンまで拡張可能
- 内部プルアップや割り込み機能など、高度な機能も搭載
- LED制御、スイッチ入力、センサー集約など幅広い用途に対応
次のステップ
- 複数のMCP23017を接続して、さらに多くのピンを制御
- 割り込み機能を使って、効率的なイベント駆動プログラミング
- SPI版のMCP23S17も検討(高速通信が必要な場合)
MCP23017を使えば、ピン不足の悩みから解放され、より大規模で複雑なプロジェクトに挑戦できます。
それでは、良き電子工作ライフを!
関連記事:GPIO拡張の選択肢
まず I2C そのものを理解したい方へ:
- I2C・SPI・UART の違いと使い分け完全ガイド|配線本数・速度・距離で選ぶマイコン通信規格:本記事で扱う I2C アドレスやプルアップ抵抗がなぜ必要なのかを、SPI・UART との比較で解説しています。プルアップ抵抗値の計算式(上限・下限の求め方)や、スタートコンディション・ACK の仕組みも扱っています。
MCP23017(I2C方式)以外のGPIO拡張方法も参考にどうぞ:
| 方式 | 特徴 | 記事 |
|---|---|---|
| MCP23017(I2C) | 配線がシンプル、2本で複数IC再利用、最大8個接続 | 本記事 |
| 74HC595(SPI) | 3本の信号線、数珠つなぎで無限に拡張可能、高速 | 【回路図付き】Arduinoで74HC595でGPIOを拡張する方法 |
| ArduinoでMCP23017 | Arduino Uno R4実装例・ループバックテスト | 【Arduinoで電子工作】MCP23017で「16本の足」を生やす完全ガイド & 自己診断テスト |
