I2C Help

Hello people,

I am in need of some serious programming help for my project. In essence, what I want to do is simple enough, yet I can't figure out where I'm going wrong. Also, if you can tell me a more efficient way of achieving what I ultimately want, I would be over the moon.

Anyway, simply put, I've got a few LDRs connected to a slave and I want to send the analog reading to the master. Then the master will use the readings to execute a few "if" commands using the data gathered by the slave. Simple enough right?

Well the problem is I'm having trouble figuring out how to send more than one analog reading successfully. I can send one analog reading no problem, but any additional analog reading reads as 0. Also, I should note that I would like more than one slave to send LDR readings to the master.

This is my current attempt:

Slave #2

int photocellPin0 = 0;     // the cell and 10K pulldown are connected to a0
int photocellReading0;     // the analog reading from the analog resistor divider
int photocellPin1 = 1;     // the cell and 10K pulldown are connected to a1
int photocellReading1;     // the analog reading from the analog resistor divider
int photocellPin2 = 2;     // the cell and 10K pulldown are connected to a2
int photocellReading2;     // the analog reading from the analog resistor divider
int photocellPin3 = 3;     // the cell and 10K pulldown are connected to a3
int photocellReading3;     // the analog reading from the analog resistor divider

#include <Wire.h>

void setup()
{
  Serial.begin(9600);
  Wire.begin(2);                // join i2c bus with address #2
  Wire.onRequest(requestEvent); // register event
}

void loop() {
  photocellReading0 = analogRead(photocellPin0);
  photocellReading1 = analogRead(photocellPin1);
  photocellReading2 = analogRead(photocellPin2);
  photocellReading3 = analogRead(photocellPin3);

  Serial.print("Analog reading0 = ");
  Serial.println(photocellReading0);     // the raw analog reading   
  Serial.print("Analog reading1 = ");
  Serial.println(photocellReading1);     // the raw analog reading
  Serial.print("Analog reading2 = ");
  Serial.println(photocellReading2);     // the raw analog reading
  Serial.print("Analog reading3 = ");
  Serial.println(photocellReading3);     // the raw analog reading

  delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  Wire.send(photocellReading0);
  Wire.send(photocellReading1);
  Wire.send(photocellReading2);
  Wire.send(photocellReading3);
}

Master

#include <Wire.h>

void setup()
{
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop()
{
  Wire.requestFrom(2, 1);    // request 6 bytes from slave device #2

  while(Wire.available())    // slave may send less than requested
  { 
    int photocellReading0 = Wire.receive(); // receive a byte as character
    Serial.println(photocellReading0);         // print the character
  }
  int photocellReading1 = Wire.receive();
  Serial.println(photocellReading1);
  
  delay(100);
}

Please let me know how to solve my issue. Any help is much appreciated.

Thank you soo much!
Ryan

Moderator edit: Quote boxes swapped to code boxes. AWOL

  Wire.requestFrom(2, 1);    // request 6 bytes from slave device #2

You sent 8 bytes from the slave. Yet you are asking for 1, regardless of what the comment says. Why am I not surprised that you don't get multiple values?

    int photocellReading0 = Wire.receive(); // receive a byte as character

And store that one byte in an int, and pretend that you got both bytes. How's that working out?

  while(Wire.available())    // slave may send less than requested
  {
    int photocellReading0 = Wire.receive(); // receive a byte as character
    Serial.println(photocellReading0);         // print the character
  }
  int photocellReading1 = Wire.receive();

While there is any data available, read it incorrectly, storing it in a local variable that goes out of scope as soon as the while loop ends. As soon as there is no more data to read, read another byte, pretend that it represents both bytes of an int.

There is more wrong with the receiver code than is right, I'm afraid.

Thanks for the response Paul. Much appreciated.

However, are you able to elaborate your response please. Obviously, you can tell that I am by no means any good at this programming stuff so I'm having a bit of problem understanding your explanations. I have been trying to learn the Arduino language slowly, but due to delays in fabrication of my circuit, I am left with a lot less time than anticipated. So I'm really just trying to follow the wire examples and going from there, but those examples are a lot more simpler. So this is why my coding is pretty much a patch job.

Btw, I understand how ridiculous the "int photocellReading0 = Wire.receive();" coding is. What would be a better way of sending and receiving all of the readings? Is it possible to put it in a matrix or table or something?

Thanks for the responses,
Ryan

Can you amend the subject line please? It's I2C not 2ic (2ic means "2nd in charge").

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  Wire.send(photocellReading0);
  Wire.send(photocellReading1);
  Wire.send(photocellReading2);
  Wire.send(photocellReading3);
}

It may not be clearly documented but in a requestEvent you can only successfully do a single Wire.send. You need to do something like:

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  int buf [4] = { photocellReading0, photocellReading1, photocellReading2, photocellReading3 };

  Wire.send (buf, sizeof buf);
}

Bear in mind this is sending 8 bytes (4 integers).

More information and examples at:

Thanks for the help and link Nick. They've been very helpful in giving me more examples to study from. Also, I have just realised that the code I posted at the start is all over the place. I'm sorry but I made this post after 5 hours of constant struggling and stress trying to get the coding right, so I may have posted my 'last ditch effort' code rather than my working one.

As with the code that you gave me, I keep getting an error. It keeps telling me that the 'sizeof buf' part is unsigned int, even though I have written my code as you specified.

Also, do you by any chance have an example of a master receiving data from multiple slaves? Do I need to specify the slaves it receives from or will it just loop through all the slaves for data? Also, will it save this data before the next run of transmission, or will it overwrite the data from, lets say, slave 2 with data from slave 3? Sorry if that last part doesn't make sense. I just need the master to be able to use the data from slave 2 and 3 at the same time.

Once again, thank you for your time and help.
Ryan

As with the code that you gave me, I keep getting an error. It keeps telling me that the 'sizeof buf' part is unsigned int, even though I have written my code as you specified.

Show YOUR code and the EXACT error message.

mjscar:
As with the code that you gave me, I keep getting an error. It keeps telling me that the 'sizeof buf' part is unsigned int, even though I have written my code as you specified.

When I say "something like" that is code for "I haven't tested this" .

I left out a typecast, this compiles:

void requestEvent()
{
  int buf [4] = { photocellReading0, photocellReading1, photocellReading2, photocellReading3 };

  Wire.send ((byte *) buf,  sizeof buf);
}

mjscar:
Also, do you by any chance have an example of a master receiving data from multiple slaves? Do I need to specify the slaves it receives from or will it just loop through all the slaves for data?

There is only the one pair of wires, they can't all be sending at once. You need to address each slave individually.

mjscar:
Also, will it save this data before the next run of transmission ...

What is this "it" of which you speak? Your program will save the data if you write it that way.

Ok I think I should start from the top, seeing as my coding is all over the place. This is in essence what I want/need to do

#There's 4 slave arduino, each connected to 4 LDRs.
#The slave simply sends the LDR analog reading to the master.
#The master receives the analog reading from each arduino.
#The master executes a few if commands, such as
if analogreadingslave11 > analogreadingslave 23 // ie the reading from slave1LDR1 is greater than slave2LDR3
.....so and so...

I'm pretty sure it is a relatively simple idea, but I just can't get enough information on how to transfer data between multiple arduinos. I know its possible as I have read people using multiple arduinos to control bigger things, which I would assume are far more complex, but I just can't get access to any of the coding.

Once you get back one reading, surely getting 4 or 40 is just an extension?

eg. (for the master):

#include <Wire.h>

const int SEND_TEMPERATURE = 1;

const int SLAVE1 = 10;  // I2C address
const int SLAVE2 = 11;
const int SLAVE3 = 12;
const int SLAVE4 = 13;

int getReading (const byte slave_address)
  {
  // tell slave to send us the temperature
  Wire.beginTransmission (slave_address);
  Wire.send (SEND_TEMPERATURE);
  if (Wire.endTransmission () != 0)
    return -1;   // slave didn't respond

  // for the results
  int result;
  
  // request result
  if (Wire.requestFrom (slave_address, sizeof result) < sizeof result)
    return -1;  // not enough data or no response

  byte * p = (byte *) &result;
  
  // get each byte
  for (byte i = 0; i < sizeof result; i++)
    *p++ = Wire.receive ();

  return result;    
  }  // end of getReading

void setup () 
  {
  Wire.begin ();
  }  // end of setup

void loop () 
  {
  int result1, result2, result3, result4;
  
  result1 = getReading (SLAVE1);
  result2 = getReading (SLAVE2);
  result3 = getReading (SLAVE3);
  result4 = getReading (SLAVE4);
  
  // warning: a result of -1 means that slave didn't respond, perhaps handle that here

  if (result1 > result2)
    {
      // blah blah  
    }
    
  }  // end of loop

I'm pretty sure it is a relatively simple idea, but I just can't get enough information on how to transfer data between multiple arduinos. I know its possible as I have read people using multiple arduinos to control bigger things, which I would assume are far more complex, but I just can't get access to any of the coding.

That is because you first need to develop and test a serial protocol for the master/slaves to utilize. Only when you have a well behaved multi-drop serial protocol working is it time to work on the tasks the slave have to perform and what the master does with all the data from the slaves. The built in serial library commands offer no support for multi-drop serial, that is something you have to build on top of the basic serial read and write commands.

Lefty

Ok, I've got some outside help on this and this is what we came up with. However, the master is still receiving only 0s. Can you please kindly look over my current coding and see if you can spot the mistakes.

MASTER

int sensorReading00;
int sensorReading01;
int sensorReading02;
int sensorReading03;
int sensorReading10;
int sensorReading11;
int sensorReading12;
int sensorReading13;
int sensorReading20;
int sensorReading21;
int sensorReading22;
int sensorReading23;
int sensorReading30;
int sensorReading31;
int sensorReading32;
int sensorReading33;

#include <Wire.h>

void requestSensor(char address, int* sensor0, int* sensor1, int* sensor2, int* sensor3)
{
  byte data[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 
  Wire.requestFrom(0x30, 16);
 
  byte c = 0;
 
  while (c < 16)
  {
    if (Wire.available())
    {
    data[c] = Wire.receive();
    c++;
    }
  }
 
  *sensor0 = data[0] << 24 + data[1] << 16 + data[2] << 8 + data[3];
  *sensor1 = data[4] << 24 + data[5] << 16 + data[6] << 8 + data[7];
  *sensor2 = data[8] << 24 + data[9] << 16 + data[10] << 8 + data[11];
  *sensor3 = data[12] << 24 + data[13] << 16 + data[14] << 8 + data[15];
}

void setup()
{
  Wire.begin(1);                // join i2c bus with address #4
  Serial.begin(9600);           // start serial for output
}

void loop()
{
  requestSensor(0x30, &sensorReading00, &sensorReading01, &sensorReading02, &sensorReading03);
  requestSensor(0x31, &sensorReading10, &sensorReading11, &sensorReading12, &sensorReading13);
  requestSensor(0x32, &sensorReading20, &sensorReading21, &sensorReading22, &sensorReading23);
  requestSensor(0x33, &sensorReading30, &sensorReading31, &sensorReading32, &sensorReading33);

if ((sensorReading30+sensorReading32)/2 > sensorReading00) {
  noTone(10);   // set the TONE off
} if ((sensorReading30+sensorReading32)/2 > sensorReading02) {
  noTone(10);    // set the TONE off
} if ((sensorReading30+sensorReading32)/2 > sensorReading10) {
  noTone(10);    // set the TONE off
} if ((sensorReading30+sensorReading32)/2 > sensorReading12) {
  noTone(10);    // set the TONE off  
} if ((sensorReading30+sensorReading32)/2 > sensorReading20) {
  noTone(10);    // set the TONE off
} if ((sensorReading30+sensorReading32)/2 > sensorReading22) {
  noTone(10);    // set the TONE off  
} if (sensorReading00-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,200);    // set the TONE on
} if (sensorReading02-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,200);    // set the TONE on
} if (sensorReading10-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,1000);    // set the TONE on
} if (sensorReading12-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,1000);    // set the TONE on
} if (sensorReading20-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,500);    // set the TONE on
} if (sensorReading22-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,500);    // set the TONE on
}
 
  Serial.print("Analog reading00 = ");
  Serial.println(sensorReading00);     // the raw analog reading  
  Serial.print("Analog reading01 = ");
  Serial.println(sensorReading01);     // the raw analog reading
  Serial.print("Analog reading02 = ");
  Serial.println(sensorReading02);     // the raw analog reading
  Serial.print("Analog reading03 = ");
  Serial.println(sensorReading03);     // the raw analog reading
  Serial.print("Analog reading10 = ");
  Serial.println(sensorReading10);     // the raw analog reading  
  Serial.print("Analog reading11 = ");
  Serial.println(sensorReading11);     // the raw analog reading
  Serial.print("Analog reading12 = ");
  Serial.println(sensorReading12);     // the raw analog reading
  Serial.print("Analog reading13 = ");
  Serial.println(sensorReading13);     // the raw analog reading 
  Serial.print("Analog reading20 = ");
  Serial.println(sensorReading20);     // the raw analog reading  
  Serial.print("Analog reading21 = ");
  Serial.println(sensorReading21);     // the raw analog reading
  Serial.print("Analog reading22 = ");
  Serial.println(sensorReading22);     // the raw analog reading
  Serial.print("Analog reading23 = ");
  Serial.println(sensorReading23);     // the raw analog reading
  Serial.print("Analog reading30 = ");
  Serial.println(sensorReading30);     // the raw analog reading  
  Serial.print("Analog reading31 = ");
  Serial.println(sensorReading31);     // the raw analog reading
  Serial.print("Analog reading32 = ");
  Serial.println(sensorReading32);     // the raw analog reading
  Serial.print("Analog reading33 = ");
  Serial.println(sensorReading33);     // the raw analog reading
 
 
  delay(0);
}

SLAVE

int photocellPin0 = 0;     // the cell and 10K pulldown are connected to a0
int photocellReading0;     // the analog reading from the analog resistor divider
int photocellPin1 = 1;     // the cell and 10K pulldown are connected to a1
int photocellReading1;     // the analog reading from the analog resistor divider
int photocellPin2 = 2;     // the cell and 10K pulldown are connected to a2
int photocellReading2;     // the analog reading from the analog resistor divider
int photocellPin3 = 3;     // the cell and 10K pulldown are connected to a3
int photocellReading3;     // the analog reading from the analog resistor divider
 
#include <Wire.h>
 
void requestHandler()
{
  Wire.send(analogRead(photocellPin0));
  Wire.send(analogRead(photocellPin1));
  Wire.send(analogRead(photocellPin2));
  Wire.send(analogRead(photocellPin3));
}
 
void setup()
{
  Wire.begin(0x30); // join i2c bus (address optional for master)
  Serial.begin(9600);
}
 
void loop() {
  photocellReading0 = analogRead(photocellPin0);
  photocellReading1 = analogRead(photocellPin1);
  photocellReading2 = analogRead(photocellPin2);
  photocellReading3 = analogRead(photocellPin3);
 
  Serial.print("Analog reading0 = ");
  Serial.println(photocellReading0);     // the raw analog reading  
  Serial.print("Analog reading1 = ");
  Serial.println(photocellReading1);     // the raw analog reading
  Serial.print("Analog reading2 = ");
  Serial.println(photocellReading2);     // the raw analog reading
  Serial.print("Analog reading3 = ");
  Serial.println(photocellReading3);     // the raw analog reading
 
  delay(0);
}

Appreciate all the help.
Ryan

A peek at the Wire.cpp file might prove useful.

void TwoWire::send(int data)
{
  send((uint8_t)data);
}

What happens when the int output by analogRead() is cast to a byte? Depends on the value, but for 3/4 of the range of values that analogRead can return, the results are not good.

Why does this matter to you? Because of this:

  Wire.send(analogRead(photocellPin0));
  Wire.send(analogRead(photocellPin1));
  Wire.send(analogRead(photocellPin2));
  Wire.send(analogRead(photocellPin3));

This invokes the int version of TwoWire::send().

Since you are (usually) sending garbage, the failure to retrieve it properly is not surprising.

On the master, the function requestSensor could use an array of values, rather than 4 individual values. It could use reference arguments instead of pointers.

Some Serial.print() statement on the slave and on the master would confirm how much data (and what data) was sent (mangled or not) and how much data and what data was received (mangled or not).

On the sender, you could put all the data in an int array, then send the data like so:

int dataToSend[4];
dataToSend[0] = analogRead(photocellPin0);
dataToSend[1] = analogRead(photocellPin1);
dataToSend[2] = analogRead(photocellPin2);
dataToSend[3] = analogRead(photocellPin3);
Wire.send((byte *)dataToSend, 4*sizeof(int));

Of course, this will send 8 bytes. Why you are expecting 16 bytes is a mystery.

Ah ok, so that clears a few things up.

Well I've retried incorporating what you said into the next set of coding. What do you think?

MASTER

int sensorReading00;
int sensorReading01;
int sensorReading02;
int sensorReading03;
int sensorReading10;
int sensorReading11;
int sensorReading12;
int sensorReading13;
int sensorReading20;
int sensorReading21;
int sensorReading22;
int sensorReading23;
int sensorReading30;
int sensorReading31;
int sensorReading32;
int sensorReading33;
 
#include <Wire.h>
 
void requestSensor(char address, int* sensor0, int* sensor1, int* sensor2, int* sensor3)
{
  byte data[] = {0, 0, 0, 0, 0, 0, 0, 0};
 
  Wire.requestFrom(0x30, 8);
 
  byte c = 0;
 
  while (c < 8)
  {
    if (Wire.available())
    {
    data[c] = Wire.receive();
    c++;
    }
  }
 
  *sensor0 = data[0] << 8 + data[1];
  *sensor1 = data[2] << 8 + data[3];
  *sensor2 = data[4] << 8 + data[5];
  *sensor3 = data[6] << 8 + data[7];
}
 
void setup()
{
  Wire.begin();
  Serial.begin(9600);
}
 
void loop()
{
  requestSensor(0x30, &sensorReading00, &sensorReading01, &sensorReading02, &sensorReading03);
  requestSensor(0x31, &sensorReading10, &sensorReading11, &sensorReading12, &sensorReading13);
  requestSensor(0x32, &sensorReading20, &sensorReading21, &sensorReading22, &sensorReading23);
  requestSensor(0x33, &sensorReading30, &sensorReading31, &sensorReading32, &sensorReading33);
 
if ((sensorReading30+sensorReading32)/2 > sensorReading00) {
  noTone(10);   // set the TONE off
} if ((sensorReading30+sensorReading32)/2 > sensorReading02) {
  noTone(10);    // set the TONE off
} if ((sensorReading30+sensorReading32)/2 > sensorReading10) {
  noTone(10);    // set the TONE off
} if ((sensorReading30+sensorReading32)/2 > sensorReading12) {
  noTone(10);    // set the TONE off
} if ((sensorReading30+sensorReading32)/2 > sensorReading20) {
  noTone(10);    // set the TONE off
} if ((sensorReading30+sensorReading32)/2 > sensorReading22) {
  noTone(10);    // set the TONE off
} if (sensorReading00-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,200);    // set the TONE on
} if (sensorReading02-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,200);    // set the TONE on
} if (sensorReading10-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,1000);    // set the TONE on
} if (sensorReading12-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,1000);    // set the TONE on
} if (sensorReading20-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,500);    // set the TONE on
} if (sensorReading22-50 > (sensorReading30+sensorReading32)/2) {
  tone(10,500);    // set the TONE on
}
 
  Serial.print("Analog reading00 = ");
  Serial.println(sensorReading00);     // the raw analog reading  
  Serial.print("Analog reading01 = ");
  Serial.println(sensorReading01);     // the raw analog reading
  Serial.print("Analog reading02 = ");
  Serial.println(sensorReading02);     // the raw analog reading
  Serial.print("Analog reading03 = ");
  Serial.println(sensorReading03);     // the raw analog reading
  Serial.print("Analog reading10 = ");
  Serial.println(sensorReading10);     // the raw analog reading  
  Serial.print("Analog reading11 = ");
  Serial.println(sensorReading11);     // the raw analog reading
  Serial.print("Analog reading12 = ");
  Serial.println(sensorReading12);     // the raw analog reading
  Serial.print("Analog reading13 = ");
  Serial.println(sensorReading13);     // the raw analog reading 
  Serial.print("Analog reading20 = ");
  Serial.println(sensorReading20);     // the raw analog reading  
  Serial.print("Analog reading21 = ");
  Serial.println(sensorReading21);     // the raw analog reading
  Serial.print("Analog reading22 = ");
  Serial.println(sensorReading22);     // the raw analog reading
  Serial.print("Analog reading23 = ");
  Serial.println(sensorReading23);     // the raw analog reading
  Serial.print("Analog reading30 = ");
  Serial.println(sensorReading30);     // the raw analog reading  
  Serial.print("Analog reading31 = ");
  Serial.println(sensorReading31);     // the raw analog reading
  Serial.print("Analog reading32 = ");
  Serial.println(sensorReading32);     // the raw analog reading
  Serial.print("Analog reading33 = ");
  Serial.println(sensorReading33);     // the raw analog reading
 
  delay(100);
}

SLAVE

int photocellPin0 = 0;     // the cell and 10K pulldown are connected to a0
int photocellReading0;     // the analog reading from the analog resistor divider
int photocellPin1 = 1;     // the cell and 10K pulldown are connected to a1
int photocellReading1;     // the analog reading from the analog resistor divider
int photocellPin2 = 2;     // the cell and 10K pulldown are connected to a2
int photocellReading2;     // the analog reading from the analog resistor divider
int photocellPin3 = 3;     // the cell and 10K pulldown are connected to a3
int photocellReading3;     // the analog reading from the analog resistor divider
 
#include <Wire.h>
 
void requestHandler()
{
  int data[8];
 
  data[0] = analogRead(photocellPin0);
  data[1] = analogRead(photocellPin1);
  data[2] = analogRead(photocellPin2);
  data[3] = analogRead(photocellPin3);
 
  Wire.send((byte*) data, 8);
}
 
void setup()
{
  Wire.begin(0x33); // join i2c bus (address optional for master)
  Serial.begin(9600);
}
 
void loop() {
  photocellReading0 = analogRead(photocellPin0);
  photocellReading1 = analogRead(photocellPin1);
  photocellReading2 = analogRead(photocellPin2);
  photocellReading3 = analogRead(photocellPin3);
 
  Serial.print("Analog reading0 = ");
  Serial.println(photocellReading0);     // the raw analog reading
  Serial.print("Analog reading1 = ");
  Serial.println(photocellReading1);     // the raw analog reading
  Serial.print("Analog reading2 = ");
  Serial.println(photocellReading2);     // the raw analog reading
  Serial.print("Analog reading3 = ");
  Serial.println(photocellReading3);     // the raw analog reading
 
  delay(500);
}

Its a step up because now I'm getting 32640 as readings on the master rather than the initial 0s, but still not quite there.

Cheers.

  int data[8];

Why is this array sized to hold 8 ints?

  *sensor0 = data[0] << 8 + data[1];
  *sensor1 = data[2] << 8 + data[3];
  *sensor2 = data[4] << 8 + data[5];
  *sensor3 = data[6] << 8 + data[7];

Some parentheses might help.

  *sensor0 = (data[0] << 8) + data[1];
  *sensor1 = (data[2] << 8) + data[3];
  *sensor2 = (data[4] << 8) + data[5];
  *sensor3 = (data[6] << 8) + data[7];

Addition has a higher precedence than bit shifting, so data[0] is being shifted data[1] + 8 places in your code. Probably not what you expected.

Thanks for that.

So here is the new coding.

void requestSensor(char address, int* sensor0, int* sensor1, int* sensor2, int* sensor3)
{
  byte data[] = {0, 0, 0, 0, 0, 0, 0, 0};
 
  Wire.requestFrom(0x30, 8);
 
  byte c = 0;
 
  while (c < 8)
  {
    if (Wire.available())
    {
    data[c] = Wire.receive();
    c++;
    }
  }
 
  *sensor0 = (((int) data[0]) << 8) + data[1];
  *sensor1 = (((int) data[3]) << 8) + data[3];
  *sensor2 = (((int) data[4]) << 8) + data[5];
  *sensor3 = (((int) data[6]) << 8) + data[7];
}

My new results are

Analog reading00 = 255
Analog reading01 = -1
Analog reading02 = -1
Analog reading03 = -1
Analog reading10 = 255
Analog reading11 = -1
Analog reading12 = -1
Analog reading13 = -1
Analog reading20 = 255
Analog reading21 = -1
Analog reading22 = -1
Analog reading23 = -1
Analog reading30 = 255
Analog reading31 = -1
Analog reading32 = -1
Analog reading33 = -1

What's that mean?

Thank you very much for your patience Paul

  *sensor0 = (((int) data[0]) << 8) + data[1];

What's up with the cast of data[0] to an int?

Post all of your code, for both sender and receiver, after removing this cast, if you still have problems. We can't see where that output was generated.

That was just a wild attempt at trying to get a different result.

MASTER

int sensorReading00;
int sensorReading01;
int sensorReading02;
int sensorReading03;
int sensorReading10;
int sensorReading11;
int sensorReading12;
int sensorReading13;
int sensorReading20;
int sensorReading21;
int sensorReading22;
int sensorReading23;
int sensorReading30;
int sensorReading31;
int sensorReading32;
int sensorReading33;
 
#include <Wire.h>
 
void requestSensor(char address, int* sensor0, int* sensor1, int* sensor2, int* sensor3)
{
  byte data[] = {0, 0, 0, 0, 0, 0, 0, 0};
 
  Wire.requestFrom(0x30, 8);
 
  byte c = 0;
 
  while (c < 8)
  {
    if (Wire.available())
    {
    data[c] = Wire.receive();
    c++;
    }
  }
 
  *sensor0 = (data[0] << 8) + data[1];
  *sensor1 = (data[3] << 8) + data[3];
  *sensor2 = (data[4] << 8) + data[5];
  *sensor3 = (data[6] << 8) + data[7];
}
 
void setup()
{
  Wire.begin();
  Serial.begin(9600);
}
 
void loop()
{
  requestSensor(0x30, &sensorReading00, &sensorReading01, &sensorReading02, &sensorReading03);
  requestSensor(0x31, &sensorReading10, &sensorReading11, &sensorReading12, &sensorReading13);
  requestSensor(0x32, &sensorReading20, &sensorReading21, &sensorReading22, &sensorReading23);
  requestSensor(0x33, &sensorReading30, &sensorReading31, &sensorReading32, &sensorReading33);
 
  Serial.print("Analog reading00 = ");
  Serial.println(sensorReading00);     // the raw analog reading  
  Serial.print("Analog reading01 = ");
  Serial.println(sensorReading01);     // the raw analog reading
  Serial.print("Analog reading02 = ");
  Serial.println(sensorReading02);     // the raw analog reading
  Serial.print("Analog reading03 = ");
  Serial.println(sensorReading03);     // the raw analog reading
  Serial.print("Analog reading10 = ");
  Serial.println(sensorReading10);     // the raw analog reading  
  Serial.print("Analog reading11 = ");
  Serial.println(sensorReading11);     // the raw analog reading
  Serial.print("Analog reading12 = ");
  Serial.println(sensorReading12);     // the raw analog reading
  Serial.print("Analog reading13 = ");
  Serial.println(sensorReading13);     // the raw analog reading 
  Serial.print("Analog reading20 = ");
  Serial.println(sensorReading20);     // the raw analog reading  
  Serial.print("Analog reading21 = ");
  Serial.println(sensorReading21);     // the raw analog reading
  Serial.print("Analog reading22 = ");
  Serial.println(sensorReading22);     // the raw analog reading
  Serial.print("Analog reading23 = ");
  Serial.println(sensorReading23);     // the raw analog reading
  Serial.print("Analog reading30 = ");
  Serial.println(sensorReading30);     // the raw analog reading  
  Serial.print("Analog reading31 = ");
  Serial.println(sensorReading31);     // the raw analog reading
  Serial.print("Analog reading32 = ");
  Serial.println(sensorReading32);     // the raw analog reading
  Serial.print("Analog reading33 = ");
  Serial.println(sensorReading33);     // the raw analog reading
 
  delay(100);
}

SLAVE#1

int photocellPin0 = 0;     // the cell and 10K pulldown are connected to a0
int photocellReading0;     // the analog reading from the analog resistor divider
int photocellPin1 = 1;     // the cell and 10K pulldown are connected to a1
int photocellReading1;     // the analog reading from the analog resistor divider
int photocellPin2 = 2;     // the cell and 10K pulldown are connected to a2
int photocellReading2;     // the analog reading from the analog resistor divider
int photocellPin3 = 3;     // the cell and 10K pulldown are connected to a3
int photocellReading3;     // the analog reading from the analog resistor divider
 
#include <Wire.h>
 
void requestHandler()
{
  int data[4];
 
  data[0] = analogRead(photocellPin0);
  data[1] = analogRead(photocellPin1);
  data[2] = analogRead(photocellPin2);
  data[3] = analogRead(photocellPin3);
 
  Wire.send((byte*) data, 4);
}
 
void setup()
{
  Wire.begin(0x30); // join i2c bus (address optional for master)
  Serial.begin(9600);
}
 
void loop() {
  photocellReading0 = analogRead(photocellPin0);
  photocellReading1 = analogRead(photocellPin1);
  photocellReading2 = analogRead(photocellPin2);
  photocellReading3 = analogRead(photocellPin3);
 
  Serial.print("Analog reading0 = ");
  Serial.println(photocellReading0);     // the raw analog reading
  Serial.print("Analog reading1 = ");
  Serial.println(photocellReading1);     // the raw analog reading
  Serial.print("Analog reading2 = ");
  Serial.println(photocellReading2);     // the raw analog reading
  Serial.print("Analog reading3 = ");
  Serial.println(photocellReading3);     // the raw analog reading
 
  delay(500);
}

Also, I've tried disconnecting power to all the slaves so that only the master is on, and the serial monitor is now blank. I assume this means that it is polling correctly?

Also, I've tried disconnecting power to all the slaves so that only the master is on, and the serial monitor is now blank. I assume this means that it is polling correctly?

No, it means that the master is waiting for one of the unplugged slaves to respond.

Since you are polling 4 slaves, they need to all be powered up. What happens, now, when they are?

Did you change the code on all 4 slaves?

Wouldn't it be easier to test with just one slave, until the slave and master can communicate correctly?

PaulS:

Also, I've tried disconnecting power to all the slaves so that only the master is on, and the serial monitor is now blank. I assume this means that it is polling correctly?

No, it means that the master is waiting for one of the unplugged slaves to respond.

Since you are polling 4 slaves, they need to all be powered up. What happens, now, when they are?

Yeah that's what I meant. The fact that the master is only showing something on the serial monitor when the slaves are connected means that they are polling correctly. Correct or no?

And yes, I have uploaded the code on all 4.

I'll try rewriting the code for only 1 slave and see how it goes.

The fact that the master is only showing something on the serial monitor when the slaves are connected means that they are polling correctly. Correct or no?

It means that the slaves are responding with the correct number of bytes.

It implies absolutely nothing about the bytes being correct.
It implies absolutely nothing about the master's use of the bytes being correct.

Can you put Serial.print() statements on the slaves? It would be nice to know the values of the bytes that are being sent, so that you can compare them to the bytes being received.

No sense trying to make use of the data received until you know that it matches what was sent.