ARDUINOでI2C接続 I/Oエキスパンダーを使う

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 までのデバイスアドレスを設定出来ます。

上位ビット 下位ビット
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件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です