センサとArduinoとの接続にはI2Cがよく用いられます。ここではセンサとArduinoを接続する前にArduinoがしっかりとI2C通信できるか基本的な構成とコードで確認を行います。
#1. Arduino同士をつなぐ
Arduino同士で接続することで、コード上での送信と受信の大まかな手順を把握することができます。以下の図のように接続します。
今回はArduino Pro Mini 3.3Vを使用しました。MasterとSlaveの1対1構成です。どのArduinoでも基本的には同じですが、接続ピンと電圧レベル(5Vor3.3V)を確認して適切に接続します。電圧が異なる場合は変換させるなどの処置が必要となります。
#2. コード
I2CではMasterとSlaveの組み合わせが大原則になっています。通信の主導権は常にMasterが持ち、Masterからの要求に応じてSlaveが応える仕様になっています。したがって、Slave同士での通信やSlaveからMasterにリクエストを送ることはできません。
I2CのサンプルコードはArduino IDEのメニューの[ファイル] -> [スケッチの例] -> [Wire]
から参照することができます。コードはMaster用とSlave用が以下のようにペアとなってそれぞれ用意されています。
- master_reader / slave_sender : センサの読み取り etc...
- master_writer / slave_receiver : EEPROMの書き込み etc...
ここでは[ master_reader / slave_sender ]のペアに少し変更を加えてMasterからSlave(ID#8)へ1Byteのデータを要求し、Slaveは要求のたびに1ずつカウントアップして値を返すコードを作成してみます。
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
}
void loop() {
Wire.requestFrom(8, 1);// request 1 bytes from Slave ID #8
while (Wire.available()) {
byte b = Wire.read();
Serial.println(b);
}
delay(500);
}
スレーブのIDは8です。
#include <Wire.h>
byte b=0;
void setup() {
Wire.begin(8);// Slave ID #8
Wire.onRequest(requestEvent);
}
void loop() {
}
void requestEvent() {
Wire.write(b++);
}
#3. 結果
Masterをシリアル通信で見てみると、正常に動作していれば以下のようになります。
#4. 【応用】外部抵抗でプルアップする
既にお気付きかもしれませんが、接続図にはプルアップ抵抗が入っていません。公式のWireライブラリを用いるとArduinoの内部でプルアップが行われます。もし、プログラムに問題がないのにI2C通信が不安定であったり、通信ができない場合は内部プルアップ抵抗を無効にしてオシロスコープで波形を見ながら外部で適切な抵抗値でプルアップする必要があります。内部プルアップ抵抗を無効にするには2つの方法があります。
方法1.ライブラリを編集する
Arduino IDEフォルダから
(Windows) \hardware\arduino\avr\libraries\Wire\utility\twi.c
(Mac) Arduino.app/Contents/Java/hardware/arduino/avr/libraries/Wire/utility/twi.c
を開いて、以下の行をコメントアウトさせます。
// activate internal pullups for twi. digitalWrite(SDA, 1); digitalWrite(SCL, 1);
MasterとSlaveそれぞれにコメントアウトさせた状態で再度書き込みを行うと適用されます。
方法2.スケッチを変更する
ライブラリを編集してしまうとWireライブラリを使用するすべてのスケッチでSDAとSCLピンの内部プルアップが無効になります。任意のスケッチだけ内部プルアップを無効にするには、スケッチに以下のコードを追加します。
【重要】Wire.begin()の後に記述すること
pinMode(SDA, INPUT); pinMode(SCL, INPUT);
外部抵抗の接続図
抵抗値はオシロスコープで波形がなまっていないか、またはI2C通信のLowレベルがGNDから離れすぎていないかを見ながら適切な値を選択します。