In the few years I have been contributing to the Forum I don't recall any advice about using I2C (rather than Serial) for communication between two Arduinos. I had been assuming that I2C was only suitable for very short range communication of the order of 20cm to 30cm but I recently came across the Megapoints model railway control system which uses I2C over distances of 2 metres or more. Having taken the trouble to learn a little bit about I2C is seems to be easier to use than Serial and is especially useful for communicating between two Unos or nanos when you want to keep the single HardwareSerial port free.
If you are interested Nick Gammon has a lot of technical info about I2C on his website. This Tutorial is just intended to provide some simple example programs for communication between two Arduinos.
I2C SENDS PACKETS OF DATA
I2C is different from Serial because it sends messages as packets with a defined start and end. This makes it easy to send binary data as well as text. With Serial communication you have to provide the start- and end-markers (see for example the 3rd example in Serial Input Basics) which is easy when sending text but not so easy when sending binary data.
Using the Arduino Wire library I2C is limited to sending packets of not more than 32 bytes. I suspect that is sufficient for many situations. Longer messages can obviously be broken down into a series of 32 byte messages but I do not propose to cover that here.
I2C USES TWO WIRES
I2C operates using two wires - one for data and one for the clock. (I2C is also know as TWI - Two Wire Interface). The purpose of the clock is to signal to the slave when it should sample the data to get a valid value. With Serial there is only one wire for each direction and the sampling of bits is based on time set by the baud rate. (Note that both I2C and Serial also need a GND connection). Because it has only one data line (unlike Serial which has Rx and Tx lines) I2C can only operate in one direction at a time. Of course messages only take a few millisecs so it is easy to give the impression of two-way communication.
MODES OF OPERATION
The Wire library has, basically, two modes of operation. In the first case Arduino A can send a message to Arduino B with A acting as master and B acting as slave. Later the roles can be reversed and B (as master) can send a message to A (as slave). This is the basis for my first two examples.
The other mode is when the master requests data from the slave and this is used in my third example. In all cases the clock signal is provided by the master so, when the slave is requested to provide data it must be ready to do so immediately while the master is supplying the clock signal. Also the maximum number of bytes to be transferred is determined by the master.
I2C IS A BUS AND DEVICES HAVE ADDRESSES
I2C is a bus system which means that several devices can be connected at the same time and each device is identified by its address. (This is another difference from Serial which is a one-to-one system.) For the Wire library the addresses are a single byte in the range 8 to 119 allowing for 112 different devices. (The other values are reserved for special purposes which I will not cover here.) My example program has only been tested with two Arduinos but could probably be extended to several. My programs can also be used in parallel with other devices (such as sensors) connected to the I2C bus. Just ensure that every device has a separate address. The Wire library waits until the bus is free before starting a transmission so data collisions are avoided unless two devices start transmitting at precisely the same microsecond - which is unlikely. (Note that data collisions are not a problem with Serial as it is a one-to-one system with separate Rx and Tx wires).
I2C IS INTERRUPT DRIVEN
Unless it is actually sending a message the I2C system is always listening for a new message. When a message arrives the I2C systems makes a call to a function that you will have included in your program. The code in that function should be as short as possible to allow the function to complete quickly so that the interrupt can be completed and normal processing resumed. There should be no Print statements in the function. In the examples I have named the functions receiveEvent() and requestEvent(), however you can use any names you like for these functions.
THE EXAMPLE PROGRAMS
I have included three example programs. In the first pair the master only sends data to the slave. In the second example the master and slave can swap roles to provide two-way communication. In the third pair the master sends data to the slave and also requests data from the slave. This is also two-way communication but strictly controlled by the master.
Continues in next Post