Introduction: I²C Explained + an Example

In this instructable, I will first provide an overview of the circuitry and steps involved with setting up and creating a practical example of a connection between an Arduino microcontroller and a NodeMCU ESP8266 WiFi module via I²C. This is a great way to add WiFi capabilities to the Arduino UNO. In the end, I will give a thorough explanation of the I²C protocol on an intermediate level.


Step 1: The Wiring

Arduino Uno SDA > NodeMCU SDA

A4 > D1

Arduino Uno SCL > NodeMCU SCL

A5 > D2

Arduino GND > NodeMCU GND

LED Anode > Arduino GND

330 Ohm Resistor > LED Cathode

LED Cathode > Arduino DO 8

Step 2: The Code

In this section, I will explain the code aspect behind this project in a series of GitHub files, segment by segment, where I comment each line explaining its purpose in the overall program.

Take a look at the master's code, the NodeMCU:

Now for the slave code:

Step 3: Explanation

I²C (Inter Integrated Communication) is a way of having multiple devices communicate with each other with only 2 wires required. There are 2 classes of devices that can communicate with each other in I²C, the slave devices and the master devices. The master device sends out commands and requests data from slave devices. The slave devices listen for their addresses and responds with data for the master device to read from. The bulk of the process is essentially a repetitive sequence of bit addressing followed by an acknowledgement block. The sequence goes as follows:

1. A start block is sent out by the master to indicate the beginning of the sequence. This pretty much preps the slaves for them to pay attention when their names (addresses) are called out.

2. A 7 bit address is sent out by the master specifying which slave it wants to talk to. The bits are sent out according to the MSB (Most Significant Bit) to the LSB (Least Significant Bit). The MSB is the bit with the highest value, and the LSB is the bit with the least value.

3. The 8th bit is a R/W bit. This tells the slave whether we request information from it (read) or want to give information to it (write). After this bit is received, control of the SDA line is given to the slave, allowing it to perform whatever it was asked to do by the master. This bit wraps up the first byte.

4. The 9th block in the sequence is the acknowledgement block. This mainly serves as an A-OK from the slave to confirm the request has been received and smooth sailing can be assured. This acknowledgement block is seen multiple times throughout the entire communication.

5. The next sequence of 8-bit addressing is called the Internal Register Address. What this is is just the specific part of the slave device we want to read from. For example, a GY-521 gyroscope module does not have just one value the master can read from. This module can return x, y, and z values, acceleration, temperature, and a digital motion processor's calculations. All these values require their own, unique intrinsic addresses which guides the master to read from it when it requests that specific data. Of course, this is also followed by its own little acknowledgement block. We can request multiple different values from our slave device multiple times, and this step just repeats depending on how many values we want to read from.

6. Now that we collected the data from the internal addresses in our slave device in the previous step, it's time to send it over now! This last packet of bits (or byte) is the actual data that is being sent.

7. The final block is the special stop conditional block. It ends the transmission between the devices.

A great few resources explaining this further:

- HowToMechatronics' guide is especially useful, and it is where I got the image for this section from (2:00)

- This website helped me a lot when I was starting out;

Arduino Contest 2020

Participated in the
Arduino Contest 2020