カテゴリー別アーカイブ: Arduino用シールド

Arduinoの入出力を拡張増設するIOエキスパンダーシールドの使い方

「IOエキスパンダーシールド(Arduino I/O増設 デジタル28点 アナログ16点)」を使うと、比較的簡単にArduinoにデジタル入出力、アナログ入力を拡張増設することができます。

お求めは、下記のサイトでどうぞ。

http://www.elefine.jp/SHOP/IOEXPANDERSHLD.html

Arduinoとの通信は、I2Cを利用しますので、A4(SDA)、A5(SCL)、およびアナログ入力としてA0を使い、合計3点のI/Oを使うだけで済みます。

I2Cで通信を行うデジタル入出力用デバイスMCP23017が2個搭載されています。その各MCP23017のI2Cアドレスは、基板上のジャンパーピンで設定します。

アドレスの上位4ビットは、0x20(16進数) で固定されていますので、下位3ビットをジャンパーピンで設定します。
AD1、AD2、AD3はU2用、AD4、AD5、AD6はU4用です。
AD3、AD2、AD1の順でそれぞれ1、2、4の重みです。同様にAD6、AD5、AD4の順でそれぞれ1、2、4の重みです。
よって、AD1、AD2、AD3のジャンパーをすべて0側(真ん中と0をまたぐようにジャンパーピンを挿す)に挿すとU2のアドレスは、0x20になります。また、AD4、AD5を0側、AD6を1側に挿すとU4のアドレスは、0x21になります。

デジタル入出力ピンとMCP23017のピンの対応

MCP23017の入出力ピンとIOエキスパンダーシールドのピンの対応は、以下のとおりです。

0 – U2 PORT B ビット0
1 – U2 PORT B ビット1
2 – U2 PORT B ビット2
3 – U2 PORT B ビット3
4 – U2 PORT B ビット4
5 – U2 PORT B ビット5
6 – U2 PORT B ビット6
7 – U2 PORT B ビット7

8 – U2 PORT A ビット0
9 – U2 PORT A ビット1
10 – U2 PORT A ビット2
11 – U2 PORT A ビット3
12- U2 PORT A ビット 4
13 – U2 PORT A ビット5
14 – U2 PORT A ビット6
15 – U2 PORT A ビット7

16 – U4 PORT B ビット0
17 – U4 PORT B ビット1
18 – U4 PORT B ビット2
19 – U4 PORT B ビット3
20 – U4 PORT B ビット4
21 – U4 PORT B ビット5
22 – U4 PORT B ビット6
23 – U4 PORT B ビット7

24- U4 PORT A ビット 4
25 – U4 PORT A ビット5
26 – U4 PORT A ビット6
27 – U4 PORT A ビット7

U4 PORT Aの下位4ビットは、アナログマルチプレクサのアナログ入力切替に使用しているため、デジタル入出力としては使用できません。

デジタル入力

サンプルスケッチhttps://github.com/numato/samplecode/blob/master/Arduino/shields/IOExpander/DigitalIn.ino

このサンプルでは、ジャンパーピンをAD6のみ1にして、ほかはすべて0に設定して使用します。よって、U2のI2Cアドレスは0x20、U4は0x21です(7ビット表記アドレス)。

 

入出力の方向設定

setup()内で各MCP23017の入出力の方向を設定しています。
MCP23017には、8ビットのポートが二つあり、PORT A、PORT Bの名称がつけられています。

下記の部分でU2(アドレス0x20)の設定を行っています。
初めの0x00は、MCP23017の内部アドレスで0x00は、PORT Aの入出力方向設定のためのレジスターです。
次の行の0xFFは、入出力の方向を設定しています。8ビットの各ビットが入出力ピンに対応し、0で出力、1で入力です。Outなので0、Inなので1と覚えると覚えやすいです(Z80で8255を使っていた頃の覚え方)。
よって、0xFFは、すべて入力です。

Wire.beginTransmission(0x20);
Wire.write(0x00);
Wire.write(0xFF);
Wire.endTransmission();

同様に次の行で内部アドレス指定を0x01にして、U2のPORT Bの設定を行っています。

Wire.beginTransmission(0x20);
Wire.write(0x01);
Wire.write(0xFF);
Wire.endTransmission();

さらに次の行でI2Cアドレスを0x21にして、U4のPORT A、PORT B の設定を行っています。

U4のPORT Aの設定

Wire.beginTransmission(0x21);
Wire.write(0x00);
Wire.write(0xFF);
Wire.endTransmission();

厳密には、U4のPORT Aの下位4ビットは、アナログ入力のマルチプレクサーの切り替えに使用しているため、0xFFではなく、0xF0のほうがいいでしょう。

U4のPORT Bの設定

Wire.beginTransmission(0x21);
Wire.write(0x01);
Wire.write(0xFF);
Wire.endTransmission();

デジタル入力値の取得

デジタル入力の読み出しは、loop() 内で行っています。
下記は、U2のPORT Aを読み出す例です。8ビット分まとめて読み出されます。

Wire.beginTransmission(0x20); //I2CのアドレスでU2を指定
Wire.write(0x12);     // MCP23017の内部アドレスの指定
Wire.endTransmission();
Wire.requestFrom(0x20, 1);     // 読み出すアドレスを指定する
U2PortA=Wire.read();     // 読み出す

上記の0x20を0x21にするとU4、0x12を0x13にするとPORT Bのデータを読み出すことができます。
読み出した値は、8ビットをまとめた数値ですので、ビットごと、例えばビット0のH,L を確認したい場合は、下記のように &でマスク(対象以外を0にする)して、0以外かどうかを確認します。1がビットを表し、2進数の重みです。
つまり、ビット0からビット7まで、それぞれ1, 2, 4, 8 ,16, 32, 64, 128 です。

if ((U2PortA & 1) != 0) {
    // true (H)の処理
}
else {
// false (L)の処理
}

入力のプルアップ

サンプルスケッチには、記述されておりませんが、MCP23017には、入力を内部の抵抗でプルアップする機能があります。これを使うと、スイッチ入力時、外部でプルアップ抵抗を接続する必要がなく、配線の手間が省けます。プルアップ設定のレジスターのアドレスは、PORT Aが0x0C、PORT Bが0x0Dです。8ビットのビットを1にするとそれに対応したピンがMCP23017の内部の抵抗100kΩでVDD(5V)にプルアップされます。

U2のPORT Aの全端子をプルアップする例

Wire.beginTransmission(0x20);
Wire.write(0x0C);
Wire.write(0xFF);
Wire.endTransmission();

これをsetup()内に入れるとよいでしょう。

デジタル出力

サンプルスケッチhttps://github.com/numato/samplecode/blob/master/Arduino/shields/IOExpander/DigitalOut.ino

このサンプルでは、ジャンパーピンをAD6のみ1にして、ほかはすべて0に設定して使用します。よって、U2のI2Cアドレスは0x20、U4は0x21です(7ビット表記アドレス)。

 

入出力方向設定

デジタル入力と同様、setup()内で各ポートの入出力方向を設定しています。

Wire.beginTransmission(0x20);   // I2Cアドレス U2のアドレス
Wire.write(0x00);      //内部アドレス 入出力方向方向設定レジスター
Wire.write(0x00);     // 入出力方向方向設定
Wire.endTransmission();

1番目の0x00でPORT Aの入出力設定レジスターのアドレスを設定しています。PORT Bの場合は、0x01です。
2番目の0x00で入出力方向を設定しています。出力の場合は、0です。

デジタル出力を行う

loop() 内でデジタル出力を行いますが、サンプルスケッチでは、
DigitalIO(255);
と、関数を介して行っています。
サンプルスケッチでは、全ポート同じ状態を出力しています。
そのDigitalIOの定義を見ると、実際に出力する方法がわかります。
下記は、U2のPORT Aの例です。

Wire.beginTransmission(0x20);
Wire.write(0x12);
Wire.write(i);
Wire.endTransmission();

0x12 でPORT A のデジタル出力レジスターを指定しています。PORT Bの場合は、0x13 です。
Wire.write(i);  が実際に出力するところです。8ビット分まとめて、出力します。8ビットのうち、1ビットのみ変化させたい場合は、前回の状態を保持しておき、その値との | (OR、論理和)、^ (ExOR、排他的論理和)を行います。

OFFにする場合、対象以外を1にして(上記の場合だと、0xf7)、ANDでマスクする方法もあります(この方が正当な方法)が、上記の方が計算が楽です。