Question on I2C communication

Hi all,

I'm very new to I2C communications between 2 Arduinos.
Currently, my setup consists of 2 Arduino Unos, each of Arduino Uno contains its own set of sensors (e.g. IR sensors, force-resistive sensor, ultrasonic ranger and SHT31-temperature sensor)

I have not written the source code yet but I intend to connect the 2 Arduinos through the I2C channel. However, my SHT31 sensor also utilizes the I2C channel.

Questions:

  1. Will I still be able to read my SHT31 via the I2C channel while connecting both Arduinos together?
  2. Can my Master Arduino be used to as a Slave Arduino to read its own set of sensors?

Really appreciate all the knowledge from the community!

  1. Will I still be able to read my SHT31 via the I2C channel while connecting both Arduinos together?

Assuming that they are connected correctly, yes. Each I2C device has an address that must be unique so that data can be received/sent from/to it

  1. Can my Master Arduino be used to as a Slave Arduino to read its own set of sensors?

Yes

Thanks UKHeliBob! Needed to know some basic information before working on the setup.
I'll give my current setup a try and will get back if it doesn't work.

Needed to know some basic information before working on the setup.


Figure-1: UNO-1 and UNO-2 are connected as Master and Slave

(1) The PC4 and PC5 lines of MCU turn into TWI (I2C) Bus when the user executes the following instructions. The PC4 line turns into SDA line and the PC5 turns into SCL line. The switch K1 gets closed; switches K2 and K3 get opened. All data communication takes place via the TWI Registers (TWCR, TWSR, and TWDR) and after receiving ACK (acknowledgement) from slave.

#include <Wire.h>
 void loop()
 {
 Wire.begin();
 }

(2) For proper operation of the TWI Bus, the bus lines (SDA, SCL) must be connected to 5V through 2x2.2k/4.7k/10k pull-up resistors.

(3) UNO-1 becomes Master when it initiates data transfer operation which means that UNO-1 is generating SCL pulses. UNO-2 becomes a Slave. As a Slave, UNO-2 must have a 7-bit address known as deviceaddress (slaveAddress). For the present case of Fig-15.1, the slave address of UNO_2 is 0b0110110 (0x36).

(4) It is also possible that UNO-2 might initiate data transfer; in this case, UNO-2 is a Master and UNO-1 is a Slave. In Fig-15.1, the slave address of UNO-1 is 0b0110111 (0x37).

(5) Master can check that the slave is accepting it address (0x36) by executing the following instruction. This is helpful for troubleshooting a malfunctioning/nonfunctioning system.

byte busStatus;
 do
 {
 Wire.beginTransmission(deviceAddess);
 busStatus = Wire.endTransmission();
 }
 While(busStatus !=0x00);
 Serail.printl(busStatus, HEX);  //will show 0x00 if the slave responds to its own address

(6) The Master can send one or more data bytes to the slave by executing the following instructions/commands:

Wire.beginTransmission(deviceAddess);
 Wire.write(0x23); //data byte 0x23
 Wire.write(0x45); //next data byte 
Wire.endTransmission();

(7) Master sends executive command/data (s) to the Slave by executing Wire.write() instruction. The Salve is interrupted, and from the ISR it goes to Wire.onReceive() subroutine (SUR). In the SUR, the received command/data is interpreted and necessary actions are taken, after that, the control goes back to the loop() function.

bbc[/nobbc] Master sends data read command (s) to the Slave by executing Wire.requestFrom() instruction. The Slave is interrupted, and from the ISR it goes to Wire.onRequest() subroutine. In the SUR, the Slave finishes sending data to the Master; after that, the control goes back to loop() function.

(9) For the Master, to receive flag status information/data from the Wire.onReceive() SUR of the Slave, it (Master) has to be configured as Slave as well (my understanding).

(10) Just after sending the Wire.onRequest() command to the Slave, the Master will start polling the FIFO buffer to grasp the data coming from the Wire.onRequest() SUB of the Slave.

(11) In Master UNO-1, let us execute the following instruction.
Wire.requestFrom(0x36, 3); //Slave address (UNO-2) is 0x36; 3-byte data to read from Slave

(12) The instruction of Step-11 is a looping instruction. The Master has sent the deviceAddress (0x36); but it has not yet received ACK pulse (SDA line will be pulled down by the Slave's TWI Logic) from the Slave. We will see later -- when and how the Slave creates the ACK signal.

(13) After receiving the ACK signal, the Master generates required amount of SCL pulses to collect 3-byte data from the data buffer of the Slave.

(14) After receiving the deviceaddress (0x36), the Slave is interrupted; it goes to ISR, and from the ISR it goes to Wire.onRequest() subroutine. (The Slave has not yet generated the ACK signal by pulling down the SDA line.) In the SUR, the Slave executes the following instruction to fill up data buffer

void sendEvent()
{
     Wire.write(0x12);
     Wire.write(0x34);
     Wire.write(0x56);
}

(15) After executing the above SUR, the Slave returns to ISR and then creates the ACK signal by pulling down the SDA line. After that the Slave returns to MLP (Main Line Progrom) -- the loop() function.

(16) The Master has now received the ACK signal while it is still within the Wire.requestFrom() loop instruction. Now, the Master generates SCL pulses as required to collects 3-byte data from the Slave. The data are automatically stored in the 32-byte wide FIFO buffer.

(17) The following codes have been added after the Wire.requestFrom() command of the UNO-1 (Master Side).

byte x1 = Wire.read();
Serial.prinrln(x1, HEX);   //Serial Monitor shows: 12

byte x2 = Wire.read();
Serial.prinrln(x2, HEX);   //Serial Monitor shows: 34

byte x3 = Wire.read();
Serial.prinrln(x13, HEX);   //Serial Monitor shows: 56

(18) The Serial Monitor shows:

12
34
56

(19) The Master has correctly read 3-byte data from the active Slave (UNO-2).

(20) The complete program codes.
//Master Codes:

#include <Wire.h>

volatile bool flag3 = false;

void setup() 
{
  Serial.begin(9600);
  Wire.begin(0x37); //Slave Address of the Master (when the Master will be addressed as slave)

  Wire.onReceive(receiveEvent);
  
  Wire.beginTransmission(0x36);`//slave address is 0x36
  Wire.write(0x01);   //Master sending 0x01 to slave
  Wire.endTransmission();

  while(flag3 == false) //wait until the flag3 is active; 
   ;

  Wire.requestFrom(0x36, 3);   //Master will receive 3-byte data from slave
  byte x1 = Wire.read();
  Serial.println(x1, HEX);  
  
  byte x2 = Wire.read();
  Serial.println(x2, HEX);
  
  byte x3 = Wire.read();
  Serial.println(x3, HEX);

}

void loop() 
{
  
}


void receiveEvent()           //master will come here when it is addressed as slave
{
  sei(); //interrupt is enabled to allow printing on Serial Monitor
  if(Wire.read() == 0x06) //Slave has turned itself into master and has sent 0x06
  {
    flag3 = true;
  }
}

//Slave Codes:

#include<Wire.h>

void setup()
{
   Wire.begin(0x36);    //address as a slave
   Serial.begin(9600);
 
 Wire.onReceive(receiveEvent);
   Wire.onRequest(sendEvent);
  
}

void loop()
{
 
}

void receiveEvent(int howmany)
{
    sei();
    if(Wire.read() == 0x01)  //Command/data expected to receive from Master
    {
      //--SEND ack (0X06)—to Master
      Wire.beginTransmission(0x50);
      Wire.write(0x06);       //ACK Send 
      Wire.endTransmission();   
   }
}

void sendEvent(int howmany)
{
 Wire.write(0x12);
   Wire.write(0x34);
   Wire.write(0x56);  
}