I/Oエキスパンダー
I/Oエキスパンダー(MCP23017-E/SP)の確認を行い I2C接続についての調査はとりあえず終了したいと思います。今回確認するI/Oエキスパンダーは、I2C接続により入出力端子を16点拡張できるICです。外部入力からデバイスアドレスを変更し、同じICを8個まで接続出来るので、最大128点の入出力端子を拡張することができます。
MCP23017-E/SP仕様
今回扱うI/Oエキスパンダーの仕様について簡単に確認してみます。下図の左側にMCP23017-E/SPのピンアサイン、右側に今回プログラム内で書き込み、読み込みを行うレジスタのアドレスと内容を示しています。このI/Oエキスパンダーは、Aポート(GPA0~7)とBポート(GPA0~7)を入出力端子として使用します。入力/出力は、IODIRA、IODIRB レジスタ設定によって変更します。入力設定時は、GPPUA、GPPUB レジスタにて内部プルアップ抵抗を利用できる様になり、外部プルアップ抵抗は不要となります。これらの設定後、出力設定時は、GPIOA、GPIOB に書き込み、入力設定時は、GPIOA、GPIOB の値を読み込みます。
デバイスアドレス設定
ICのA0,A1,A2は、I2Cバス上のデバイスアドレスを設定する外部端子です。各端子2通り(High or Low)の設定ができますので、全8通り(= 2 X 2 X 2 )の異なるアドレスを設定できます。デバイスアドレスは下記の様になっていて、灰色の固定部とA0,A1,A2の外部端子で設定する部分で構成されます。従って、0x20~0x27 までのデバイスアドレスを設定出来ます。
上位ビット | 下位ビット | |||||
0 | 1 | 0 | 0 | A2 | A1 | A0 |
接続図
接続図です。2つのI/Oエキスパンダーと既に使用したLCDモジュールを I2Cバス接続しています。また、それぞれのI/OエキスパンダーのAポートにトグルスィッチ、BポートにLEDを2個づつ接続しています。RESET(18番PIN)は、通常Highにし、リセット時Lowとのことですので、とりあえず5V接続しています。
下図より、I/Oエキスパンダーのデバイスアドレスは、0x20、0x21です。LCDは0x3E(固定)です。
実配線は下の写真の通りです。
動作状態
スィッチ切り換えで点灯LEDの切り換えとLCDにスィッチ状態を表示します。
プログラム
プログラムは以下の通りです。
#include <Wire.h> // ★ IO-EXPANDER(MCP23017)定数・変数 #define DVC_MCP23017_00 0x20 // IO-EXPANDER_00 アドレス(外部端子設定) #define DVC_MCP23017_01 0x21 // IO-EXPANDER_01 アドレス(外部端子設定) uint8_t U1_PA, U2_PA =0; // Define variables to hold I/O port readings. // LCD(AQM0802A) 定数・変数 #define DVC_AQM0802A 0x3e // LCD(AQM0802A)アドレス(固定) byte contrast = 20; // コントラスト(0~63) // ★ LCD(AQM0802A)初期化 void LCD_INIT(){ lcd_cmd(0b00111000); // function set lcd_cmd(0b00111001); // function set lcd_cmd(0b00000100); // EntryModeSet lcd_cmd(0b00010100); // interval osc lcd_cmd(0b01110000 | (contrast & 0xF)); // contrast Low lcd_cmd(0b01011100 | ((contrast >> 4) & 0x3));// contast High/icon/power lcd_cmd(0b01101100); // follower control delay(200); lcd_cmd(0b00111000); // function set lcd_cmd(0b00001100); // Display On lcd_cmd(0b00000001); // Clear Display delay(2); } // ★ LCD(AQM0802A)コマンド書き込み(I2C) void lcd_cmd(byte x) { Wire.beginTransmission(DVC_AQM0802A); Wire.write(0b00000000); // CO = 0,RS = 0 Wire.write(x); Wire.endTransmission(); } // ★ 連続文字 void lcd_contdata(byte x) { Wire.write(0b11000000); // CO = 1, RS = 1 Wire.write(x); } // ★ 最終文字 void lcd_lastdata(byte x) { Wire.write(0b01000000); // CO = 0, RS = 1 Wire.write(x); } // ★ 文字の表示 void lcd_printStr(const char *s) { Wire.beginTransmission(DVC_AQM0802A); while (*s) { if (*(s + 1)) { lcd_contdata(*s); } else { lcd_lastdata(*s); } s++; } Wire.endTransmission(); } // ★ 表示位置の指定 void lcd_setCursor(byte x, byte y) { lcd_cmd(0x80 | (y * 0x40 + x)); } // ★ 数字表示 void lcd_printInt(int num){ char int2str[10]; sprintf(int2str,"%d",num); lcd_printStr(int2str); } // 指定レジスタにデータ書き込み void wrt_reg(byte dvc_adrs , uint8_t reg , uint8_t value) { Wire.beginTransmission(dvc_adrs); // デバイス指定、通信開始 Wire.write((uint8_t)reg); // レジスタ指定 Wire.write((uint8_t)(value)); // データ書込 Wire.endTransmission(); // 送信完了 } // 指定レジスタからデータ読み出し uint8_t read_reg(byte dvc_adrs , uint8_t reg) { Wire.beginTransmission(dvc_adrs); // 送信処理開始 Wire.write(reg); // レジスタ指定 Wire.endTransmission(false); // 送信完了(コネクション維持) Wire.requestFrom(dvc_adrs , 1); // 1byteデータに要求 if (! Wire.available()) return -1; // データ有無判定 return (Wire.read()); // 1byteデータ } // 起動時処理 void setup() { Wire.begin(); // マスタとしてI2Cバスに接続する // DVC_MCP23017_00(DVCアドレス:0x20) wrt_reg( DVC_MCP23017_00 , 0x00 , 0xFF ); // DVC00 I/O-PortA 入力設定 wrt_reg( DVC_MCP23017_00 , 0x0C , 0xFF ); // DVC00 I/O-PortA 入力プルアップ設定 wrt_reg( DVC_MCP23017_00 , 0x01 , 0x00 ); // DVC00 I/O-PortB 出力設定 wrt_reg( DVC_MCP23017_00 , 0x13 , 0x00 ); // DVC00 I/O-PortB 全OFF // DVC_MCP23017_01(DVCアドレス:0x21) wrt_reg( DVC_MCP23017_01 , 0x00 , 0xFF ); // I/O-PortA 入力設定 wrt_reg( DVC_MCP23017_01 , 0x0C , 0xFF ); // I/O-PortA 入力プルアップ設定 wrt_reg( DVC_MCP23017_01 , 0x01 , 0x00 ); // I/O-PortB 出力設定 wrt_reg( DVC_MCP23017_01 , 0x13 , 0x00 ); // I/O-PortB 全OFF LCD_INIT(); // ★ LCD初期化 } // 繰り返し処理 void loop() { U1_PA = read_reg( DVC_MCP23017_00 , 0x12 ); // デバイス・レジスタ指定しデータ読取 U2_PA = read_reg( DVC_MCP23017_01 , 0x12 ); // デバイス・レジスタ指定しデータ読取 lcd_cmd(0b00000001); // 表示クリア lcd_setCursor(0, 0); // 表示座標設定 if ((U1_PA & 1 )!=0){ lcd_printStr("SW1 ON"); // 表示内容(文字) wrt_reg( DVC_MCP23017_00 , 0x13 , 0x02 ); // DVC00 I/O-PortB 出力設定 }else{ lcd_printStr("SW1 OFF"); // 表示内容(文字) wrt_reg( DVC_MCP23017_00 , 0x13 , 0x01 ); // DVC00 I/O-PortB 出力設定 } lcd_setCursor(0, 1); // 表示座標設定 if ((U2_PA & 1 )!=0){ lcd_printStr("SW2 ON"); // 表示内容(文字) wrt_reg( DVC_MCP23017_01 , 0x13 , 0x02 ); // DVC01 I/O-PortB 出力設定 }else{ lcd_printStr("SW2 OFF"); // 表示内容(文字) wrt_reg( DVC_MCP23017_01 , 0x13 , 0x01 ); // DVC01 I/O-PortB 出力設定 } delay(100); }
以上で I2C 接続に関する確認は一旦完了としようと思います。
「ARDUINOでI2C接続 I/Oエキスパンダーを使う」への1件のフィードバック