3

I am currently trying to communicate between 3 Arduinos using I2C. One of them acts as a master, while the rest act as slaves.

I can request data correctly from the master. But if I were to do 2 consecutive requests, I will only get data for the last request. Please assist.

Master:

#include <Wire.h>

#define BLUNO_SLAVE 0x09
#define BLUNO_SLAVE_2 0X0A

void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initialized as Master");
  Serial.println("Reading from slave 1 now..");
  //Wire.beginTransmission(BLUNO_SLAVE);
  Wire.requestFrom(BLUNO_SLAVE, 25);  //char occupy 1 byte
  //Wire.endTransmission();
  Serial.println("Reading from slave 2 now..");
  Wire.requestFrom(BLUNO_SLAVE_2, 30);
}

void loop () {
  while(Wire.available()) {
    char c = Wire.read();
    Serial.print(c);
  }
}

Slave 1:

#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin(0x09);  //slave address
  Serial.println("Serials initialized");
}

void loop() {
  Wire.onRequest(returnData);
}

void returnData() {
  Wire.write("received master's request");
}

Slave 2:

#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin(0x0A);  //slave address
  Serial.println("initialized!");
}

void loop() {
  Wire.onRequest(returnData);
}

void returnData() {
  delay(60000);  //60 * 1000 = 60 seconds
  Wire.write("Lat: 103.123456, Lon: 1.098765");
}

Output on the master:

Initialized as Master
Reading from slave 1 now..
Reading from slave 2 now..
Lat: 103.123456, Lon: 1.098765

On top of that, I do not understand why the 1 minute delay was not executed before the slaves write the GPS coordinates.

I figured out from http://playground.arduino.cc/Main/WireLibraryDetailedReference that each call to the requestFrom() method, RESETS the read buffer. I looked at my code back and I saw a silly mistake on the master code. So, I corrected the master code:

#include <Wire.h>

#define BLUNO_SLAVE 0x09
#define BLUNO_SLAVE_2 0X0A

void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initialized as Master");
  Serial.print("Slave 1: ");
  Wire.requestFrom(BLUNO_SLAVE, 25);  //char occupy 1 byte
  readData();
  //each call to requestFrom, RESETs the read buffer index
  Serial.println();
  Serial.print("Slave 2: ");
  Wire.requestFrom(BLUNO_SLAVE_2, 30);
  readData();
}

void loop () {
}

void readData () {
  while(Wire.available()) {
  char c = Wire.read();
  Serial.print(c);
 }
}

But still, I don't understand why slave2 writes the data immediately instead of waiting for 1 minute?

  • Using delay inside an interrupt routine isn't adviced. Try using delayMicroseconds(60000000). Also from reading the documentation, you only need to call Wire.onRequest(returnData); once, so you should move that to the setup routine. – Gerben Jul 29 '14 at 10:13
  • @Gerben When I implement delayMicroseconds(60000000), it just hangs there. It does not write to the master at all. Even if I changed it to just delayMicroseconds(10), it does not write to the master. – Syah Jul 30 '14 at 1:26
  • Slave also cannot execute any codes inside a for loop. – Syah Jul 30 '14 at 2:01
  • I'm not sure I2C even allows extended pauses during communication. Maybe it just times-out. – Gerben Jul 30 '14 at 11:49
2

I recommend you to just set a semaphore inside your handler. When your handler is called, set it, nothing more. In your main loop, poll for this semaphore and do your communication when true. When you receive this semaphore you can easily wait as long as you like without breaking interrupt handling. As interrupt service routines should always be as short as possible, both in terms of time and code, it is generally a bad idea to do complex communication from within or wait for something.

And don't forget the "volatile" keyword for your semaphore.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.