Trouble reading from a slave device(Mega) using a master device (Uno)

Hey,

So my team and I are trying to implement a project that requires inter-communication between two Arduinos, an Uno and a Mega. In our situation, the Uno is the master device and the Mega is the slave. We have established one-way communication from the Uno (master) to the Mega (slave), however we are having trouble implementing data transfer in the opposite direction.

I am not sure whether that is due to a lack of proper coding on our part, or a misunderstanding of the way I2C works between two Arduinos. Let me explain the general gist of the project.

We are trying to build an automated deli meat slicer, where the Uno serves as the interface taking input from the user. This information is then relayed to the Mega, which causes stepper motors to move around and do their job. Like I already mentioned, the Uno to Mega data transfer works fine. The libraries we are using are the Keypad, Key, Adafruit RBG LCD and Wire libraries on the Uno and the AccelStepper, Wire and Adafruit MotorShield libraries on the Mega.

Before I begin, I need to mention that the Uno is set up as device #9 and the Mega is device #8.

I am providing some of the code below, and I will try to provide only relevant sections.

Below is the code for the Uno. While waiting for the reset button to be pressed on the keypad, the request is made to slave device#8, which is the Mega.

// Press the # key to reset the LCD to the home screen.
  reset =  keypad.waitForKey(); // The program will remain frozen here until a key is pressed.
  while(reset !=  '#'){   // If the user did not press the # key:
    //Code to check if Mega is done slicing
    Wire.requestFrom(8, 1);
  
    while(Wire.available()) {
      Serial.println("Receiving data");
      char val = Wire.read();
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Done");
      if(val == "K") {
        loop(); // Code goes back to top, waiting for any key-press to wake up machine.
      }
    }
    reset =  keypad.waitForKey(); // Loop forever until user presses the # key.
  }

Below is the code for the Mega.

if(return_value == 1) {
    stepper1.runToNewPosition(0);
    stepper2.runToNewPosition(0);
    meat = 0; //changing the input here to prevent loop function from running indef
    Wire.onRequest(requestEvent);
  }
}

void requestEvent() {
  Wire.write("K");
}

So, basically what we are trying to do is, while waiting for a key to be pressed on the Uno, a request for 1 byte of data is repeatedly sent to the Mega from within a while loop. After a certain event has occurred on the Mega, it will acknowledge that request and respond to it. So why is this not working?

Note: I am attaching the complete files for both the Uno and the Mega to this thread in case anyone wants to have a look at them.

senior_design_slicer.ino (6.38 KB)

Interface.ino (8.29 KB)

The Adafruit RGB LCD shield is controlled by I2C, and the Arduino is the master in this connection. By calling Wire.begin(9) you're setting the Arduino into slave mode but this one is the master. Change that to

Wire.begin();

Then Wire.write() transmits exactly one Byte into the I2C transmission buffer. It doesn't accept strings (character arrays) as input but will convert the array pointer into a single byte which is probably not what you expected.
Change that code to transfer single bytes.

You seem to misunderstand the way I2C works. It's a master/slave bus and not a serial point-to-point connection as the UART. The master can write bytes to a slave or it can request bytes from a slave. If it requests bytes from the slave, the slave have to answer immediately because the clock signal for the response is provided by the master. So the master is not asking the slave for an information and the slave responds when it's ready to do so.
Although there is a theoretical possibility for the slave to block the complete bus if it needs some additional time to provide the answer (that time is usually in the microseconds) this functionality is not implemented in the Arduino Wire library.

That's why Wire.onRequest() or Wire.onReceive() are usually called in the setup() routine, otherwise the master cannot request information at any time.

As I already stated, I2C is not a serial communication channel as UART is but a serial bus to usually connect sensors to a microcontroller. An Arduino can act like such a sensor but the restrictions of the bus still apply.