Skip to content

I2C

Two Arduino boards Communication


ref.Arduino同士でI2C通信する方法

I2CではMasterとSlaveの組み合わせが大原則になっています。 通信の主導権は常にMasterが持ち、Masterからの要求に応じてSlaveが応える仕様になっています。 したがって、Slave同士での通信やSlaveからMasterにリクエストを送ることはできません。

In I2C, the combination of Master and Slave is a major principle. Master always takes the initiative in communication, and Slave responds to requests from Master. Therefore, it is not possible to communicate between Slave or send a request from Slave to Master.

Master(write), Secondary(read)

Master(write)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <Wire.h>

void setup() {
  Wire.begin();
}

void loop() {
  Wire.beginTransmission(8) ; //Secondary address #8
  Wire.write("1", strlen("1")); //Send 1 to Secondary
  Wire.endTransmission();
  delay(1000);

  Wire.beginTransmission(8) ;
  Wire.write("0", strlen("1"));
  Wire.endTransmission();
  delay(1000);
}

Secondary(read)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <Wire.h>
int x = 0;

void setup() {
  Wire.begin(8); //Secondary address is 8
  pinMode (13, OUTPUT); //Built in LED
  Wire.onReceive(receiveEvent);
}

void receiveEvent(int bytes) { //INTERRUPTION 割り込み
  x = Wire.read(); //read 1 from Master
}

void loop() {
  if (x == '1') {
    digitalWrite(13, HIGH);//LED
  }
  if (x == '0') {
    digitalWrite(13, LOW);//LED
  }
}

Master(request), Secondary(write)

Master(request)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <Wire.h>
int int_x = 0; // char

void setup() {
  Wire.begin();
  Serial.begin(9600);

}

void loop() {
  Wire.requestFrom(8, 1);    // request 1 bytes to Secondary #8
  while (Wire.available()) {
    int_x = Wire.read(); // receive from Secondary
    Serial.print("x = "); Serial.println(int_x);
  }
}

Secondary(write)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <Wire.h>
int int_y = 0; // char

void setup() {
  Wire.begin(8); //Secondary address is 8
  pinMode(5, INPUT);
  Wire.onRequest(requestEvent);
}

void requestEvent() { //INTERRUPTION 割り込み
  int_y = digitalRead(5);
  Wire.write(int_y); //write to Master
}

void loop() {
}

Master(write and request), Secondary(read and write)

Master Secondary
Write “1” to Secondary …(1)
ISR onReceive run receiveEvent …(2)
input “1” from Master into x …(3)
“1” run ISR within if(x == `1`){ } …(4)
request 1 byte to Secondary …(5)
loof forever and wait from Secandary …(6)
ISR onRequest run requestEvent …(7)
read value from sensor and send to Master …(8)
Read value from secondary …(9)
Exit from forever loop by the value from Secondary …(10)

Master(write and request)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <Wire.h>
int int_x = 0;

void setup() {
  Wire.begin();
  Serial.begin(9600);
}

void loop() {
  Wire.beginTransmission(8) ; // Secondary address is 8
  Wire.write("1", strlen("1")); // Send 1 to secondary ...(1)
  Wire.endTransmission();


  while (1) {// loop forever ...(6)
    Wire.requestFrom(8, 1);    // request 1 bytes to Secondary #8 ...(5)

    while (Wire.available()) {
      int_x = Wire.read(); // receive from Secondary ...(9)
      Serial.print("int_x = "); Serial.println(int_x);
    }

    if (int_x  == 1) { //...(10)
      break; //exit from forever loop
    }
    delay(1000);
  }
}

Secondary(read and write)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <Wire.h>
int x = 0;
int int_y = 0;

void setup() {
  Wire.begin(8); //Secondary address is 8
  pinMode (5, INPUT); //Sensor pin
  pinMode (13, OUTPUT); //Built in LED

  Wire.onReceive(receiveEvent); // ...(2)
  Wire.onRequest(requestEvent); // ...(7)
}

void receiveEvent(int bytes) { //Interrupt Service Routine 割り込み
  x = Wire.read(); //read 1 from Master ...(3)
}

void requestEvent() { //ISR 割り込み
  int_y = digitalRead(5); // ...(8)
  Wire.write(int_y); //write to Master
}

void loop() {

  if (x == '1') { // ...(4)
    //digitalWrite(13, HIGH);//LED

    while (int_y == 0) {
      int_y = digitalRead(5);
      digitalWrite(13, HIGH);
    }
    //rest
    digitalWrite(13, LOW);//LED
    x = '0';
  }
}

Example

Master

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include <Servo.h>
//#include <Servo_megaTinyCore.h>
#include <Wire.h>

int weight1 = 0;

int masu = 85; //weight of masu
int sake = 30; //weight of sake

int pour = 0;
//int x = 1;

int ledPin = 12;    // LED connected to digital pin 12

//int switchPin = 7; // Switch to behave scale weight
int switchPin = A3; // Switch to behave scale weight(pro micro)

Servo myservo1;  // create servo1 object to control a servo
Servo myservo2;  // create servo2 object to control a servo

int pos = 0;    //  change the servo degrees
int pos_now = 1;

int Liquid_level = 0; // received liquid_level from Secondary
//int int_x = 0;

void setup() {
  Serial.begin(9600);

  myservo1.attach(6);  // attaches the servo1 on pin 8 (PWM) to the servo object
  myservo2.attach(9);  // attaches the servo2 on pin 9 (PWM) to the servo object

  //Set the servos to initial positions
  myservo1.write(90);
  myservo2.write(135);

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

  //Wire.swap(1);
  Wire.begin();

}

void loop() {
  Serial.println("Loop");

  int sensorValue = analogRead(switchPin);
  float weight1 = sensorValue * ((masu + sake) / 1023.0);
  Serial.println(weight1);


  if (weight1 < 75) {
    // do nothing
    Serial.println("do nothing under 75g");
  } else if (weight1 > 90) {
    // do nothing
    Serial.println("do nothing over 90g");
  } else {

    // Servo1
    if ((weight1 >= 75) && (weight1 <= 90)) { //If the weight1 is 75-90g
      Serial.println("masu is ON");
      for (pos = 90; pos >= 0; pos -= 1) {
        myservo1.write(pos);              // tell servo1 to go to position in variable 'pos'
        delay(30);                       // waits 30ms for the servo to reach the position
      }

      //mp3
      Wire.beginTransmission(8) ; // Secondary address is 8
      Wire.write("2", strlen("2")); // Send 1 to secondary
      Wire.endTransmission();
      Serial.print("sent "); Serial.println("2");
      delay(500);

      //OLED
      Wire.beginTransmission(9) ; // Secondary address is 9
      Wire.write("3", strlen("3")); // Send 1 to secondary
      Wire.endTransmission();
      Serial.print("sent "); Serial.println("3");
      delay(500);

      // Servo2
      for (pos = 135; pos >= 55; pos -= 1) { // goes from 135 degrees to 55 degrees
        myservo2.write(pos);
        sensorValue = analogRead(switchPin);
        weight1 = sensorValue * ((masu + sake) / 1023.0);
        Serial.println(weight1);
        Serial.println("pouring quickly");
        pos_now = pos;
        if (weight1 >= (masu + sake / 3) ) { //85 + 30/3=95g
          break;
        }
        delay(50);
      }
      //in here, weight1 >= masu + sake / 3

      // Servo2
      for (pos = pos_now; pos >= 45; pos -= 1) { // goes from 55 degrees to 45 degrees
        myservo2.write(pos);
        sensorValue = analogRead(switchPin);
        weight1 = sensorValue * ((masu + sake) / 1023.0);
        Serial.println(weight1);
        Serial.println("pouring slowly");

        pos_now = pos;
        if (weight1 >= (masu + sake)) { //85 + 30=115g
          break;
        }
        delay(300);
      }
      // in here, weight1 > masu + sake

      // Servo2
      for (pos = pos_now; pos <= 135; pos += 1) { // goes from 45 degrees to 135 degrees
        myservo2.write(pos);
        delay(50);
      }

      // Servo1
      for (pos = 0; pos <= 90; pos += 1) { // goes from 0 degrees to 90 degrees
        // in steps of 1 degree
        myservo1.write(pos);
        delay(30);
        //
      }

      pour = pour + 1;
      Serial.print("pour= "); Serial.print(pour); Serial.println(" not_empty");
      delay(500);

      if (pour >= 3) {
        Serial.println("empty now request to Refill");
        delay(3000);

        Wire.beginTransmission(8) ; // Secondary address is 8
        Wire.write("1", strlen("1")); // Send 1 to secondary
        Wire.endTransmission();
        Serial.print("sent "); Serial.println("1");
        delay(3000);

        while (1) { // loop forever
          Wire.requestFrom(8, 1); // request 1 bytes from secondary device #8
          Serial.println("request Liquid_level");

          while (Wire.available()) {
            Liquid_level = Wire.read(); // receive from secondary
            Serial.print("Liquid_level="); Serial.println(char(Liquid_level));// "1" is ASCII code 49
          }
          if (Liquid_level == '1') {//Liquid is full
            break;
          }
          delay(5000);
        }//while(1)
        Serial.println("break");
        pour = 0;
      }//if (pour >= 3)

    }//if
  }//else
  delay(500);

} //loop

Secondary

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <Wire.h>
int x = 0;
int Liquid_level = 0;

#include <SoftwareSerial.h>
SoftwareSerial Serial1(2, 3);//(Rx_UNO_to_Tx_mp3,Tx_UNO with 1k ohm)

void setup() {
  Wire.begin(8);
  pinMode (14, OUTPUT); // A0 MOTOR

  Serial.begin(9600);
  Serial1.begin(9600);
  volume(0x1E);//Volume settings 0x00-0x1E

  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
}


void receiveEvent(int bytes) { // Interrupt Service Routine 割り込み
  x = Wire.read(); // read e from Master
  Serial.print("received -------------" ); Serial.println((char)x);// "1" is ASCII code 49
  Liquid_level = 0;//empty
}


void requestEvent() { //ISR 割り込み
  Serial.println("REQUESTEvent");
  if (Liquid_level == 1) {
    Wire.write("1", strlen("1"));
    Serial.print("sent Liquid_level = "); Serial.println(Liquid_level);
  } else
    Wire.write("0", strlen("0"));
}


void loop() {
  Serial.println("Loop");

  //mp3
  if (x == '2') {
    Serial.println("play music");
    play(0x01);//Play the specified audio:0x01-file0001//au
    delay(2000);
    x = '0';
  }

  //Motor
  if (x != '1') {
    // do nothing
    Serial.println("do nothing");
  }
  else if (x == '1') {
    Serial.println("MOTOR ON");
    digitalWrite(14, HIGH); //MOTOR
    delay(5000);
    digitalWrite(14, LOW);//MOTOR
    delay(500);
    Liquid_level = 1;//full
    Serial.print("Motor OFF: Liquid_level ="); Serial.println(Liquid_level);
    x = '0';
  }

  delay(500);
}//loop


void play(unsigned char Track) {
  unsigned char play[6] = {0xAA, 0x07, 0x02, 0x00, Track, Track + 0xB3};
  Serial1.write(play, 6);//(buf, len)
}

void volume( unsigned char vol) {
  unsigned char volume[5] = {0xAA, 0x13, 0x01, vol, vol + 0xBE};
  Serial1.write(volume, 5);
}

Open 2 Serial Monitors

mac in Terminal

1
2
3
4
5
6
7
8
% ls /dev | grep usb
tty.usbmodem14301
tty.usbserial-D307RG9V

% screen /dev/tty.usbmodem14301 9600

// command + n // open new Terminal
% screen /dev/tty.usbserial-D307RG9V 9600

Windows in PuTTY

Setup

  • Download PuTTY from site or here
  • Run Installer (putty-64bit-0.76-installer)

Open Serial Monitor

  • Start “PuTTY” from Start menu and set COM port

  • To open 2nd Serial Monitor, re-start “PuTTy” and set other COM port

You may see here to send Japanese character in strings.

How to find COM ports

  • type cmd to open Command Prompt
  • type mode
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
C:\Users\name>mode

デバイス状態 COM6:
------------
    ボー レート:        9600
    パリティ:           None
    データ ビット:      8
    ストップ ビット:    1
    タイムアウト:       OFF
    XON/XOFF:           ON
    CTS ハンドシェイク: OFF
    DSR ハンドシェイク: OFF
    DSR の検知:         OFF
    DTR サーキット:     ON
    RTS サーキット:     ON


デバイス状態 COM4:
------------
    ボー レート:        0
    パリティ:           None
    データ ビット:      0
    ストップ ビット:    1
    タイムアウト:       OFF
    XON/XOFF:           OFF
    CTS ハンドシェイク: OFF
    DSR ハンドシェイク: OFF
    DSR の検知:         OFF
    DTR サーキット:     OFF
    RTS サーキット:     ON


デバイス状態 CON:
-----------
    行数:                9001
    桁数:                120
    キーボード速度:      31
    キーボード ディレイ: 1
    コード ページ:       932
    コード ページ:       932

I2C address

1
2
3
#define SCREEN_ADDRESS 0x3C    //0b0111100  //7bits
#define SCREEN_ADDRESS 0x78    //0b01111000 //8bits
#define SCREEN_ADDRESS 0x78>>1 //0b0111100  //
The Wire library uses 7 bits addresses. 8th bit is used as Read/Write.

7bits (device) address Decimals Hexadecimal 8 bits address(7bit +0) Hex
0b0000 000_ 0d000 Reserved 0x00 0b0000 0000 0x00
0b0000 001_ 0d001 Reserved 0x01 0b0000 0010 0x02
0b0000 010_ 0d002 Reserved 0x02 0b0000 0100 0x04
0b0000 011_ 0d003 Reserved 0x03 0b0000 0110 0x06
0b0000 100_ 0d004 Reserved 0x04 0b0000 1000 0x08
0b0000 101_ 0d005 Reserved 0x05 0b0000 1010 0x0A
0b0000 110_ 0d006 Reserved 0x06 0b0000 1100 0x0C
0b0000 111_ 0d007 Reserved 0x07 0b0000 1110 0x0E
0b0001 000_ 0d008 min 0x08 0b0001 0000 0x10
0b0111 100_ 0d060 OLED 0x3C 0b0111 1000 0x78
0b1111 111_ 0d127 max 0x7F 0b1111 1110 0xFE

ref. Convert decimal to binary, octal and hexadecimal

There are both 7- and 8-bit versions of I2C addresses. 7 bits identify the device, and the eighth bit determines if it’s being written to or read from. The Wire library uses 7 bit addresses throughout. If you have a datasheet or sample code that uses 8 bit address, you’ll want to drop the low bit (i.e. shift the value one bit to the right), yielding an address between 0 and 127. However the addresses from 0 to 7 are not used because are reserved so the first address that can be used is 8. Please note that a pull-up resistor is needed when connecting SDA/SCL pins. Please refer to the examples for more informations. MEGA 2560 board has pull-up resistors on pins 20 - 21 onboard.

ref. Wire Library


Last update: October 6, 2021