Using OnRequest for communication

I am trying to communicate between 2 Arduinos using i2c. I am trying to take in input from user through the slave, then send it to the master. For this purpose I am specifically trying to use Wire.onRequest() and Wire.requestFrom(). I am aware that there other ways to implement this. But I am curious if it could be done this way.

Master Code:

#include <Wire.h>


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

void loop()
{
 Wire.beginTransmission(4); 
  Wire.requestFrom(4,5);
  if(Wire.available()>0){
    int i = Wire.read();
    Serial.print(i);}
  else Serial.print("empty");
  Wire.endTransmission();   
  }

Slave Code:

#include <Wire.h>
void setup()
{
  
  Wire.begin(4);                
  Wire.onRequest(handler);
  Serial.begin(9600);

}

void loop()
{
  delay(100);
}

void handler(){
  if(Serial.available()>0){
  int i = Serial.read();
  Serial.print(i);
  Wire.write(i);}}

What I expect is that when there is no input from the user, the requestFrom() function should do nothing but instead, I continuously get zeros printed.

I am curious if what I am trying to implement is possible. If yes, what I am doing wrong?

When a Master requests data from a Slave, the Slave can not stop that halfway neither can the Slave add extra bytes.
The Master does not know how much valid data the Slave has send.
The first byte returned by the Slave could be the number of valid data bytes. Suppose there are up to 8 valid data bytes, and the first byte is the amount, then the Master should always request 9 bytes and simply ignore the bytes that are not valid.

The way you use the Wire library is not okay. See my alternative explanation.
The Wire.requestFrom() does everything on its own. It does not need the Wire.beginTransmission() or Wire.endTransmission().

The onRequest handler runs in a interrupt. The Serial library also uses interrupts. It even might work sometimes ! but it is bound to go wrong. So please don't use any Serial functions in the onRequest handler.

Are you sure that you want to use the I2C bus between Arduino boards ? Did you connect the GNDs ?
I wrote this page to scare new users: How to make a reliable I2C bus.

@OP
You may exercise the following tutorial to see how a fixed-length (9 characters) string collected from the InputBox of Slave could be sent to Master using I2C Bus.

1. Build the following set up (Fig-1) between Master-UNO and Slave-NANO using I2C Bus; where, the Slave is assigned the address 0x08 as 0x00 - 0x07 addresses are reserved addresses.

i2cmsunonano.png
Figure-1:

2. Collect the Newline terminated string "Hello UNO" from the InputBox of Serial Monitor of Slave (SM2, Fig-2). Select "Newline" option for the 'Line ending tab" of SM2.


Figure-2:

3. When Slave has finished the collection of the string of Step-2, it interrupts the Master to get this string from Slave and then show on SM1.

4. Upload the following sketches in Master-UNO and Slave-NANO.
Master Codes:

#include<Wire.h>
volatile bool flag = false;
char myString[20]; //to hod string coming from  Slave

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), ISRINT0, LOW);
  Wire.beginTransmission(0x08);
  byte busStatus = Wire.endTransmission();
  if (busStatus != 0)
  {
    Serial.println("Slave is not found...!");
    while (1);
  }
  Serial.println("Salve is found.");
  noInterrupts();
  delay(1000);
  interrupts();
}

void loop()
{
  if (flag == true)
  {
    byte m = Wire.requestFrom(0x08, 9);  //request for 9 charcaters
    for (int i = 0; i < m; i++)
    {
      myString[i] = Wire.read();
    }
    myString[m] = '\0';

    //------------------------------------------
    Serial.println(myString);
    flag = false;
  }
}

void ISRINT0()
{
  flag = true;
}

Slave Codes:

#include<Wire.h>
char myString[20];
int i = 0;   //array pointer

void setup()
{
  Serial.begin(9600);
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);
  Wire.begin(0x08);   //Slave address: 0x08
  Wire.onRequest(sendEvent);  //ISR declaration
}

void loop()
{
  byte y = Serial.available();//if a charcater has arrived
  if (y != 0)
  {
    char z = Serial.read();
    if (z != '\n')
    {
      myString[i] = z;
      i++;
    }
    else
    {
      myString[i] = '\0';
      Serial.println(myString);  //show string on SM1
      i = 0;
      //------------------------------------------------------
      Wire.print(myString); //Send string to Master over I2C bus
      //-------------------------------------------------------
      digitalWrite(4, LOW); //interrupt Master
      delayMicroseconds(100);
      digitalWrite(4, HIGH);
      //------------------------------------------------------
    }
  }
}
void sendEvent()
{
  Wire.print(myString); //sendin the string to master via I2C Bus
  memset(myString, 0x00, 20);   //array reset
}

5. Bring in SM1 and SM2.
6. Press down RESET buttons of both Master and Slave.
7. Release RESET button of Master.
8. Release RESET button of Slave.
9. Check that SM1 shows the message: Slave is found.
10. Enter Hello UNO in the InputBox of SM2 and then click on Sendd button.
11. Check that the message "Hello UNO" has appeared on SM1 and SM2.
12. Master Serial Monitor


Figure-3:

i2cmsunonano.png

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.