How to make an I2C slave send data in an I2C system

The master device mostly controls the I2C slave device. In this post, we will send data from the master to the slave. This is useful as some projects require the I2c slave to send sensor readings to the master to be processed or displayed.

We will send distance readings from an ultrasonic sensor and display the distance in the master device’s serial monitor. You can use any sensor of your choice. We will also be making use of the newping.h Library so our ultrasonic sensor uses just a single wire for both Echo and Trigger pins.

Circuit diagram for the I2C slave and master

I2C slave

NOTE: The SDA and SCL pins can also be connected using A4 and A5 (SDA and SCL respectively).

Code for the I2C system

I2C Master code

#include <Wire.h>

#define SLAVE_ADDR 9

int distance;
int rval;

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

 byte readI2C(int address){
  Wire.requestFrom(address,1);
    rval=Wire.read();
    return rval;
}

void loop() {
 distance=readI2C(SLAVE_ADDR);
Serial.println(distance);
}

The above defines the slave address and declared variables to store the received data. The only new piece of code is the function below.

 byte readI2C(int address){
  Wire.requestFrom(address,1);
    rval=Wire.read();
    return rval;
}

This function uses the Wire.requestFrom(slave address, number of bytes) function to request data from the slave device and specify the number of bytes to be received. from the above function, the master then reads the data on the I2C bus using Wire.read() function and stores the data in the rval.

distance=readI2C(SLAVE_ADDR);

In the void loop, we called the readI2C(SLAVE_ADDR) function and stored the result in the distance variable then we printed the result in the serial monitor.

As an alternative, you can skip the readI2C() function entirely and just add Wire.requestFrom() in the loop then use the Wire.read() to get the data. View the code below.

#include <Wire.h>

#define SLAVE_ADDR 9

int distance;
int rval;

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

void loop() {
Wire.requestFrom(address,1);
 distance=Wire.read();
Serial.println(distance);
}

I2C slave code

#include <Wire.h>
#include <NewPing.h>

#define SLAVE_ADDR 9

#define TRIGGER_PIN  9 
#define ECHO_PIN     9 
#define MAX_DISTANCE 200 

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);

int distance;

void setup(){
  Wire.begin(SLAVE_ADDR);
  Wire.onRequest(requestEvent);
  Serial.begin(9600);
  
}

void requestEvent(){
Wire.write(distance);
}


void loop(){
  delay(50);                    
  distance=sonar.ping_cm();
  Serial.print("Ping: ");
  Serial.print(distance); 
  Serial.println("cm");
}

The above code uses the newping.h library to get the distance readings from the ultrasonic sensor and send the data to the master on request using the Wire.onRequest() function to send the data to the master.

void requestEvent(){
Wire.write(distance);
}

In the requentEvent() function, we just send the distance readings to the master. With this, the I2C slave sends data to the master.

Leave a Comment