2014年6月8日日曜日

Arduino同士でI2C通信(1)

I2CでArduino同士を通信させてみたいと思います。

I2C通信のしくみについてはここがとてもわかりやすかったです。

用意するもの

・Arduino UNO 2個
・抵抗(4.7kΩ) 2個
測距モジュール GP2Y0A21YK
・タクトスイッチ

今回はI2C通信を使って、スレーブのArduinoに繋いだ測距センサーで計測した値をマスター側で確認することと、同じくスレーブ側のスイッチのON/OFFをマスター側で確認するということをします。

余談ですがこの測距モジュール、GNDがオレンジでVccが黒というトラップがあるので注意。


センサーから値を得る

Analog inの4がSDA、5がSCLでそれぞれを5Vからプルアップ抵抗をはさんだところに繋ぎます。手持ちの4.7kΩを繋いだのですが、どうもここによると今回使う「Wire.h」のほうで内部プルアップ抵抗をONにする設定をしてくれているそうなので、いらないと言えばいらないです。

ちなみに上がスレーブで下がマスターです。





先述したとおり、「Wire.h」を利用するのですが、使い方はArduinoのリファレンスでWireのところを参照してください。

「スレーブ側」↓
#include <Wire.h>
#define dist_PIN 1

void setup()
{
    Serial.begin(9600);
    Wire.begin(8); // スレーブのアドレスを8に設定
    Wire.onRequest(psd); // マスターに呼ばれたときに呼び出す関数
}

void loop()
{
    delay(100);
}

void psd()
{
    // 以下は距離[cm]を求める近似計算
    int temp,distance;
    temp = analogRead(dist_PIN);
    if(temp<4) temp = 4; // 0除算を回避
    distance = (6787 / (temp - 3) );

    Wire.write(distance); // 1バイト送信
}
「マスター側」↓
#include <Wire.h>

void setup()
{
    Serial.begin(9600);
    Wire.begin(); // マスターに設定
}

void loop()
{
    // スレーブの8番に接続されているデバイスから1バイトのデータを取得
    // 送られてくる値は10進数で255以下、つまり1バイト以内であるため
    Wire.requestFrom(8, 1);

    // Wire.available()がfalseになるまでループ
    // 要求より短いデータがくる可能性あり
    while(Wire.available())
    { 
        int c = Wire.read(); // 1バイト受信
        Serial.print(c);
    }
    Serial.println(" cm");

    delay(500);
}

スイッチのON/OFF (文字列の送信)

配線例 同じく上がスレーブで下がマスターです。





「スレーブ側」↓
#include <Wire.h>
int pullup =1;
void setup()
{
    Serial.begin(9600);
    Wire.begin(8); // スレーブのアドレスを8に設定
    Wire.onRequest(on_off); // マスターに呼ばれたときに呼び出す関数
    pinMode(12,INPUT_PULLUP); //内部プルアップ抵抗を使う
}

void loop()
{
    delay(100);
}

void on_off()
{
    pullup = digitalRead(12);
    if (pullup == 0){
        Wire.write("ON "); // 3バイト送信
    }
    else{
        Wire.write("OFF"); // 3バイト送信
    }
}
「マスター側」↓
#include <Wire.h>

void setup()
{
    Serial.begin(9600);
    Wire.begin(); // マスターに設定
}

void loop()
{
    // スレーブの8番に接続されているデバイスから3バイトのデータを取得
    // 送られてくるのは3バイトの文字列であるため
    Wire.requestFrom(8, 3); 

    while(Wire.available())
    { 
        char c = Wire.read(); // 1バイト受信
        Serial.print(c);
    }
    Serial.println("");

    delay(500);
}
結果

Wire.hを使って思ってたよりも簡単にI2C通信をすることができました。
今回はスレーブから値を読み取るだけでしたが、他にもマスターからスレーブへの命令を飛ばしたり、以前作った量産型Arduinoを複数台繋げたり、Raspberry Piを購入したのでそれとも繋げたりしたいです。

次回→Arduino同士でI2C通信(2)

※2015/04/16 追記
I2C通信するシリーズに記事を追加しました
【Ruby】 Raspberry Pi とArduinoでI2C通信

参考ページ
Arduino Duemilanoveを2個I2C接続
2台のarduinoをI2Cバスで接続して通信を行う実験

参考書籍
Arduinoで電子工作をはじめよう!

0 件のコメント:

コメントを投稿