Talking to multiple I2C devices in sequence

Hello,

I am trying to communicate with 3 arduino UNO boards connected to each other via I2C bus. My setup is as follows:

  1. Master has an OLED.
  2. Slave 1 has a fingerprint device and a bluetooth connected to it.
  3. Slave 2 has a wifi module connected to it.

I am successfully communicating with the Master and Slave 1 back and forth via I2c bus. I need to communicate with Slave 2 after i finished communicating with the Slave 1.

Slave 1 has an address 3 and slave 2 has an address 2.

I am able to talk to the slaves using Wire.begin(2) and Wire.begin(3) separately. I want to implement both in the same file. First Wire.begin(3) gets executed and then it talks with slave 1(which i am successful), then after that i wrote Wire.beginTransmission(2) and wrote data to slave 2. But that data is not received on the slave side when i try to read it. I gives me a y with 2 dots which is empty data.

I have tried the following:

  1. This is my master UNO code
void setup()
{
//Finger print code here
  Wire.begin(3);                                    //Slave 1
  Wire.onRequest(requestEvent);              //This is for communicating with slave 1
  Wire.onReceive(receiveEvent);             ////This is for communicating with slave 1

  delay(40000);                                  
  Serial.println("Channel 2..................");
  Wire.beginTransmission(2);                     //talking to slave 2    -- i also tried Wire.begin(2)
  Wire.write("w");                                     //writing to slave 2
  Wire.endTransmission();                          //ending the transmission
}

When i used Wire.begin(2) after Wire.begin(3) the wire.begin(3) doesn't work, it's like the last wire.begin executes. I introduced a delay so that my wire.begin(3) executes first and then i can move on to my slave 2. But it didn't work either.

I need to send commands to my second I2C device after i finished talking with first device. The master must change the wire.begin(3) to wire.begin(2). I am not sure where to call that change.

Any help?

dheerajdake:
Hello,

I am trying to communicate with 3 arduino UNO boards connected to each other via I2C bus. My setup is as follows:

  1. Master has an OLED.
  2. Slave 1 has a fingerprint device and a bluetooth connected to it.
  3. Slave 2 has a wifi module connected to it.

I am successfully communicating with the Master and Slave 1 back and forth via I2c bus. I need to communicate with Slave 2 after i finished communicating with the Slave 1.

Slave 1 has an address 3 and slave 2 has an address 2.

I am able to talk to the slaves using Wire.begin(2) and Wire.begin(3) separately. I want to implement both in the same file. First Wire.begin(3) gets executed and then it talks with slave 1(which i am successful), then after that i wrote Wire.beginTransmission(2) and wrote data to slave 2. But that data is not received on the slave side when i try to read it. I gives me a y with 2 dots which is empty data.

I need to send commands to my second I2C device after i finished talking with first device. The master must change the wire.begin(3) to wire.begin(2). I am not sure where to call that change.

Any help?

No, your code is not correct. Here is a simple master code:

// I2C Master Code

#include <Wire.h>

#define FIRSTSLAVE 0x10   // first Slave I2C address
#define LASTSLAVE 0x15    // Last Slave I2C address  (0x15-0x10)+1 = 6 slaves

void setup(){
Serial.begin(9600); // debug monitor 
Wire.begin(); // no number!  passing a value to Wire.begin() assigns this Arduino as a SLAVE I2C device.

}

static uint8_t slave=FIRSTSLAVE-1;  // initialize to first Slave I2C address

void loop(){
slave++; // increment to first slave
if(slave>LASTSLAVE) {
  slave=FIRSTSLAVE;  // start over at the beginning
  delay(10000); //Delay so I can read the Serial monitor
  }
uint8_t err;
Wire.beginTransmission(slave);
Wire.write((uint8_t)0); // some commands bytes that make sense for your program ...
Wire.write((uint8_t)1);
Wire.write((uint8_t)2);
Wire.write((uint8_t)3);
Wire.write((uint8_t)slave); // just because I want to verify the correct slave actually received it
err=Wire.endTransmission();
char ch[50];
if(err){ // if error is not zero
  sprintf(ch,"\nSendid to Slave 0x%02x failed, error= %d",slave,err);
  Serial.print(ch);
  }
else { // slave accepted write, now lets see if I can get the info Back!
  err=Wire.requestFrom(slave,6);
  sprintf(ch,"\nRequest from Slave 0x%02X ",slave);
  Serial.print(ch); 
  bool failed = false;
  if(err==6){ // requestFrom will return the number of RequestBytes or Zero
    uint8_t i = 0,b;
    uint16_t tWord=0;
    while(Wire.available()){
      b=Wire.read();
      switch(i){ // use a case statement to figure out where to store the byte
       case 0 : 
         if(b!=0){ // first byte is Wrong!
            Serial.print("bad First Byte ");
            failed = true;
         }
         break;
       case 1 :
         if(b!=1){ // Second byte is Wrong!
            Serial.print("bad Second Byte ");
            failed = true;
         }
         break;
       case 2 :      
         tWord = b;
         break;
       case 3 :
         tWord = tWord | (uint16_t)b<<8; // build a word (16bit) from two bytes
         if(tWord!=770) {
           Serial.print(" Bad Word Value ");
           failed = true;
           }
         break;
       case 4 : 
         if(b!=slave){
           Serial.print("bad Echo Slave ID ");
           failed = true;
           } 
         break;
       case 5 :
         if(b!=slave){
           Serial.print("Bad Slave ID ");
           failed = true;
           }
       default : ; // ignore any bytes past the fifth one.
       }// case
     i++;
     }// while
    }// if
  else failed = true; // RequestFrom returned 0, marking a failure!
  if(failed) Serial.println(" Failed!");
  else Serial.println(" Succeeded!");  
  }
}

And the Matching slave code:

#include <Wire.h>

#define SLAVEID 0x10  // this is the value that must change for each slave!

struct MYSTRUCT{
   uint8_t firstByte;
   uint8_t secondByte;
   uint16_t aWord;
   char c;
   uint8_t slaveI2Caddr;  // a sneeky sixth byte that you have to ask for
};

volatile MYSTRUCT m; // volatile because it will be accessed during an interrupt.
volatile bool receiveFlag=false;
volatile bool requestFlag = false;
volatile uint8_t receiveCnt;


void onRequestEvent(){ // This function is call when the Master uses requestFrom().
// only ONE (1) Wire.write() call can be used
//but I want to send upto 6 bytes back irrespective of how many bytes the master actually reads?

Wire.write((uint8_t*)&m,6); // fake the compiler into thinking m is a pointer to a byte array
requestFlag = true; // I want to send a message out the serial port but Interrupt routines
// need to be really fast, and not call any library calls, so I set a flag and process it in the LOOP()
}

void onReceiveEvent(int howMany){ // this function is call when the Master Sends Data
uint8_t i=0,b; // 
while(Wire.available()){
   b= Wire.read();
   switch(i){ // use a case statement to figure out where to store the byte
    case 0 :
      m.firstByte = b;
      break;
    case 1 : 
      m.secondByte = b;
      break;
    case 2 :      
      m.aWord = b;
      break;
    case 3 :
      m.aWord = m.aWord | (uint16_t)b<<8; // build a word (16bit) from two bytes
      break;
    case 4 : 
      m.c = b;
      break;
    default : ; // ignore any bytes past the fifth one.
    }// case
  i++;
  }// Wire.avail()
if(!receiveFlag){
  receiveFlag = true;
  receiveCnt = i;
  }
}

void setup(){
Serial.begin(9600); // for debug monitor
Wire.begin(SLAVEID);
Wire.onReceive(onReceiveEvent);
Wire.onRequest(onRequestEvent);
m.slaveI2Caddr = SLAVEID;
}

void loop(){
if(receiveFlag){
  Serial.print(" R=");
  Serial.print(receiveCnt,DEC);
  receiveFlag = false; // clear 

  }
if(requestFlag){
  requestFlag = false;
  Serial.print(" T");
  }
}

Chuck.