The I2C communication is not easy and there are many things that can go wrong. Two Arduino boards instead of one board are often used for the wrong reason in the first place.
Using a serial port is easier. The Arduino Leonardo has an extra hardware serial port, you could use the serial port to communicate between two Arduino boards. The Arduino Mega 2560 has three extra serial ports.
Sometimes two Arduino boards are used because multiple things have to be done at the same time.
When you use the Blink Without Delay example with millis
, then the Arduino can do many things at the same time.
Sometimes two Arduino boards are used because there is some distance between the Arduino boards.
The I2C bus is a "bus", but that does not mean that you can use a long cable. You can go up to 20 inch (50 cm).
When two Arduino Uno boards are connected with the I2C bus, then three wires are needed:
- GND to GND
- SDA to SDA (plus pullup resistor)
- SCL to SCL (plus pullup resistor)
For a small test with short jumper wires, it is possible to do that without pullup resistors. For the final project pullup resistors should be used for SDA and SCL, for example 4k7 or 10k.
The example below uses a flag in the Slave Arduino. That extra variable makes it easier.
In the Slave receiveEvent
function, there is a extra check to check if exactly one byte is received. That extra check is not required, but it can be useful.
I show this example as something to start with, because there are too many bad examples for I2C between Master and Slave.
Master
#include <Wire.h>
byte dataTransmit;
void setup() {
Wire.begin();
}
void loop() {
Wire.beginTransmission(9); // sending to slave with i2c address 9
Wire.write(dataTransmit); // the data to send
Wire.endTransmission();
dataTransmit++; // all numbers from 0 to 255
delay(250); // 250ms delay, to send 4 times per second
}
Slave
#include <Wire.h>
volatile byte dataReceive;
volatile bool newData; // a flag to indicate that new data has arrived
void setup() {
Wire.begin(9); // create i2c slave at i2c address 9
Wire.onReceive(receiveEvent);
Serial.begin(9600);
}
void loop() {
if(newData) { // is there new data?
Serial.print("Received: ");
Serial.println(int(dataReceive)); // convert to integer to print the number
newData = false; // reset flag
}
}
void receiveEvent(int howMany) {
if(howMany == 1) { // extra check, to check if one byte is received
dataReceive = Wire.read();
newData = true; // set flag, there is new data
}
}
volatile int x = 0;