I2C Communication between Master and Slave

Hi everyone

Basically, I am trying to make the Slave arduino the sender and the Master arduino the receiver. I have implemented an Ultrasonic Sensor onto the Slave arduino and it is outputting the distance measurements successfully onto the CLI of the Slave Arduino. However, I would like the Slave arduino to send the Ultrasonic measurements to the Master Arduino. I have tried getting it to work since the past couple of weeks but my attempts have not been successful. I can send basic messages such as 'Hello' but not sensor readings..

I'm currently at work so if you would like both the master and slave Arduino codes I can post them once I get home. Thanks in advance. :slight_smile:

Yes, we'll need to see the code to help you.

While you’re at it, post the “Hello” sketch that does work too.

Hi, apologies for the delay. Here is the code which works and sends the “Hello” message across.

Master Code

// Include the Arduino Wire Library for I2C
#include <Wire.h>

// Define Slave I2C Address 
#define SLAVE_ADDR 9

// Define Slave answer size
#define ANSWERSIZE 5

const int ledPin = 13;
const int ldrPin = A0;

int pressureAnalogPin = 1;
int pressureReading;

int noPressure = 5;
int lightPressure = 100;
int mediumPressure = 200;

void setup() {
  // put your setup code here, to run once:

  // Initialize I2C communications as Master
  Wire.begin();

  // Setup serial monitor
  Serial.begin(9600); // This is the baud rate
  Serial.println("I2C Master Demonstration"); // Let's test this..
  pinMode(ledPin, OUTPUT);
  pinMode(ldrPin, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:

  delay(50);
  Serial.println("Write data to slave");

  // Write a character to the Slave
  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write(0);
  Wire.endTransmission();

  Serial.println("Receive data");

  // Read response from Slave
  // Read back 5 characters
  Wire.requestFrom(SLAVE_ADDR,ANSWERSIZE);

  // Add characters to string
  String response = "";
  while (Wire.available()) {
    char b = Wire.read();
    response += b;
  }

  // Print to Serial Monitor
  Serial.println(response);

  int ldrStatus = analogRead(ldrPin);
  if (ldrStatus <= 200) { 
    digitalWrite(ledPin, HIGH);
    Serial.print("It is Dark, Turn on the LED : ");
    Serial.println(ldrStatus);
  } 
  else {
    digitalWrite(ledPin, LOW);
    Serial.print("It is Bright, Turn off the LED : ");
    Serial.println(ldrStatus);
  }
  
  pressureReading = analogRead(pressureAnalogPin);

  Serial.print("Pressure Pad Reading = ");
  Serial.println(pressureReading);

  if (pressureReading < noPressure) {
    Serial.println(" - No pressure");
  } else if (pressureReading < lightPressure) {
    Serial.println(" - Light Pressure");
  } else if (pressureReading < mediumPressure) {
    Serial.println(" - Medium Pressure");
  } else{
    Serial.println(" - High Pressure");
  }
  delay(1000);
  }

Slave Code

#include <Servo.h>

// Include Arduino library for I2C
#include <Wire.h>

// Define Slave I2C Address
#define SLAVE_ADDR 9

// Define Slave answer size
#define ANSWERSIZE 5

// Define string with response to Master 
String answer = "Hello";

Servo servo;
int trig=8;
int echo=9;
int duration;
float distance;
float meter;
int buzz = 10;

void setup()
{

  // Initialize I2C communications as Slave
  Wire.begin(SLAVE_ADDR);

  // Function to run when data requested from master 
  Wire.onRequest(requestEvent);

  // Function to run when data received from master
  Wire.onReceive(receiveEvent);

  // Setup Serial Monitor
  Serial.begin(9600);
  Serial.println("I2C Slave Demonstration");
  
  servo.attach(6);
  pinMode(trig, OUTPUT);
  digitalWrite(trig, LOW);
  delayMicroseconds(2);
  pinMode(echo, INPUT);
  delay(6000);
  pinMode(buzz, OUTPUT); // Buzzer is the digital one.
  Serial.println("Distance:");
}

void receiveEvent() {

  // Read while data received
  while (0 < Wire.available()) {
    byte x = Wire.read();
  }

  // Print to Serial Monitor
  Serial.println("Receive event");
}

void requestEvent() {

  // Setup byte variable in the correct sizw
  byte response[ANSWERSIZE];

  // Format answer as array
  for (byte i=0;i<ANSWERSIZE;i++) {
    response[i] = (byte)answer.charAt(i);
  }

  // Send response back to Master
  Wire.write(response,sizeof(response));

  // Print to Serial Monitor
  Serial.println("Request event");
}

void loop()
{
  // Time delay in loop
  delay(50);

  int i=20; // This can be set to any value to change the frequency.
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig,LOW);
  duration = pulseIn(echo, HIGH);
  distance = duration/58;
  Serial.print(distance);
  Serial.print("cm");
  Serial.print("\n"); // This is required to calculate the distance in centimeters.

  if(distance<=30 && distance >=1) // The buzzer will start buzzing if the distance is between 1 to 30cm.
  {
  i=distance*i; // This is the main algorithm.
  digitalWrite(buzz, HIGH);
    delay(i); // So the delay between switching will change according to the distance.
  digitalWrite(buzz, LOW);
    delay(i);
  }
  

  delay(10);
}

I hope the way I posted the code is okay, it’s my first time posting here so sorry if anything isn’t correct, thanks.

The way you posted the code is perfect. Thanks!

Now please post the code that is not working.

Great! well, I’m getting an error on the Slave sketch saying that the ‘receiveEvent’ was not declared in this scope…

Here is my code for the Slave Arduino:

#include <Servo.h>

// Include Arduino library for I2C
#include <Wire.h>

// Define Slave I2C Address
#define SLAVE_ADDR 9

// Define Slave answer size
#define ANSWERSIZE 5

Servo servo;
int trig=8;
int echo=9;
int duration;
float distance;
float meter;
int buzz = 10;

void setup()
{

  Wire.begin(4); // Join I2C bus with address #4
  Wire.onReceive(receiveEvent); // register event
  
  // Setup Serial Monitor
  Serial.begin(9600);
  
  servo.attach(6);
  pinMode(trig, OUTPUT);
  digitalWrite(trig, LOW);
  delayMicroseconds(2);
  pinMode(echo, INPUT);
  delay(6000);
  pinMode(buzz, OUTPUT); // Buzzer is the digital one.
  Serial.println("Distance:");
}

void loop()
{
  // Time delay in loop
  delay(50);

  int i=20; // This can be set to any value to change the frequency.
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig,LOW);
  duration = pulseIn(echo, HIGH);
  distance = duration/58;
  Serial.print(distance);
  Serial.print("cm");
  Serial.print("\n"); // This is required to calculate the distance in centimeters.

  if(distance<=30 && distance >=1) // The buzzer will start buzzing if the distance is between 1 to 30cm.
  {
  i=distance*i; // This is the main algorithm.
  digitalWrite(buzz, HIGH);
    delay(i); // So the delay between switching will change according to the distance.
  digitalWrite(buzz, LOW);
    delay(i);
  }

  void receiveEvent(int howMany)
  {
    while(1 < Wire.available()) // Loop through all but the last
    {
      char c = Wire.read(); // Receive byte as a character
      Serial.print(c); // Print the character
    }
    int x = Wire.read(); // Receive byte as an integer
    Serial.println(x);
  }
  

  delay(10);
}

You put the definition of your receiveEvent function inside the loop function. You can see this by the way the function definition is indented. You can’t define one function inside another function.

:o O wow, didn't see that! its done uploading now, thanks to you. I'm going to have a play with it and try to get it sending the distance measurements then come back if I encounter any other errors. Appreciate that!

You’re welcome. I’m glad if I was able to be of assistance.

I hope it will work correctly now, but if not we’re always here to help.
Enjoy!
Per

Okay, It uploaded successfully but it doesn’t seem to be outputting anything… It is giving me the same outputs I had before adding in this code which is odd.

Master Code

// Include the Arduino Wire Library for I2C
#include <Wire.h>

// Define Slave I2C Address
#define SLAVE_ADDR 9

// Define Slave answer size
#define ANSWERSIZE 5

const int ledPin = 13;
const int ldrPin = A0;

int pressureAnalogPin = 1;
int pressureReading;

int noPressure = 5;
int lightPressure = 100;
int mediumPressure = 200;

void setup() {
  // put your setup code here, to run once:

  Wire.begin();

  // Setup serial monitor
  Serial.begin(9600); // This is the baud rate
  pinMode(ledPin, OUTPUT);
  pinMode(ldrPin, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:

  Wire.requestFrom(2, 6); // Request 6 bytes from slave device.

  while (Wire.available()) // Slave may send less than requested.
  {
    float distance = Wire.read(); // Receive a byte as a float
    Serial.print(distance);
  }

  int ldrStatus = analogRead(ldrPin);
  if (ldrStatus <= 200) {
    digitalWrite(ledPin, HIGH);
    Serial.print("It is Dark, Turn on the LED : ");
    Serial.println(ldrStatus);
  }
  else {
    digitalWrite(ledPin, LOW);
    Serial.print("It is Bright, Turn off the LED : ");
    Serial.println(ldrStatus);
  }

  pressureReading = analogRead(pressureAnalogPin);

  Serial.print("Pressure Pad Reading = ");
  Serial.println(pressureReading);

  if (pressureReading < noPressure) {
    Serial.println(" - No pressure");
  } else if (pressureReading < lightPressure) {
    Serial.println(" - Light Pressure");
  } else if (pressureReading < mediumPressure) {
    Serial.println(" - Medium Pressure");
  } else {
    Serial.println(" - High Pressure");
  }
  delay(1000);
}

Slave Code

#include <Servo.h>

// Include Arduino library for I2C
#include <Wire.h>

// Define Slave I2C Address
#define SLAVE_ADDR 9

// Define Slave answer size
#define ANSWERSIZE 5

Servo servo;
int trig = 8;
int echo = 9;
int duration;
float distance;
float meter;
int buzz = 10;

void setup()
{

  Wire.begin(4); // Join I2C bus with address #4
  Wire.onReceive(receiveEvent); // register event

  // Setup Serial Monitor
  Serial.begin(9600);

  servo.attach(6);
  pinMode(trig, OUTPUT);
  digitalWrite(trig, LOW);
  delayMicroseconds(2);
  pinMode(echo, INPUT);
  delay(6000);
  pinMode(buzz, OUTPUT); // Buzzer is the digital one.
  Serial.println("Distance:");
}

void loop()
{
  // Time delay in loop
  delay(50);

  int i = 20; // This can be set to any value to change the frequency.
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  duration = pulseIn(echo, HIGH);
  distance = duration / 58;
  Serial.print(distance);
  Serial.print("cm");
  Serial.print("\n"); // This is required to calculate the distance in centimeters.

  if (distance <= 30 && distance >= 1) // The buzzer will start buzzing if the distance is between 1 to 30cm.
  {
    i = distance * i; // This is the main algorithm.
    digitalWrite(buzz, HIGH);
    delay(i); // So the delay between switching will change according to the distance.
    digitalWrite(buzz, LOW);
    delay(i);
  }

}
void receiveEvent(int howMany)
{
  while (1 < Wire.available()) // Loop through all but the last
  {
    float distance = Wire.read(); // Receive byte as a character
    Serial.print(distance); // Print the distance values
  }
  int x = Wire.read(); // Receive byte as an integer
  Serial.println(x);

  delay(10);
}

Try the following codes which are modifications of your Post#9. (There are many things wrong both in Master and Slave codes of Post#9.)

Master Code:

// Include the Arduino Wire Library for I2C
#include <Wire.h>

// Define Slave I2C Address
#define SLAVE_ADDR 9

// Define Slave answer size
#define ANSWERSIZE 5

const int ledPin = 13;
const int ldrPin = A0;

int pressureAnalogPin = 1;
int pressureReading;

int noPressure = 5;
int lightPressure = 100;
int mediumPressure = 200;

union
{
   float distance;                     //distance
   byte myData[4];
}data;

void setup() {
  // put your setup code here, to run once:

  Wire.begin();

  // Setup serial monitor
  Serial.begin(9600); // This is the baud rate
  pinMode(ledPin, OUTPUT);
  pinMode(ldrPin, INPUT);
}

void loop() 
{
  // put your main code here, to run repeatedly:

  Wire.requestFrom(SLAVE_ADDR, 4); // Request 4 bytes (32-bit binary32 data of float distance from slave 
  for(int i=0; i<4; i++)
  {
        data.myData[i] = Wire.read();  //

  }
   Serial.println(data.distance, 2);   //Serial Monitor shows distance sent by Slave (2-digit after decimal point)

  //while (Wire.available()) // Slave may send less than requested.
  //{
   // float distance = Wire.read(); // Receive a byte as a float
    //Serial.print(distance);
  //}

  int ldrStatus = analogRead(ldrPin);
  if (ldrStatus <= 200) {
    digitalWrite(ledPin, HIGH);
    Serial.print("It is Dark, Turn on the LED : ");
    Serial.println(ldrStatus);
  }
  else {
    digitalWrite(ledPin, LOW);
    Serial.print("It is Bright, Turn off the LED : ");
    Serial.println(ldrStatus);
  }

  pressureReading = analogRead(pressureAnalogPin);

  Serial.print("Pressure Pad Reading = ");
  Serial.println(pressureReading);

  if (pressureReading < noPressure) {
    Serial.println(" - No pressure");
  } else if (pressureReading < lightPressure) {
    Serial.println(" - Light Pressure");
  } else if (pressureReading < mediumPressure) {
    Serial.println(" - Medium Pressure");
  } else {
    Serial.println(" - High Pressure");
  }
  delay(1000);
}

Slave Codes:

#include <Servo.h>

// Include Arduino library for I2C
#include <Wire.h>

// Define Slave I2C Address
#define SLAVE_ADDR 9

// Define Slave answer size
#define ANSWERSIZE 5

Servo servo;
int trig = 8;
int echo = 9;
int duration;
float distance;
float meter;
int buzz = 10;

union
{
   float x;                     //x will be replace by distance
   byte myData[4];
}data;

void setup()
{

  Wire.begin(SLAVE_ADDR); //(4) // Join I2C bus with address #4
  //Wire.onReceive(receiveEvent); // register event
  Wire.onRequest(sendEvent);

  // Setup Serial Monitor
  Serial.begin(9600);

  servo.attach(6);
  pinMode(trig, OUTPUT);
  digitalWrite(trig, LOW);
  delayMicroseconds(2);
  pinMode(echo, INPUT);
  delay(6000);
  pinMode(buzz, OUTPUT); // Buzzer is the digital one.
  Serial.println("Distance:");
}

void loop()
{
  // Time delay in loop
  delay(50);

  int i = 20; // This can be set to any value to change the frequency.
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  duration = pulseIn(echo, HIGH);
  distance = duration / 58;
  data.x = distance;
  Serial.print(distance);
  Serial.print("cm");
  Serial.print("\n"); // This is required to calculate the distance in centimeters.

  if (distance <= 30 && distance >= 1) // The buzzer will start buzzing if the distance is between 1 to 30cm.
  {
    i = distance * i; // This is the main algorithm.
    digitalWrite(buzz, HIGH);
    delay(i); // So the delay between switching will change according to the distance.
    digitalWrite(buzz, LOW);
    delay(i);
  }

}

void sendEvent()//receiveEvent(int howMany)
{
   Wire.write(data.myData, sizeof(data.myData));//float distance goes to Master as 32-bit binary32 data
  /*
  while (1 < Wire.available()) // Loop through all but the last
  {
    float distance = Wire.read(); // Receive byte as a character
    Serial.print(distance); // Print the distance values
  }
  int x = Wire.read(); // Receive byte as an integer
  Serial.println(x);

  delay(10); */
}

Thank you, brother! It is working now.

Thank you Pert and Mustafa.