I2C通信

はじめに

Arduino UnoのI2C通信の使い方を紹介します。実際に試したのは、Arduino Unoですが、ESP-WROOM-32を含む、他のArduinoでも利用できると思います。

I2C通信は、データとクロックの2本の信号線を使って通信する同期型のプロトコルです。Arduinoでは、ハードウェアの機能を利用したWireライブラリによって実装されています。

I2Cは、一つのマスターデバイスと一つ以上のスレーブデバイスが通信を行うことができます。スレーブデバイスを識別するために、全てのスレーブデバイスは、アドレスを持ちます。

Arduinoはマスターになることもスレーブになることもできます。ここでは、Arduinoがマスターデバイスとなり、スレーブデバイスを制御する方法の枠組みを説明します。

具体的な使い方は、利用するI2Cデバイスの仕様に依存するので、データシートを確認したうえで、プログラムすることになります。

デバイスの接続

Arduino Unoでは、ハードウェア(ATmega328P)の機能を用いてI2C通信を行うため、接続に利用する2本のピンは、以下のように決まっています。

ピン番号 種別 意味
A4 SDA データ
A5 SCL クロック

I2C通信に利用するピンは、プルアップ抵抗でプルアップする必要がありますが、Arduino UnoのWireライブラリは、内部のプルアップ抵抗を有効にします。このため、通常は外部にプルアップ抵抗を接続する必要はありません。

複数のI2Cデバイスを接続する場合も、上記のピンに全てのデバイスを接続します。接続する各デバイスは、アドレスで識別します。このため、同一のアドレスを持つI2Cデバイスは、一つしか接続することができません。I2Cデバイスの中には、アドレスを切り替えられるものもあり、同一デバイスを複数同時に接続できるようにしているものもあります。

I2Cアドレス

I2C通信では、スレーブデバイスのアドレスを指定して、データの送受信を行います。アドレスには、7ビットのアドレスと10ビットのアドレスがあります。通常は7ビットのアドレスが使われるようです。ここでは、7ビットアドレスの使い方を紹介します。

7ビットのアドレスに、1ビットの読み書き(R/W)ビットを付加した8ビットを、I2Cアドレスとして(誤って)表現する場合もあるようです。

ArduinoのWireライブラリでは、7ビットアドレスを使用します。R/Wビットは、Wireライブラリが適切に処理してくれます。

データシート上、8ビットのアドレスが指定されているデバイスを利用する際は、1ビット分右にシフトして、7ビットのアドレスに変換する必要があります。

例えば、8ビットアドレスが、0xaaと0xabで指定されている場合は、7ビットアドレスは0x55となります。

0xaa >> 1 ⇒ 0x55、0xab >> 1 ⇒ 0x55

形式アドレス表現I2CアドレスR/W
8ビット(W)0xaa10101010
8ビット(R)0xab10101011
7ビット0x551010101-

使用方法

初期化

I2C通信で、マスターとして参加する場合は、Wire.begin()を使って、初期化を行います。Wireは、Wireライブラリで定義されている変数(オブジェクト)です。利用者が定義する必要はありません(Wire.hをインクルードすれば利用できます)。マスターとして参加する場合は、パラメータは不要です。

1
2
3
4
5
#include <Wire.h>

void setup() {
  Wire.begin();
}

送信

I2C通信で、デバイスにデータを送信する場合は、以下のメソッドを利用します。

個々の関数の使い方は、リファレンスを参照してください。

例えば、I2Cアドレスが 0x55 のデバイスに、0x1と0x2を送信するには、以下のようなプログラムとなります。Wire.write()は、1バイト、もしくは、複数バイトの送信を行うことができます。下記の例では、1バイト送信する方法を示しています。

1
2
3
4
5
6
7
8
  uint8_t addr = 0x55;
  uint8_t data1 = 0x1;
  uint8_t data2 = 0x2;

  Wire.beginTransmission(addr);
  Wire.write(data1);
  Wire.write(data2);
  Wire.endTransmission();

Wire.endTransmission()は、引数にtrueを指定する、もしくは、省略したときは、I2Cバスを開放します。falseを指定したときは、バスを開放しません。

具体的な使い方は、利用するI2Cデバイスの仕様に依存します。送信するデータとして、デバイスの持つレジスタのアドレスと、書き込む値を指定することが多いと思います。

受信

I2C通信で、デバイスにデータから受信する場合は、以下のメソッドを利用します。

  • Wire.requestFrom()
    • 指定したアドレスに対応するI2Cデバイスから、指定したバイト数を読み出すことを宣言します。
  • Wire.available()
    • 現在読み出し可能なデータ長を返却します。
  • Wire.read()
    • データを受信します。

個々の関数の使い方は、リファレンスを参照してください。

例えば、I2Cアドレスが 0x55 のデバイスから、2バイトを受信するには、以下のようなプログラムとなります。Wire.available()の使い方は、プログラムやデバイスによって変更してください。

1
2
3
4
5
6
7
8
9
  uint8_t addr = 0x55;
  uint8_t data1;
  uint8_t data2;

  Wire.requestFrom(addr, 2);
  if (Wire.available() >= 2) {
    data1 = Wire.read();
    data2 = Wire.read();
  }

Wire.requestFrom()は、第3引数にtrueを指定する、もしくは、省略したときは、I2Cバスを開放します。falseを指定したときは、バスを開放しません。

具体的な使い方は、利用するI2Cデバイスの仕様に依存します。Wire.requestFrom()を送信する前に、デバイスに対して、データ送信要求を送信することが多いと思います。

バージョン

Hardware:Arduino UNO R3
Software:Arduino 1.8.12

最終更新日

January 27, 2024

inserted by FC2 system