べれすく!

素人プログラマによるモノづくりやブログ生活を話すブログ

【スポンサーリンク】

【Arduino】Arduino同士をI2C通信でつないでみた話

つなぎ方

いろいろなサイトで調べたけどイマイチわからなかった。
とりあえず、こんな感じで各ArduinoのSDA同士、SCL同士、グラウンド同士をつないでみる。  
f:id:Veresk:20190704011238j:plain  
Arduino IDEには最初からI2Cのライブラリが入っている。
それにはサンプルも付属している。
 

f:id:Veresk:20190704012509p:plain

master_writerとslave_receiverの組み合わせで試したところうまくいったようだ。

ライブラリの解説

ぶっちゃけArduino 日本語リファレンスWireの欄を一つずつ呼んだほうがいいと思う。
 

使用方法関係なく使う関数

Wire.begin(address)

まずはこれ。
基本的にはsetup関数内で動かす。
これがないとWireライブラリは動かない。 引数のaddressは複数機器をI2Cで使わない限りは、適当でいいと思う。
複数使う場合はmaster側とslave側で数値を合わせる必要がある。
 

Wire.write(value)

これは、データを送信をする関数...って考えていい。 正確には送信用に保管するって感じかな。
下で説明するWire.onRequest()やWire.endTransmission();で保管したデータを送信する。  

Wire.read()

これは送られてきたでデータを読み出すもの。
戻り値がデータなので、変数に代入して使う。 送られてきたタイミングで実行しないと受け取れないのでWire.available()をうまく組み合わせるといい。
 

Wire.available()

送られてきたデータが何バイトかを戻り値とする。 送られてきていなければ0。5文字のアルファベットなら5。 こんな感じでバイト数がそのまま帰ってくる。  

マスターからスレーブへのリクエス

f:id:Veresk:20190705015806p:plain

Wire.requestFrom(address, count) 

これは、slave側にリクエストを送る関数。 masterのArduinoのプログラムに記述する。
addressにはbeginのaddressと同じものを書く。
countにはリクエストするバイト数を入れる。
サンプルではcountを6にして、"H" "e" "l" "l" "o" "(改行)"を受け取っていた。
1バイトは数字なら0~255、文字なら一文字だ。
複数バイトをリクエストしても送られてくるのは1バイトずつなので注意したい。
 

Wire.onRequest(handler)

上のrequestFromと対になる関数。
masterからリクエストが来た時に実行する関数を決める。
slaveのArduinoのプログラムに記述する。
handleにはリクエストされたときに実行する関数名を入れる。
リクエストされた瞬間に割り込み実行されるのでslave側で動かしているプログラムがある場合は注意が必要だ。
 
 
 

マスターからスレーブへのリクエス

f:id:Veresk:20190705022238p:plain

Wire.beginTransmission(address);
Wire.write(value);
Wire.endTransmission();

この3つはセットだと考えていいと思う。
それ以外の使い方をしたことがない。
これは、masterからslaveに数値や文字を送るものだ。
使い方は簡単。adressにbeginと同じものを入力。
valueに送りたい数値や文字を入れます。
文字の場合は""(ダブルクォーテーション)でくくる。  

Wire.onReceive(handler)

これはmasterから何らかの値が送られてきた場合に作動する関数だ。
slaveで作用する。
handlerには送られてきた時に実行する関数名を入れる。
onRequest同様、割り込みによる動作なので気を付けたい。
 

ちょっとした応用例

Arduino(master)ーArduino(slave)ーセンサ
 
とつながっているとする。
ところがこのセンサ、値の取得に数秒かかるようだ。(超音波やRGBカラーセンサ)
その間masterには待機させる。 f:id:Veresk:20190707153620p:plain いろいろ書き方があるだろうけど私はこう書いた。

//master

#include <Wire.h>

void setup() {
  Wire.begin();        //I2C通信スタート!
  Serial.begin(9600);
}

void loop() {
  byte value = 0;
  Wire.requestFrom(8, 1, true);//アドレス8(適当)で1バイトのデータをリクエスト!
  while (Wire.available() != 1) {}    //1バイトのデータが帰ってくるまで空ループ
  value = Wire.read();                //空ループ抜けたら値読み込み
  Serial.println(value);
}

 

//slave

#include <Wire.h>

void setup() {
  Wire.begin(8);             
  Wire.onRequest(Request); 
}

void loop() {
  delay(100);
}

void Request() {
  byte value = Senser();
  Wire.write(value);
}

byte Senser(){
    //センサの起動と値の取得
  }

間違ってたらコメントでもください