Test for i2c devices

I am using three Arduino mega 2560 units - one as a master and the other two as slaves via the SDA/SCL two wire system.

I am trying to test, during the setup phase, to make sure that each slave is connected and turned on.
However, the Wire.beginTransmission() …Wire.endTransmission() just hangs if any slave unit is not turned on.
Here’s my humble attempt for the master unit:

#include <Wire.h>
int PButtons[]= {3,4,5,6};
byte whatsent = 0;
bool slave1Online = false;
bool slave2Online = false;

void setup(){
  Wire.begin();                    // join i2c bus as master
  Serial.begin(9600);           // start serial for output
  for (int i=0; i<4; i++){
  pinMode (PButtons[i], INPUT_PULLUP);
  }
  // check for slaves present
  Wire.beginTransmission(1);
  if (Wire.endTransmission() ==0){
    slave1Online = true;
    Serial.print("Hello slave 1");
  }else {Serial.print("slave 1 absent");
}
  Wire.beginTransmission(2);
  if (Wire.endTransmission() ==0){
    slave1Online = true;
    Serial.print("Hello slave 2");
  }else {Serial.print("slave 2 absent");
}
}

void loop(){
  for (int x=0; x<4; x++){
    int reading = digitalRead(PButtons[x]);
    delay(75);
    reading - digitalRead(PButtons[x]);
    if (reading ==LOW){
    sendtoSlave(PButtons[x]);
    } 
  }
}

void sendtoSlave(int buttonID){
    Serial.print(buttonID);
    Serial.print(" Pressed");
    if (buttonID ==3 or buttonID ==4){
    if(slave1Online ==true){
    contactSlave(1, buttonID);
    Serial.println("Slave 1");
    }
   }
    if (buttonID ==5 or buttonID ==6){
    if (slave2Online == true){
    contactSlave(2, buttonID);
    Serial.println("Slave 2");
    }
    }
}

void contactSlave(int slaveID, int buttonnumber){
  Wire.beginTransmission(slaveID);
  Wire.write(buttonnumber);
  Wire.endTransmission();
}

I have searched the internet and looked at the i2c scanner code, but that runs in the loop section. I was hoping to just do the test once after turn on.

I hope someone out there who has more programming expertise than me can suggest something.

Do you have pull-up resistors on the I2C pins of your master?

It looks like this is sufficient to 'scan' a single address:

    Wire.beginTransmission(address);
    error = Wire.endTransmission();

If 'error' gets set to 0 then a device acknowledged the address.

johnhb:
However, the Wire.beginTransmission() ..Wire.endTransmission() just hangs if any slave unit is not turned on.

Can't do that.

Every device on the bus must be powered, otherwise it will drag the I2C pins down to a pin-protection diode drop (0.7volt).

A Mega already has 10k pull up resistors build-in.
Leo..

Wawa:
Can't do that.

Every device on the bus must be powered, otherwise it will drag the I2C pins down to a pin-protection diode drop (0.7volt).

Not universally true. Many devices can be powered down and safely not interfere with the i2c bus.

A Mega already has 10k pull up resistors build-in.

No. They have something more like 50k but is can vary widely. It is not a strong pull-up which is usually okay for most input applications, but can be an issue with i2c.

blh64:
Not universally true.

Surprised if it didn't with a Mega, which uses normal digital pins for I2C instead of open collector outputs.

blh64:
No. They have something more like 50k but is can vary widely.

The Uno/Nano uses internal/software pull up, but the Mega has physical 10k pull up resistors.
Look at the schematic (the quad-resistor array near pin 20,21).
Leo..

johnhb:
That seems a very unworkable arrangement given that any electronic device can fail often at the most inconvenient time.

So if I2C is 'unworkable' because if one device fails the whole I2C bus can fail, why do so many systems use it ?

johnhb:
Does that means that if one i2c device fails the whole communication link fails also? That seems a very unworkable arrangement given that any electronic device can fail often at the most inconvenient time.

Define 'failing'. Forgetting to turn the power on?

johnhb:
Sorry to be single minded but is there a way to test if an i2c device is attached and turned on.

You can test for attached, but AFAIK not for turned on. At least not without extra hardware.

Why the three Megas anyway.
Thinking you need multiple Arduinos is usually a beginner's mistake.
"More pins" is usually solved with port expanders, not with more processors.
Leo..

The I2C scanner software works for me, tells me the addresses in use on the bus.

Wawa:
The Uno/Nano uses internal/software pull up, but the Mega has physical 10k pull up resistors.
Look at the schematic (the quad-resistor array near pin 20,21).
Leo..

Thanks! I stand corrected. I did not know they had those on the Mega.

Aren't you going to power them all on, when the system is running? Then, it hardly matters that it won't work with some devices powered down. Why is it a show stopper? You could even arrange for them to all share a power source if you're really worried about that.

Servos are best controlled with a PCA9685 breakout board. Up to 16 servos per board.
Hardware servo control also frees up processor time of the Arduino.
PCA9685 boards can be daisy-chained, using the same two I2C pins of the Arduino.
Those boards can also drive LEDs, but there are also other solutions for the LEDs.

Buttons can be read with a port expander, 16 buttons per expander.
Can use the same two I2C pins of the Arduino.
If the buttons are matrixed, 10 pins are needed for 25 buttons.
Then one Mega can do it all.
Leo..

Software driven LEDs are actually a good plan for model railroad signals. I take advantage of software abilities to do gamma correction, brightness calibration (so different colour LEDs can use the same value limiting resistor), and simulating tungsten lamp thermal response (fade in/out).

johnhb:
I am sorry I started this post; seems to have generated some disagreements.

Get over it.
Arguing is a good way to learn new things :slight_smile:
Leo..

Do not detach/re-attach() the servo for starters.

As a better approach, your receiveEvent() function is called without an interrupt so only do the minimal actions required. Read the value. Store it in a global variable. Set a flag that some action is required

Within loop(), check the flag and if action is required, do all the LED flashing/motor moving and then reset the flag.

Repeat.