I2C Communication with Arduino Uno

3
(2)

Last Updated on 13th April 2024 by peppe8o

In this tutorial, I’ll show how to perform I2C communication with two Arduino boards. The potentiometer and LCD are used to display the data sharing from a master Arduino to the slave one. The tutorial shows the simulation results for the potentiometer values read from the master and applied to the slave and vice versa, performed controlling the related LCD attached.

There are many devices which work on Inter-Integrated Circuit (I2C) protocols to share data with each other. The communication of the board is independent of the baud rate as of the USART.

Introduction

Inter-Integrated Circuit (I2C), also spelt IIC, is a synchronous, master/slave, packet-switched, single-ended serial communication bus that supports multiple controllers and targets. In order to transmit and receive data using the I2C protocol, it uses two lines: a serial clock pin (SCL), which pulses periodically by the Uno Controller (master) board, and a serial data pin (SDA), through which data pass between the transmitter and receiver.

So, the SDA line transfers data, and the SCL line synchronizes the devices with the clock signal.

Working Phenomena

The I2C Bus connects to two different sorts of devices: slave and master. The bus masters handle data transmission and reception to and from the slave devices. The master also provides the clock signal. The I2C protocol also supports multiple masters and multiple slaves, but in this tutorial, we’ll simplify with a single master and slave.

Each slave device connected to the I2C bus gets an exclusive 7-bit address. The master chooses a specific slave using this address to send or receive data, and the chosen slave reacts in accordance with the request.

i2c-message-structure
I2C communication data bits

What We Need

Arduino Uno R3 board

As usual, I suggest adding from now to your favourite e-commerce shopping cart all the needed hardware, so that in the end you will be able to evaluate overall costs and decide if continue with the project or remove them from the shopping cart. So, hardware will be only:

Check hardware prices with the following links:

Amazon Arduino Uno box
Amazon rotary potentiometer box
Amazon Dupont Wiring box

Step-by-Step Procedure

Wiring Diagram of Master and Slave Arduino board

The following wiring diagram gives the I2C communication between two Arduino boards (more info on ports can be found at Arduino pinout).

Each Arduino will read the value from its nearest potentiometer and send it to the other Arduino. The 2 potentiometers on the LCDs are just to control the contrast and don’t affect the read value variable.

Wiring Diagram of the SD card with Arduino Uno

Please find below more wiring info:

  • GND: GND of both boards need to connect together
  • Master A4: Slave A4
  • Master A5: Slave A5
  • LCD wires are VCC=5V, GND= GND, rs=2, enable = 7, D4=8, D5=9, D6=10, D7=11 for both master and slave Contrast = Connected with a potentiometer to change the value for a contrast setting
  • The potentiometer of both boards is connected at A0 of their board.

Get the code and Library for the I2C communication between Arduino

Connect your PC to Arduino and open Arduino IDE. For the very first steps, you can refer to Connecting Windows PC with Arduino tutorial. You can get the .ino code and libraries from my download area with the following link:

master_code.ino

slave_code.ino

Our I2C test will use the Wire.h library, which is already included in our Arduino IDE.

You also need to install the LiquidCrystal library, according to my Install Arduino Libraries: methods to add libraries with Arduino IDE tutorial, available from the Library Manager in Arduino IDE:

arduino-liquidcrystal-library-manager

Code Explanation

Section 1: Master Code

We start by adding the I2C library, followed by the LCD library and its pins definition.

#include<Wire.h>
#include<LiquidCrystal.h>
LiquidCrystal lcd(2, 7, 8, 9, 10, 11);

In the setup, we open a the serial monitor at a baud rate of 9600 to visualize the data coming after receiving. The wire.begin() command enables an 8-bit data communication.

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

We also initialize our LCD with a welcome message that will last 5 seconds (5.000 milliseconds). Then, we’ll clear the LDC display in order to get it for receiving data:

  lcd.begin(16,2);                    //Initilize LCD display
  lcd.setCursor(0,0);                 //Sets Cursor at first line of Display 
  lcd.print("Peppe8o");               //Prints Peppe8o in LCD 
  lcd.setCursor(0,1);                 //Sets Cursor at second line of Display
  lcd.print("I2C 1 ARDUINO");         //Prints I2C ARDUINO in LCD
  delay(5000);                        //Delay 5 seconds
  lcd.clear();                        //Clear LCD display
}

In the loop section, the master requires to the I2C device with address “8” (our Arduino slave) 1 byte of data. We also start listening to the communication to get it stored in our MasterReceive variable. This will be the value that we’ll show in our Master LCD, received from the Slave:

void loop()
{
    Wire.requestFrom(8,1);
    byte MasterReceive = Wire.read();

On the other hand, the master must send its potentiometer value to the slave. So, we proceed to read the Master potentiometer value, mapping it from the raw 0-1023 range to a shorter 0-127 range, and then we’ll transmit it on the I2C port:

    int potvalue = analogRead(A0);
    byte MasterSend = map(potvalue,0,1023,0,127); 

    Wire.beginTransmission(8);
    Wire.write(MasterSend);
    Wire.endTransmission();

All the data have been now shared between Master and Slave. The loop ends by managing their presentation on LCD (and in our serial monitor), finally adding a 500 milliseconds delay before running a new loop:

    lcd.setCursor(0,0);
    lcd.print(">>  Master  <<");
    lcd.setCursor(0,1);
    lcd.print("SlaveVal:");
    lcd.print(MasterReceive);
    Serial.println("Master Received From Slave");
    Serial.println(MasterReceive);
    delay(500);
    lcd.clear();
}

Section 2: Slave Code

Differently from Master, which has the control to initialize actions on I2C bus, the Slave will only react to actions executing 2 main functions:

  • when the Master requires data, the Slave will execute the requestEvent() function
  • when the Master sends data, the Slave will execute the receiveEvent() function

That said, the Slave code starts initializing the required libraries similarly to the master case:

#include<Wire.h>
#include<LiquidCrystal.h>
LiquidCrystal lcd(2, 7, 8, 9, 10, 11);

We also need a variable to store what values have been transmitted by Master, in order to get them from the receiveEvent() function and display them in our main loop:

byte SlaveReceived;

In the Slave setup section, we again initialize the serial monitor and then we’ll register the Arduino slave board with address “8”:

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

As anticipated, we initialize the onReceive and onRequest actions, by referring them to the functions defined later in the code:

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

Again, a welcome message will print for 5 seconds, before clearing the LCD to perform the I2C communication work:

  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("Peppe8o");
  lcd.setCursor(0,1);
  lcd.print("I2C 2 ARDUINO");
  delay(5000);
  lcd.clear();
} 

The request event function starts getting the Slave potentiometer and mapping from 0 to 127. The result is sent to I2C for the master:

void requestEvent()
{
  int potvalue = analogRead(A0);
  byte SlaveSend = map(potvalue,0,1023,0,127);
  Wire.write(SlaveSend);
}

Similarly, the receive event gets the data from the I2C and stores it in the “SlaveReceived” variable:

void receiveEvent (int howMany)
{
   SlaveReceived = Wire.read();
}

In the main loop, the slave will just display on the LCD (and on the serial monitor) what is stored in our SlaveReceived variable:

void loop(void)
{
  lcd.setCursor(0,0);                              //Sets Currsor at line one of LCD
  lcd.print(">>  Slave  <<");                      //Prints >> Slave << at LCD
  lcd.setCursor(0,1);                              //Sets Cursor at line two of LCD
  lcd.print("MasterVal:");                         //Prints MasterVal: in LCD
  lcd.print(SlaveReceived);                        //Prints SlaveReceived value in LCD received from Master
  Serial.println("Slave Received From Master:");   //Prints in Serial Monitor
  Serial.println(SlaveReceived);
  delay(500);
  lcd.clear();
}

Testing the I2C communication with Arduino Uno

When the potentiometer data from the master changes by rotating it, the changed data are sent to the slave to display on the slave LCD. Similarly, when the potentiometer at the slave rotates, values will show on the master LCD. The communication means between both boards I2C is set by pins A4 and A5.

i2c arduino communication test 1
i2c arduino communication test 2
i2c arduino communication test 3
i2c arduino communication test 4

What’s Next

Please find more tutorials on Arduino in peppe8o Arduino archives.

Enjoy!

Umar Jamil

For any queries and help with work, please contact me at:
Whatsapp: +92-346-661-7017/ Link

Email: umarjamil0007@gmail.com

How useful was this post?

Click on a star to rate it anonymously!

Average rating 3 / 5. Vote count: 2

No votes so far! Be the first to rate this post.

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?