How to connect two Arduino boards using I2C

While a single Arduino can accomplish many tasks, some projects may require the use of more than one board to handle different functions.

So, to allow data transfer between two microcontrollers, a communication protocol such as CAN, SPI, I2C or UART must be established.

This tutorial will cover the basics of how I2C works, the hardware connections, and the software implementation needed to set up two Arduino boards as I2C master and slave.

What is I2C?

Inter-Integrated Circuit (I2C) is a communication protocol widely used in embedded systems and microcontrollers to allow data transmission between electronic devices. Unlike SPI (Serial Peripheral Interface), I2C allows you to connect multiple master devices to a bus with one or more slave devices. It was first used by Philips and is also known as the Two Wire Interface (TWI) communication protocol.

How does I2C communication work?

I2C uses two bidirectional lines: Serial Data (SDA) and Serial Clock (SCL) to transfer data and synchronize communication between devices. Each device connected to the I2C bus has a unique address that identifies it during communication. The I2C protocol allows multiple devices to share the same bus, and each device can act as master or slave.

How to connect two Arduino boards using I2C Picture 1How to connect two Arduino boards using I2C Picture 1

Communication is initiated by the master device and incorrect addressing of the slave device may cause transmission errors. One major advantage of I2C communication is notable for the flexibility it offers when it comes to power management. Devices operating at different voltages can still communicate effectively with the help of a voltage converter. This means that devices operating at 3.3V require a voltage converter to connect to the 5V I2C bus.

Wire Library

The Wire library is a built-in Arduino library that provides functions for communicating over I2C. It uses two pins - SDA and SCL - on the Arduino board for I2C communication.

I2C pins on Arduino Uno:

How to connect two Arduino boards using I2C Picture 2How to connect two Arduino boards using I2C Picture 2

Arduino Nano I2C pins:

How to connect two Arduino boards using I2C Picture 3How to connect two Arduino boards using I2C Picture 3

To use the library, you must include the Wire.h header file at the top of your Arduino sketch.

#include 

The Wire library provides functions to initiate communication with an I2C device, sending and receiving data. Some important functions you should know about include:

  1. Wire.begin()  is used to join the I2C bus and initiate communication.
  2. Wire.beginTransmission() is used to specify the slave address and initiate transmission.
  3. Wire.write()  is used to send data to the I2C device.
  4. Wire.endTransmission()  is used to terminate the transmission and check for errors.
  5. Wire.requestFrom()  is used to request data from an I2C device.
  6. Wire.available()  is used to check if data is available to read from the I2C device.
  7. Wire.read()  is used to read data from an I2C device.

Use the Wire.beginTransmission() function to set the sensor's address, which is inserted as an argument. For example, if the sensor's address was 0x68 , you would use:

Wire.beginTransmission(0x68);

Arduino I2C Hardware Setup

To connect two Arduino boards using I2C, you will need the following hardware components:

  1. Two Arduino boards (master and slave)
  2. Breadboard
  3. Cables
  4. Two 4.7kΩ . pull-up resistors

Connect the SDA and SCL pins of both Arduino boards to the breadboard. Connect the pull-up resistors between the SDA and SCL pins to the 5V power line on the breadboard. Finally, connect the two breadboards together using cables.

Arduino Uno . Circuit

How to connect two Arduino boards using I2C Picture 4How to connect two Arduino boards using I2C Picture 4

 

Arduino Nano Circuit

How to connect two Arduino boards using I2C Picture 5How to connect two Arduino boards using I2C Picture 5

Set up Arduino board as I2C Master and Slave device

Use the Wire.requestFrom() function to specify the address of the slave device we want to communicate with. Then use the Wire.read() function to get the data from the slave device.

Master device code:

#include void setup() { Wire.begin(); // join i2c bus Serial.begin(9600); // start serial for output } void receiveData() { int address = 8; int bytesToRead = 6; Wire.requestFrom(address, bytesToRead); while (Wire.available()) { char data = Wire.read(); Serial.print(data); } delay(500); } void loop() { receiveData(); }

The Wire.onReceive() function is used to specify what to do when the slave device receives data from the master device. In the above code, the Wire.available() function checks if there is data available and the Wire.read() function reads the data sent by the master device.

Slave device code:

#include void setup() { Wire.begin(8); // join the I2C bus with address 8 Wire.onReceive(receiveEvent); // call receiveEvent when data is received } void loop() { delay(100); } void receiveEvent(int bytes) { Wire.write("hello "); // respond with message of 6 bytes as expected by master }

Send and receive data using I2C

In this example, read the temperature from the DHT11 temperature sensor that communicates with the Arduino slave and print it on the serial monitor of the Arduino master.

How to connect two Arduino boards using I2C Picture 6How to connect two Arduino boards using I2C Picture 6

 

Let's modify the code we wrote earlier to include a temperature measurement that we will then send to the motherboard via the I2C bus. The main board can then read the sent value, displaying it on the serial monitor.

Master device code:

#include void setup() { Wire.begin(); Serial.begin(9600); Serial.println("Master Initialized!"); } void loop() { Wire.requestFrom(8, 1); // Request temperature data from slave if (Wire.available()) { byte temperature = Wire.read(); // Read temperature data from slave Serial.print("Temperature: "); Serial.print(temperature); Serial.println(" °C"); } delay(2000); // Wait for 2 seconds before requesting temperature again }

Slave device code:

#include #include #define DHTPIN 4 // Pin connected to DHT sensor #define DHTTYPE DHT11 // DHT sensor type DHT dht(DHTPIN, DHTTYPE); byte temperature; void setup() { Wire.begin(8); // Slave address is 8 Wire.onRequest(requestEvent); dht.begin(); } void loop() { delay(2000); // Wait for 2 seconds for DHT to stabilize temperature = dht.readTemperature(); // Read temperature from DHT sensor } void requestEvent() { Wire.write(temperature); // Send temperature data to master }

You can customize this code to fit any sensor you may have in your project, or even display sensor values ​​on the display module to create your own thermometer and hygrometer. in room.

Slave addressing with I2C on Arduino

To read values ​​from components added to the I2C bus in such a project, it is important that you include the correct slave address when writing your code. Fortunately, Arduino provides a scanner library that simplifies the process of determining slave addresses, eliminating the need to sift through lengthy sensor data sheets and confusing online documentation.

Use the following code to determine the address of any slave device present on the I2C bus.

#include // Include the Wire library for I2C communication void setup() { Wire.begin(); // Initialize the I2C communication Serial.begin(9600); // Initialize the serial communication with a baud rate of 9600 while (!Serial); // Wait for the serial connection to establish Serial.println("nI2C Scanner"); // Print a message indicating the start of I2C scanning } void loop() { byte error, address; // Declare variables to store errors and device addresses int nDevices; // Declare a variable to store the number of devices found Serial.println("Scanning."); // Print a message indicating the start of I2C scanning nDevices = 0; // Set the number of devices found to 0 for (address = 1; address < 127; address++) { // Iterate over all possible I2C addresses Wire.beginTransmission(address); // Start a transmission to the current address error = Wire.endTransmission(); // End the transmission and store any errors if (error == 0) { // If no errors were found Serial.print("I2C device found at address 0x"); // Print a message indicating a device was found if (address < 16) Serial.print("0"); // If the address is less than 16, add a leading 0 for formatting purposes Serial.print(address, HEX); // Print the address in hexadecimal format Serial.println(" !"); // Print a message indicating a device was found nDevices++; // Increment the number of devices found } else if (error == 4) { // If an error was found Serial.print("Unknown error at address 0x"); // Print a message indicating an error was found if (address < 16) Serial.print("0"); // If the address is less than 16, add a leading 0 for formatting purposes Serial.println(address, HEX); // Print the address in hexadecimal format } } if (nDevices == 0) { // If no devices were found Serial.println("No I2C devices foundn"); // Print a message indicating no devices were found } else { // If devices were found Serial.println("donen"); // Print a message indicating the end of I2C scanning } delay(5000); // Delay for 5 seconds before starting the next scan }

Interfacing two Arduino boards using the I2C communication protocol provides a flexible and efficient way to achieve complex tasks that a single board cannot handle. With the help of the Wire library, communication between two boards using I2C becomes easy, allowing you to add more components to your project.

5 ★ | 1 Vote