3台のArduinoをI2Cで通信してみた

バージョン情報
Arduino IDE 1.0.6 ,windows 8.1

3台のArduinoをI2Cで接続し通信してみた。

マスター側は赤外線リモコン。
 Arduinoで赤外線リモコンとシリアル通信
スレーブ1は7セグ。
 Arduino スレーブその1: 1桁7セグ
スレーブ2はサーボ。
 Arduino スレーブその2:サーボ

fig

I2C通信を使うに場合はArduino同士の以下のピンを接続する。
・A4 (SDA):データ送受信用
・A5 (SCL):通信用クロック

ソースコード

以前作ったプログラムはシリアル通信(UART)用につくったので、I2C用に書き換える。とはいえ、Wire.hを使うので少し変えるだけでできた。
・Wire.h を include
・Serial.begin(9600) >> Wire.begin()
・Serial.println(“0”) >> Wire.write(“0”)
・Wire.write()の前にWire.beginTransmission(スレーブのアドレス)
・Wire.write()の後にWire.endTransmission()

【マスター側】

//IRリモコンコントローラ I2C master

#include <Wire.h>
 
#define IR_IN 10
#define IR_DATA_SIZE 100//768

byte ir_data[IR_DATA_SIZE];
byte ir_code[32];
byte ir_result;

 
void setup() {
  Wire.begin();
  pinMode(IR_IN, INPUT_PULLUP);     
}

void loop() {
  
  ir_result = ir_read(IR_IN);
  if (ir_result > 0){
    print_comand(ir_result);    
  }
  
}

//データ受信
byte ir_read(byte ir_pin){  
  unsigned long now, last, start_at;
  boolean stat;
  start_at = micros();
  
  //2.5秒以上入力がなかったら終了
  while(stat = digitalRead(ir_pin)){
    if(micros() - start_at > 2500000) return 0;
  }
  
  digitalWrite(13,HIGH);
  for(int i = 0; i < IR_DATA_SIZE; i++){
    ir_data[i] = 0;
  }

  start_at = last = micros();
  for(int i = 0; i < IR_DATA_SIZE; i++){
    //入力が反転するまで待ち(上限25ms)
    while(1){
      if(stat != digitalRead(ir_pin)) break;
      //信号終了
      if(micros() - last > 25000){
        digitalWrite(13,LOW);
        return ir_get_data();
      }
    }
    now = micros();
    ir_data[i] = (now - last)/100;  //byteに格納するあため
    last = now;
    stat = !stat;
  }
  
}

//データ解析
byte ir_get_data(){
  int j = 0;
  byte result = 0;
  
  //1or0判定
  for (int i = 3; i < 66; i+=2){
    if(ir_data[i] > 10){
      ir_code[j] = 1;
    }else{
      ir_code[j] = 0;
    }
    j++;
  }
  
  //データを数値化
  for (int i = 0; i < 8; i++){
    if(ir_code[i+16] == ir_code[i+24]){  //反転データチェック
      result = 0;
      break;
    }else{
      bitWrite(result,i,ir_code[i+16]);
    }
  }
  return result;
  
}

//コマンド出力
void print_comand(byte ir){
  switch (ir){
    case 69:
      //Wire.write("power");
      break;
    case 70:
      //Wire.write("mode");
      break;
    case 71:
      //Wire.write("mute");
      break;
    case 68:
      Wire.beginTransmission(2);
      Wire.write("play");
      break;
    case 64:
      Wire.beginTransmission(2);
      Wire.write("back");
      break;
    case 67:
      Wire.beginTransmission(2);
      Wire.write("forward");
      break;
    case 7:
      //Wire.write("EQ");
      break;
    case 21:
      //Wire.write("-");
      break;
    case 9:
      //Wire.write("+");
      break;
    case 22:
      Wire.beginTransmission(1);
      Wire.write("0");
      break;
    case 25:
      //Wire.write("repeat");
      break;
    case 13:
      //Wire.write("SD");
      break;
    case 12:
      Wire.beginTransmission(1);
      Wire.write("1");
      break;
    case 24:
      Wire.beginTransmission(1);
      Wire.write("2");
      break;
    case 94:
      Wire.beginTransmission(1);
      Wire.write("3");
      break;
    case 8:
      Wire.beginTransmission(1);
      Wire.write("4");
      break;
    case 28:
      Wire.beginTransmission(1);
      Wire.write("5");
      break;
    case 90:
      Wire.beginTransmission(1);
      Wire.write("6");
      break;
    case 66:
      Wire.beginTransmission(1);
      Wire.write("7");
      break;
    case 82:
      Wire.beginTransmission(1);
      Wire.write("8");
      break;
    case 74:
      Wire.beginTransmission(1);
      Wire.write("9");
      break;
    default:
      ;
  }
  Wire.endTransmission();

}

【スレーブ1】
こちらもシリアル通信(UART)用の部分を、I2C用に書き換える。
・Wire.h を include
・Serial.begin(9600) >> Wire.begin(スレーブのアドレス)
・Wire.begin の後に Wire.onReceive(関数名);
・Serial.available() >> Wire.available()
・Serial.read() >> Wire.read()

Wire.onReceiveで呼ぶ関数は『void 関数名(int 変数名)』でないとエラーになるようだ。

//7seg I2c

#include <Wire.h>

#define BUZZER   5
#define P_a 6
#define P_b 7
#define P_c 13
#define P_d 10
#define P_e 11
#define P_f 9
#define P_g 8
#define P_dp 12

char charA_out[80];
int freq;

void setup() {  
  pinMode(BUZZER,OUTPUT);
  pinMode(P_a,OUTPUT);
  pinMode(P_b,OUTPUT);
  pinMode(P_c,OUTPUT);
  pinMode(P_d,OUTPUT);
  pinMode(P_e,OUTPUT);
  pinMode(P_f,OUTPUT);
  pinMode(P_g,OUTPUT);
  pinMode(P_dp,OUTPUT);
  Wire.begin(1);
  Wire.onReceive(myReadLine);

}

void loop() {
  delay(100); 
}

void myReadLine(int a){
  int cnt_buf = 0;
  
  //受信したら
  if(Wire.available() > 0){
    delay(100);
    cnt_buf = max(79,Wire.available());  //受信文字数 最大79文字
    for (int iii = 0; iii < cnt_buf; iii++){
      charA_out[iii] = Wire.read();
    }
    charA_out[cnt_buf] = '\0';  //終端文字
  }
  seg_num(atoi(charA_out));
}

void seg_num(int num){
  //7セグに数字を出力
  byte out_seg;
  switch (num){
    case 0:
      out_seg = B11111100;
      break;
    case 1:
      out_seg = B01100000;
      break;
    case 2:
      out_seg = B11011010;
      break;
    case 3:
      out_seg = B11110010;
      break;
    case 4:
      out_seg = B01100110;
      break;
    case 5:
      out_seg = B10110110;
      break;
    case 6:
      out_seg = B10111110;
      break;
    case 7:
      out_seg = B11100000;
      break;
    case 8:
      out_seg = B11111110;
      break;
    case 9:
      out_seg = B11110110;
      break;
    default:
      out_seg = B00000001;
  }
  seg_disp(out_seg);
}


void seg_disp(byte out){
  digitalWrite(P_a,bitRead(out,7));
  digitalWrite(P_b,bitRead(out,6));
  digitalWrite(P_c,bitRead(out,5));
  digitalWrite(P_d,bitRead(out,4));
  digitalWrite(P_e,bitRead(out,3));
  digitalWrite(P_f,bitRead(out,2));
  digitalWrite(P_g,bitRead(out,1));
  digitalWrite(P_dp,bitRead(out,0));
}

【スレーブ2】


//スレーブ:サーボ
 
#include <Servo.h> 
#include <Wire.h>

#define servo_1 9
#define button_1 11
#define button_2 12

String str_cmd = "";
Servo myservo_1;
int angle = 90;
 
void setup() {                
  myservo_1.attach(servo_1);
  pinMode(button_1, INPUT_PULLUP);     
  pinMode(button_2, INPUT_PULLUP);
  Wire.begin(2);
  Wire.onReceive(myReadLine);
}

void loop() {
    
  //ボタンで手動操作  
  if (digitalRead(button_1) == 0){
    angle = min(angle + 10,180);
    myservo_1.write(angle);
  }
  
  if (digitalRead(button_2) == 0){
    angle = max(angle - 10,10);
    myservo_1.write(angle);
  }
  
  delay(20);
}

void myReadLine(int a){
  int cnt_buf = 0;
  str_cmd = "";
  char ch;
  
  //受信したら
  if(Wire.available() > 0){
    delay(100);
    cnt_buf = Wire.available();
    for (int iii = 0; iii < cnt_buf; iii++){
      ch = Wire.read();
      str_cmd.concat(ch);
    }
  }
  action_servo();    
}


//サーボアクション
void action_servo(void){
  if(str_cmd.endsWith("action")){
    char chA[5];
    str_cmd.toCharArray(chA,4);
    myservo_1.write(constrain(atoi(chA),10,180));
  }else if(str_cmd == "play"){
    myservo_1.write(90);
  }else if(str_cmd == "back"){
    myservo_1.write(10);
  }else if(str_cmd == "forward"){
    myservo_1.write(180);
  }
  
  delay(20);
}

動作確認

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です