Arduino ESP32 電子部品

【ESP32で電子工作-4】I/Oエキスパンダー MCP23017を使う

本記事でしようしているMCP23017 のライブラリ"Adafruit_MCP23017.h"は旧ライブラリとなっています。
新ライブラリ<Adafruit_MCP23X17.h>を使用した電子工作はこちらの記事に書いていますので
よろしければ、こちらの記事をご参考ください。

https://electwork.net/arduino10/

I/Oエキスパンダー MCP23017を使う

I/Oエキスパンダーとは

マイコンとかを使っている時にI/Oピンが足りなくなった経験はないでしょうか?
LEDを大量に使用したい場合やスイッチなどの入力点数がほしくなる場合がありませんか。

そのような場合に役に立つのがI/Oエキスパンダーです。

これを使うことで単純な入出力はI/Oエキスパンダーに、AD変換でやPWMなど複雑な処理はマイコンのピンにさせるなど、用途によって使い分けることによって効率よくマイコンを使用することができます。

今回使用するI/Oエキスパンダーは「MCP23017」と呼ばれる素子を使用します。

早速、仕様を確認していきましょう。

MCP23017の仕様確認

早速「MCP23017」のデータシートを確認していきましょう。
→MCP23017 datasheet

ピンアサインは以下のようになっています。

MCP23017 ピンアサイン

通信方法はI2Cを用いて、MVP23017と接続します。
駆動電圧は1.8V- 5.5Vなのでレベルシフト等は気にしなくてよさそうですね。
入出力はAportとBportでそれぞれ8つずつ、計16本の入出力信号を扱うことができます。

I2CのアドレスA0,A1、A2のそれぞれのピン入力の組み合わせて。設定することができます。
なので、2*2*2の他のI2C機器のアドレス競合がなければ、計8個の素子を接続することができます。

I2CのSDA.SCLの2本の信号線で8個の素子、それぞれに16個のIO。

16*8の計128個のI/Oが増設可能となります。

これだけあったら簡単な電子工作ではそうそう困ることもないでしょう。
レジスタの設定をすることで入出力の管理だけでなく内部プルアップが可能であったり割り込み出力などいろいろとできることが多いです。

MCP23017を使ってみる

実際にMCP23017をESP32で使用してみましょう。
プログラムはArduinoIDEで書いていきます。

まずMCP23017をArduinoIDEで簡単に使用するために「Adafruit_MCP23017.h」のライブラリをGitHubからダウンロードしてArduinoIDEに登録します。

では、さっそくコードを書いていきましょう。
今回、作成するプログラムはMCP23017を1個使用します。
入力3点、出力8点を使用して、スイッチの押すボタンによってLEDの光るパターンが変わるプログラムを書いていきます。

アドレスの設定

MCP23017とマイコンを接続するためにはI2Cのアドレスを知っておく必要があります。
データシートを確認するとアドレス構成は以下の画像のようになります。MCP23017のA0,A1,A2の入力信号によって決められることがわかります。

MCP23017 address

従来なら、7bitのスレーブアドレスを指定しなければいけません。しかし、「Adafruit_MCP23017.h」のライブラリを使用すると、A0,A1,A2の3bitのアドレスを指定することで通信することができます。

アドレスを以下の表にまとめました。

A0 A1 A2 アドレス アドレス(ライブラリ使用時)
0 0 0 0x20 0x00(指定なし)
1 0 0 0x21 0x01
0 1 0 0x22 0x02
0 0 1 0x23 0x03
1 1 0 0x24 0x04
1 0 1 0x25 0x05
0 1 1 0x26 0x06
1 1 1 0x27 0x07

回路の作成

今回作成した回路の回路図は以下のようになっています。

仕様通りの入力3ポートにはプルダウン抵抗を入れたスイッチを、出力は8ポートでLEDにつながるようになっています。

ブレッドボードに組むと以下のようになりました。

では、実際にプログラムを組んでいきましょう。

プログラムの作成

早速ですが、作成したプログラムの全文は以下のようになっています。

#include <Wire.h>
#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp;
  int sw1, sw2, sw3;
void setup() {
  delay(1000);
  Serial.begin(115200);
  Wire.begin();
  mcp.begin();  //アドレスが0の場合()内は空白、
  //OUTPUT
  mcp.pinMode(0, OUTPUT);
  mcp.pinMode(1, OUTPUT);
  mcp.pinMode(2, OUTPUT);
  mcp.pinMode(3, OUTPUT);
  mcp.pinMode(4, OUTPUT);
  mcp.pinMode(5, OUTPUT);
  mcp.pinMode(6, OUTPUT);
  mcp.pinMode(7, OUTPUT);
  //INPUT
  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(sw2); Serial.println(sw3);
  if (sw1 == 1 && sw2 == 0 && sw3 == 0) {
    Serial.println("mode1");
    mcp.digitalWrite(0, 1);delay(1);
    mcp.digitalWrite(1, 1);delay(1);
    mcp.digitalWrite(2, 1);delay(1);
    mcp.digitalWrite(3, 1);delay(1);
    mcp.digitalWrite(4, 0);delay(1);
    mcp.digitalWrite(5, 0);delay(1);
    mcp.digitalWrite(6, 0);delay(1);
    mcp.digitalWrite(7, 0);delay(1);
  } 
  else if (sw1 == 0 && sw2 == 1 && sw3 == 0) {
    Serial.println("mode2");
    mcp.digitalWrite(0, 0);delay(1);
    mcp.digitalWrite(1, 0);delay(1);
    mcp.digitalWrite(2, 0);delay(1);
    mcp.digitalWrite(3, 0);delay(1);
    mcp.digitalWrite(4, 1);delay(1);
    mcp.digitalWrite(5, 1);delay(1);
    mcp.digitalWrite(6, 1);delay(1);
    mcp.digitalWrite(7, 1);delay(1);
  } else if (sw1 == 0 && sw2 == 0 && sw3 == 1) {
    Serial.println("mode3");
    mcp.digitalWrite(0, 1);delay(1);
    mcp.digitalWrite(1, 1);delay(1);
    mcp.digitalWrite(2, 1);delay(1);
    mcp.digitalWrite(3, 1);delay(1);
    mcp.digitalWrite(4, 1);delay(1);
    mcp.digitalWrite(5, 1);delay(1);
    mcp.digitalWrite(6, 1);delay(1);
    mcp.digitalWrite(7, 1);delay(1);
  } else {
    Serial.println("mode0");
    mcp.digitalWrite(0, 0);delay(1);
    mcp.digitalWrite(1, 0);delay(1);
    mcp.digitalWrite(2, 0);delay(1);
    mcp.digitalWrite(3, 0);delay(1);
    mcp.digitalWrite(4, 0);delay(1);
    mcp.digitalWrite(5, 0);delay(1);
    mcp.digitalWrite(6, 0);delay(1);
    mcp.digitalWrite(7, 0);delay(1);
  }
  delay(10);
}

以下にプログラム内部で使用している関数の説明をしていきます。

mcp.begin();
mcpとのI2C通信を開始します。( )内にはライブラリ使用時の設定したアドレスを入力します。ただし、0x00の場合は空白3のままにしておきます。
例:アドレスが0x00の場合 mcp.begin();
アドレスが0x05の場合 mcp.begin(0x05);

mcp.pinMode(num, mode);
それぞれのピンの入出力モードを設定します。
numにはピン番号を設定します。GPA0~GPA7は0~7に、GPB0~7は8~15にそれぞれ対応しています。
modeにはピン番号に対する入出力モードを設定します。出力なら"OUTPUT"を、入力なら”INPUT”を入力します。

mcp.digitalRead(num)
指定ピン番号の入力状態を確認します。HIGHが入力されていたら1を、LOWが入力されていたら0を返します。

mcp.digitalRead(num,mode);
指定ピン番号の出力を設定します。mode = 0ならLOWを、mode = 1ならHIGHを出力します。

実際の動作

実際に動作させると以下の動画のようになります。

スイッチによる入力が変化すると、LEDへの出力パターンが変化していることがわかりますね。
これでI/Oエキスパンダー:MCP23017 の入出力を完璧に扱うことができましたね。

今回のまとめ

今回I/Oエキスパンダー:MCP23017とArduinoIDEで使うための「Adafruit_MCP23017.h」の使い方について学ぶことができました。
今回はLEDへの出力をしていますが、モータなどの動力などいろんなことに応用ができると思います。
I/Oが大量に増やすことができたら、開発の幅もすごく広がると思います。

私がI/Oエキスパンダーを知らないときはマイコンを増やしてIOの増設を行っていました(笑)

この記事を読んでいただいた方は私のような無駄なことをせずにコスパのいい電子工作を行っていただけたらと思います。

今回は以上となります。
それでは、良き電子工作ライフを!!
See You …

ブログランキング参加中

クリックしていただけると
ブログ更新の励みになります


電子工作ランキング
にほんブログ村 その他趣味ブログ 電子工作へ
にほんブログ村

スポンサーリンク

-Arduino, ESP32, 電子部品
-, , , ,