2018年12月13日木曜日

ESP32/arduino:I2CでMCP23017を接続

目的:
I2C で MCP23017 を接続し、GPIO を追加。I2Cの使用方法を確認する。

構成:
   動作確認時の攻勢を上図に示す。
・MCP23017 を I2C で接続。
・A2~A0 は '1' に設定。(デバイスアドレス 0x21)
・GPA7 に スイッチ、GPA0,GPB7 に LED を接続。

I2C 制御方法:
 I2C を使用する場合、wire ライブラリを使用する。
主な関数は、
  Wire.begin() ; で I2C マスタとして初期化。
  Wire.beginTransmission(address); で デバイスに送信開始。
  Wire.write(value) ; で データを送信。
  Wire.endTransmission() ; で送信終了。
  Wire.requestFrom(address, count) ; で デバイスにデータを要求。
  Wire.available() ; で受信可能なバイト数を取得。
  Wire.read() ; でデータを受信。

I2C のライト/リード手順は、
ライト
  1. アクセスするレジスタアドレスを送信。
  2. アクセスするデータを送信。
リード
  1. アクセスするレジスタアドレスを送信。
  2. リード要求を送信。
  3. データを受信。
の順に行う。 詳細は、例を参照。

例:スイッチをON したら 2秒毎に LED が交互に点灯し、スイッチ OFF で両方消灯。

/*
 * i2c_test
 */

 
#include <Wire.h>

byte MCP23017  = 0x21 ;       // slave address
byte IODIRA    = 0x00 ;       // IODIRA Register Address
byte IODIRB    = 0x01 ;       // IODIRB Register Address
byte GPPUA     = 0x0C ;       // GPPUA Register Address
byte GPPUB     = 0x0D ;       // GPPUA Register Address
byte GPIOA     = 0x12 ;       // GPIOA Register Address
byte GPIOB     = 0x13 ;       // GPIOA Register Address



void I2C_BWR(byte TGT, byte REGADR, byte DATA) {
  Wire.beginTransmission(TGT);         // transmit to device #TGT 
  Wire.write(REGADR);                  // send REG address (REGADR)
  Wire.write(DATA);                    // send write data (DATA)
  Wire.endTransmission();              // end transmit
}

byte I2C_BRD(byte TGT,byte REGADR) {
  byte data = 0 ;
  Wire.beginTransmission(TGT);         //  transmit to device #TGT
  Wire.write(REGADR);                  //  send REG address (REGADR)
  Wire.endTransmission();              //  end transmit
  Wire.requestFrom(TGT, 1);            // request 1 byte from slave device #TGT
  data = Wire.read();                  // receive 1 byte 
  
  return data ;
}

void setup()
{
  byte DATA   = 0 ;          // for data
  byte error = 0xff ;

  Wire.begin();

  Serial.begin(115200);        //
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C test");


  // set direction IOA,IOB
  I2C_BWR(MCP23017,IODIRA,0xFE) ;   // set IOA0 : output
  I2C_BWR(MCP23017,IODIRB,0x7F) ;   // set IOB7 : output
  I2C_BWR(MCP23017,GPPUA,0x80) ;    // set IOA7 : PullUp
}


void loop()
{
  byte DATA ;

  DATA = I2C_BRD(MCP23017,GPIOA) ;
  if ( (DATA & 0x80) == 0x00 ) {
    I2C_BWR(MCP23017,GPIOA,0x01) ;   // set IOA0 = H
    I2C_BWR(MCP23017,GPIOB,0x00) ;   // set IOB7 = L

    DATA = I2C_BRD(MCP23017,GPIOA) ;
    Serial.print("REG GPIOA : 0x");
    Serial.println(DATA, HEX);
    DATA = I2C_BRD(MCP23017,GPIOB) ;
    Serial.print("REG GPIOB : 0x");
    Serial.println(DATA, HEX);

    delay(2000);           // wait 2 seconds for next

    I2C_BWR(MCP23017,GPIOA,0x00) ;   // set IOA0 = L
    I2C_BWR(MCP23017,GPIOB,0x80) ;   // set IOB7 = H

    DATA = I2C_BRD(MCP23017,GPIOA) ;
    Serial.print("REG GPIOA : 0x");
    Serial.println(DATA, HEX);
    DATA = I2C_BRD(MCP23017,GPIOB) ;
    Serial.print("REG GPIOB : 0x");
    Serial.println(DATA, HEX);

    delay(2000);           // wait 2 seconds for next
  } else {
    I2C_BWR(MCP23017,GPIOA,0x00) ;   // set IOA0 = L
    I2C_BWR(MCP23017,GPIOB,0x00) ;   // set IOB7 = L
    delay(4000);           // wait 4 seconds for next
  }    
}

以下、覚書など。
  ( 行# 8 )
デバイスのアドレスを定義。
  ( 行# 9~14 )
各レジスタのアドレスを定義。
 ( 行# 18,23 )
1バイトライト用の関数。
 送信開始 - レジスタアドレス送信 - データ送信 - 送信終了
の順に処理。
 ( 行# 25,34 )
1バイトリード用の関数。
 送信開始 - レジスタアドレス送信 - 送信終了 - データ 1バイト要求 - データ受信
の順に処理。

 setup 処理:
 ( 行# 41 )
I2C マスタとして初期化。
 ( 行# 49 )
IOA の 入出力を設定。IOA0 を出力に設定。 (他は入力)
 ( 行# 50 )
IOB の 入出力を設定。IOB7 を出力に設定。 (他は入力)
 ( 行# 51 )
IOA の プルアップを設定。IOA7 をプルアップ有効に設定。 (他は無効)

Loop処理:
 ( 行# 59 )
IOA の 状態をリード。
 ( 行# 60~84 )
スイッチが ON の場合の処理。
"IOA0 を ON, IOB7 を OFF" した後、2秒待って "IOA0 を OFF, IOB7 を ON" して 2秒待つ。 (デバッグ用に シリアルに GPIO の値を表示 )
 ( 行# 85~88 )
スイッチが OFF の場合の処理。
 "IOA0 を OFF, IOB7 を OFF" した後、4秒待つ。






0 件のコメント:

コメントを投稿