周辺デバイスとのデータ通信で使われるI2C通信ですが、使うたびにその方法を調べるのも結構面倒です。ArduinoのI2C通信方法を備忘録かねて要点(必要最低限な内容に絞っての使い方)だけまとめておきます。(Arduinoを久しぶり(半年くらい?ぶり)に使ってみたのですが、細かいことをいろいろ忘れがちです・・・・。)
今回はArduino(マスター)とセンサー等(スレーブ)側を前提として、I2C通信でセンサー等との情報の読み書き方法です。
ArduinoのI2C結線
Arduino SDApin ⇔ デバイス SDApin
Arduino SCLpin ⇔ デバイス SCLpin
I2C通信の場合、基本的にはArduinoとデバイスの接続はSDAとSCLの2本のラインをつなぐだけです。後述しますが、wire.hライブラリ使って通信する場合は、Arduinoの内部プルアップを使っているため、外部で抵抗準備する必要も基本的にはありません。Arduinoの場合、SDAはA4ピンに、SCLはA5ピンにも割り当てられてます。
よくあるのがデバイスが3.3Vの場合、Arduino5.0Vをそのまま直結できないため、レベルシフト回路などを挟みます。
デバイスアドレスを指定してデータのやり取りを行うため、複数デバイスを接続する場合でもラインは共通して使うことができます。
通信の方法(Arduinoスケッチ)
Arduinoのスケッチ(ソース)はwire.hライブラリを使用する前提で、最低限必要な内容に絞ってまとめておきます。
初期設定
Wire.begin();
Wire.setClock(400000);
ArduinoでI2C通信を開始して、通信速度を指定してます。通信速度はデフォルト100kHzなので、変更しない場合は記述しなくても良いと思います。
ここら辺は1度だけ実行されれば良いのでセットアップ内に記述します。
またこの時点でArduino側でSDAピンとSCLピンの内部プルアップが有効になります。ですので、もし通信が不安定とかであれば内部プルアップを解除して外部で適切な抵抗でプルアップすべきかと思います。
内部プルアップを解除する場合は、
digitalWrite(SDA, 0);
digitalWrite(SCL, 0);
wire.begin();よりの後に記述します。(試してないですがたぶんこれでO.Kと思います)でオシロとかあるなら波形確認しながら適切な外部抵抗を配置します。
ただ私の場合、プルアップ抵抗付きのセンサーモジュール品などを使うとき、Aduinoの内部プルアップとかを特に気にせずに使っててもあまり問題になったことはないです・・・・。
データ送信(書込み)
デバイスへ情報を書き込むときの記述です。
Wire.beginTransmission(0x68);
Wire.write(0x6B);
Wire.write(0x00);
Wire.endTransmission();
(MPU6050(6軸センサー)を例に記述してます)
- 最初に通信するI2Cデバイス(スレーブ)のアドレスを指定。ここでは「0x68」としてます。
- 次にI2Cデバイスの書き込みレジスタを指定。ここでは「0x6B」レジスタを指定。
- で次に書き込む値を指定する
- 最後に送信を完了します。
書き込みは基本的にこの手順で行います。
データ受信(読込み)
デバイスの情報を読み込むときの記述です。
Wire.beginTransmission(0x68);
Wire.write(0x3B);
Wire.endTransmission();
Wire.requestFrom(0x68, 14);
while (Wire.available() < 14);
accRaw.B16.X = Wire.read() << 8 | Wire.read();
accRaw.B16.Y = Wire.read() << 8 | Wire.read();
accRaw.B16.Z = Wire.read() << 8 | Wire.read();
temperature = Wire.read() << 8 | Wire.read();
gyroRaw.B16.X = Wire.read() << 8 | Wire.read();
gyroRaw.B16.Y = Wire.read() << 8 | Wire.read();
gyroRaw.B16.Z = Wire.read() << 8 | Wire.read();
(MPU6050(6軸センサー)を例に記述してます)
- 最初にI2Cデバイス(スレーブ)のアドレスを指定します。ここでは「0x68」としてます。
- 次に読み込むレジスタ値を指定
- で送信処理をします。
- I2Cデバイス(スレーブ)のアドレスと情報の読み込みサイズ(byte数)を指定します。
- 情報(要求したbyte)が到着するまで待機
- 最後に「Wire.read()」で1byteずつ情報を取得します
I2Cデバイスから情報を読み込むときは基本的にはこの手順です。
その他
デバイスアドレスが不明の場合。I2C-Scannerというソースを利用します。総当たりで順番にアドレス確認をして反応のあるアドレスを確認できる物です。(物によってはデバイスアドレス以外にも反応してしまいます)
あまりデバイスアドレスが不明という状況は少ないと思いますが、、私の場合このスケッチを通信確認の意味を込めて、結線後に最初に走らせて確認してます。
必要最低限の使い方のみですが、これだけわかってれば私の場合はだいたいO.Kです。
コメント