I2C not sending all data (with i2c_anything)

Hello everyone,

Can anyone help me out on this. I like to sent DHT22 data from one to another arduino. This is temp, humidity, max en min levels of both temp / hum etc.. I use the I2C anything library to sent the data. Problem is that the receiving arduino only gets data from dht sensor 1.

Thank you. Ed. (Netherlands)

My code:

Sending arduino:

    Wire.beginTransmission (SLAVE_ADDRESS);
    float t1=(myDHT1.getTemperatureC());
    float v1=(myDHT1.getHumidity());
    I2C_writeAnything (t1);
    I2C_writeAnything (v1);
    I2C_writeAnything (THsensor1);
    I2C_writeAnything (THsensor1_fout);
    I2C_writeAnything (THsensor1_minT);
    I2C_writeAnything (THsensor1_maxT);
    I2C_writeAnything (THsensor1_minH);
    I2C_writeAnything (THsensor1_maxH);
    Wire.endTransmission ();
    
    Wire.beginTransmission (SLAVE_ADDRESS);
    float t2=(myDHT2.getTemperatureC());
    float v2=(myDHT2.getHumidity());
    I2C_writeAnything (t2);
    I2C_writeAnything (v2);
    I2C_writeAnything (THsensor2);
    I2C_writeAnything (THsensor2_fout);
    I2C_writeAnything (THsensor2_minT);
    I2C_writeAnything (THsensor2_maxT);
    I2C_writeAnything (THsensor2_minH);
    I2C_writeAnything (THsensor2_maxH);
    Wire.endTransmission ();

Receiving arduino:

 void receiveEvent (int howMany)
 {
  
 if (howMany >= (sizeof t1) + (sizeof v1) + (sizeof THsensor1) + (sizeof THsensor1_fout) + 
                (sizeof THsensor1_minT) + (sizeof THsensor1_maxT) + (sizeof THsensor1_minH) + (sizeof THsensor1_maxH))
   {
   I2C_readAnything (t1);
   I2C_readAnything (v1);
   I2C_readAnything (THsensor1);
   I2C_readAnything (THsensor1_fout);
   I2C_readAnything (THsensor1_minT);
   I2C_readAnything (THsensor1_maxT);
   I2C_readAnything (THsensor1_minH);
   I2C_readAnything (THsensor1_maxH);
   }

else if (howMany >= (sizeof t2) + (sizeof v2) + (sizeof THsensor2) + (sizeof THsensor2_fout) + 
         (sizeof THsensor2_minT) + (sizeof THsensor2_maxT) + (sizeof THsensor2_minH) + (sizeof THsensor2_maxH))
   {
   I2C_readAnything (t2);
   I2C_readAnything (v2);
   I2C_readAnything (THsensor2);
   I2C_readAnything (THsensor2_fout);
   I2C_readAnything (THsensor2_minT);
   I2C_readAnything (THsensor2_maxT);
   I2C_readAnything (THsensor2_minH);
   I2C_readAnything (THsensor2_maxH);   
   }

Hi, welcome to the forum.

There is a website for showing only small pieces of code : http://snippets-r-us.com/

The Sending Arduino with the sensors is the Master ? The Receiving Arduino is the Slave ? Perhaps you are using more data then the buffer size of the Wire library. The BUFFER_LENGTH is 32. https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/libraries/Wire/Wire.h Because you show only a part of the code, I can't see if they are small bytes or large float variables.

How do you know if sensor 1 or sensor 2 is being received ? Is the "howMany >=" always valid ?

Thank you Peter.
I am a newbie to Arduino so forgive me if i don’t understand all your questions. :blush:
Indeed the sending Arduino is the master. I was under the assumption that with splitting the transmissions voor sensor 1 and 2 the buffer could not overflow. Is this correct ?

Except for (THsensor1) and (THsensor1_fout), wich are small bytes, all the other variables are floats.

If i switch the sensor numbers in the receiving Arduino it will show the corresponding (other) sensor. I guess this is what you ment with

Is the “howMany >=” always valid ?

That's okay. Keep asking if you don't understand something. When you don't understand something, that is not your fault, that is my fault, for not explaining it well ;)

That are many float variables. 6 * 4 + 2 * 1 = 26 bytes, that is okay I guess.

The two lines with "howMany >=" seems weird to me. How can you tell which sensor data it is ? Google Translate "ik vraag me af..."

Could you add a number as the first byte ? byte sensorNumber = 0; // first sensor I2C_WriteAnything[sensorNumber); I2C_WriteAntthing ...

In the receiver, you read that number and you know which data it is.

I thought the numbering of the variables in i2canything would be sufficient. I have my sketch based on the example of Nick Gammon. I’ve changed it a little but in this setting it works. (The two lines with “howMany >=” )
I don’t have any clue why this is not working in my sketch … :frowning:

// Written by Nick Gammon
// May 2012

#include <Wire.h>
#include <I2C_Anything.h>

const byte MY_ADDRESS = 42;

void setup() 
{
  Wire.begin (MY_ADDRESS);
  Serial.begin (115200);
  Wire.onReceive (receiveEvent);
}  // end of setup

volatile float fnum;
volatile long foo;
volatile byte x;
volatile byte y;

void loop() 
{
    Serial.print ("Received fnum = ");
    Serial.println (fnum,1);  
    Serial.print ("Received foo = ");
    Serial.println (foo);  
    Serial.print ("Received x = ");
    Serial.println (x); 

    Serial.print ("Received y = ");
    Serial.println (y); 
} 
// called by interrupt service routine when incoming data arrives
void receiveEvent (int howMany){
 
 if (howMany >= (sizeof fnum) + (sizeof foo) + (sizeof x))
   {
   I2C_readAnything (fnum);   
   I2C_readAnything (foo); 
   I2C_readAnything (x);
     }  // end if have enough data
   
   else if (howMany >= (sizeof y)){
   I2C_readAnything (y);
    }
 }  // end of receiveEvent
// Written by Nick Gammon
// May 2012

#include <Wire.h>
#include <I2C_Anything.h>

const byte SLAVE_ADDRESS = 42;

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

void loop() 
{
 byte x = 5; 
 byte y = 15;
 long foo = 42456;
 float fnum=23.1;

 
    Wire.beginTransmission (SLAVE_ADDRESS);
   I2C_writeAnything (fnum); 
   I2C_writeAnything (foo++);
    I2C_writeAnything (x);
    Wire.endTransmission ();
    
    Wire.beginTransmission (SLAVE_ADDRESS);
    I2C_writeAnything (y);
    Wire.endTransmission ();
    
      
    delay (200);


}  // end of loop

If the total size for sensor 2 would be the same or larger than the total size of sensor 1, the if-statement for sensor 1 will always be true.

But i don't like to use the howMany to determince the sensor number anyway. Can you add a variable for the sensor number ? That is straightforward and it will work.

I get your point about the howMany thing. I implemented the sensorNumber but the problem stil occurs. Only one sensor is shown by the slave arduino. I tried several options but after many hours with no result. Can you take a look at my last code ?

This is the last code i tried:

Slave:

 void receiveEvent (int howMany)
 {volatile byte sensorNumber;

   while(Wire.available()) // loop through all but the last
  {
   I2C_readAnything (sensorNumber);

   if (sensorNumber==0)
   { 
     
   I2C_readAnything (t1);
   I2C_readAnything (v1);
   I2C_readAnything (THsensor1);
   I2C_readAnything (THsensor1_fout);
   I2C_readAnything (THsensor1_minT);
   I2C_readAnything (THsensor1_maxT);
   I2C_readAnything (THsensor1_minH);
   I2C_readAnything (THsensor1_maxH);
   }
   
   if (sensorNumber==1)
   { 
    
   I2C_readAnything (t2);
   I2C_readAnything (v2);
   I2C_readAnything (THsensor2);
   I2C_readAnything (THsensor2_fout);
   I2C_readAnything (THsensor2_minT);
   I2C_readAnything (THsensor2_maxT);
   I2C_readAnything (THsensor2_minH);
   I2C_readAnything (THsensor2_maxH);
   }
   
      }  // end if have enough data

Master

   byte sensorNumber = 0;           // first sensor
     
    Wire.beginTransmission (SLAVE_ADDRESS);
    I2C_writeAnything (sensorNumber);
    I2C_writeAnything (t1);
    I2C_writeAnything (v1);
    I2C_writeAnything (THsensor1);
    I2C_writeAnything (THsensor1_fout);
    I2C_writeAnything (THsensor1_minT);
    I2C_writeAnything (THsensor1_maxT);
    I2C_writeAnything (THsensor1_minH);
    I2C_writeAnything (THsensor1_maxH);
    Wire.endTransmission ();

Those parts of code are okay. Should I try to write a test with it ? I have two Arduino Uno boards lying here.

If it's not too much trouble. :)

I will try to find some time in the next 15 hours...

:) Peter! I got it working! A slight modification in the receiving Arduino did the trick.

I added this line for every sensor:

while(Wire.available())

Thank you [u]very[/u] much for putting me on the right track!!

The code:

 void receiveEvent (int howMany)
 {
      I2C_readAnything (sensorNumber);

   if (sensorNumber==0)
   {   while(Wire.available()) // loop through all but the last
  {
     
   I2C_readAnything (t1);
   I2C_readAnything (v1);
   I2C_readAnything (THsensor1);
   I2C_readAnything (THsensor1_fout);
   I2C_readAnything (THsensor1_minT);
   I2C_readAnything (THsensor1_maxT);
   I2C_readAnything (THsensor1_minH);
   I2C_readAnything (THsensor1_maxH);
   }}
   
   if (sensorNumber==1)
   {   while(Wire.available()) // loop through all but the last
  {
    
   I2C_readAnything (t2);
   I2C_readAnything (v2);
   I2C_readAnything (THsensor2);
   I2C_readAnything (THsensor2_fout);
   I2C_readAnything (THsensor2_minT);
   I2C_readAnything (THsensor2_maxT);
   I2C_readAnything (THsensor2_minH);
   I2C_readAnything (THsensor2_maxH);
   }}

Maybe you have to check that again. The Wire.available can be used in receiveEvent, but it is not needed since ‘howMany’ is the number of bytes that are received.

Meanwhile I was writing this sketch:

I noticed that you didn’t post your whole sketch. So you are asking about a problem that you don’t show us.
Please read this : http://snippets-r-us.com/
And this : http://forum.arduino.cc/index.php/topic,148850.0.html

Because I don’t have your sketch, I decided to push forward and use a ‘struct’ :stuck_out_tongue:
A ‘struct’ is a some variables, packed into a single package.
I also like to use ‘struct’ everywhere :grin:

I used 9600 baud, so you have to set the serial monitor to 9600 baud.

Slave, Receiving Arduino

// Slave, Receiving Arduino.
// Arduino Uno
// Arduino IDE 1.6.0
// Imported library : I2c_Anything.zip ( http://www.gammon.com.au/i2c )
//

#include <Wire.h>
#include <I2C_Anything.h>

const byte SLAVE_ADDRESS = 42;

// The struct must be the same in the Master and in the Slave
struct sensorData_STRUCT
{
  byte sensorNumber;
  float t;
  float v;
  byte THsensor;
  byte THsensor_fout;
  float THsensor_minT;
  float THsensor_maxT;
  float THsensor_minH;
  float THsensor_maxH;
};

// A special struct for the received sensor data
volatile sensorData_STRUCT sensorDataNew;

// A flag to indicate new data
volatile boolean haveData = false;

// The normal sensor data
sensorData_STRUCT sensorData[2];

void setup()
{
  Serial.begin(9600);
  Serial.println(F("\nSlave has started"));
  Serial.print(F("The size of the sensorData struct is "));
  Serial.print( sizeof( sensorData_STRUCT));
  Serial.println(F(" bytes"));
  
  Wire.begin( SLAVE_ADDRESS);
  Wire.onReceive (receiveEvent);
  
  // fill fixed data
  sensorData[0].sensorNumber = 0;
  sensorData[1].sensorNumber = 1;
}


void loop()
{
  int sensor;
  
  if( haveData)
  {
    // New data has arrived, copy it in one of the two sensorData.
    // Disable interrups as short as possible
    // The interrupts are disabled to avoid an receiveEvent interrupt that writes new data.
    noInterrupts();
    sensor = sensorDataNew.sensorNumber;
    if( sensor == 0 || sensor == 1)
    {
      memcpy( &sensorData[sensor], (const void *) &sensorDataNew, sizeof( sensorData_STRUCT)); // destination, source, size
    }
    haveData = false;
    interrupts();
    
    
    // Show new data
    Serial.print(F( "------ sensor["));
    Serial.print( sensor);
    Serial.println(F( "] ------"));
    Serial.print(F( "  t="));
    Serial.println( sensorData[sensor].t);
    Serial.print(F( "  v="));
    Serial.println( sensorData[sensor].v);
    Serial.print(F( "  THsensor="));
    Serial.println( sensorData[sensor].THsensor, HEX);
    Serial.print(F( "  THsensor_fout="));
    Serial.println( sensorData[sensor].THsensor_fout, HEX);
    Serial.print(F( "  THsensor_minT="));
    Serial.println( sensorData[sensor].THsensor_minT);
    Serial.print(F( "  THsensor_maxT="));
    Serial.println( sensorData[sensor].THsensor_maxT);
    Serial.print(F( "  THsensor_minH="));
    Serial.println( sensorData[sensor].THsensor_minH);
    Serial.print(F( "  THsensor_maxH="));
    Serial.println( sensorData[sensor].THsensor_maxH);
    Serial.println();
  }
}


void receiveEvent( int howMany)
{
  if( howMany == sizeof( sensorData_STRUCT))
  {
    I2C_readAnything( sensorDataNew);   
    haveData = true;
  }
  else
  {
    // something is wrong. Wrong number of bytes received.
    // it is possible to set a volatile variable to an error.
  }
}

Master, Sending Arduino

// Master, Sending Arduino.
// Arduino Uno
// Arduino IDE 1.6.0
// Imported library : I2c_Anything.zip ( http://www.gammon.com.au/i2c )
//

#include <Wire.h>
#include <I2C_Anything.h>

const byte SLAVE_ADDRESS = 42;

// The struct must be the same in the Master and in the Slave
struct sensorData_STRUCT
{
  byte sensorNumber;
  float t;
  float v;
  byte THsensor;
  byte THsensor_fout;
  float THsensor_minT;
  float THsensor_maxT;
  float THsensor_minH;
  float THsensor_maxH;
} sensorData[2];

void setup()
{
  Serial.begin(9600);
  Serial.println(F("\nMaster has started"));
  
  Wire.begin();
  
  // fill fixed data
  sensorData[0].sensorNumber = 0;
  sensorData[1].sensorNumber = 1;
}


void loop()
{
  // collect new data
  sensorData[0].t = 23.6;
  sensorData[0].v = 50.8;
  sensorData[0].THsensor = 0x12;
  sensorData[0].THsensor_fout = 0x01;
  sensorData[0].THsensor_minT = -10.5;
  sensorData[0].THsensor_maxT = 1003.2;
  sensorData[0].THsensor_minH = 0.5;
  sensorData[0].THsensor_maxH = 95.5;

  sensorData[1].t = 57.83;
  sensorData[1].v = 98.231;
  sensorData[1].THsensor = 0x45;
  sensorData[1].THsensor_fout = 0xa0;
  sensorData[1].THsensor_minT = -430.57;
  sensorData[1].THsensor_maxT = 69.875;
  sensorData[1].THsensor_minH = 29.88;
  sensorData[1].THsensor_maxH = 89.505;


  for( int sensor = 0; sensor < 2; sensor++)
  {
    // transmit the data
    Wire.beginTransmission( SLAVE_ADDRESS);
    I2C_writeAnything( sensorData[sensor]);
    int error = Wire.endTransmission ();
    
    if( error != 0)
    {
      Serial.println(F("Error, no acknowledge from Slave"));
    }
  
    delay(500);
  }
  delay(3000);
}

Next time i will post the full code.

A struct is new to me. :o

Thank you for your code! :) I will experiment with it.

Did you know that you can have two Arduino IDE side by side on the screen. One for the Master Arduino and one for Slave Arduino, each with its own serial monitor ?

I have my two arduino boards connected to a USB hub.
I start the Arduino IDE, move it to the left side of the screen, select Uno board, and the serial port for the Master.
I start another Arduino IDE, select Uno, and the other serial port for the Slave.
Then I can develop both sketches at the same time.

When I upload a sketch to the Slave, it is temporary not available to the Master, and the serial monitor of the Master starts writing error messages that the Slave is not responding. Very funny.

Wow! I did not know that. This works a lot easier! :grin: Thanks for sharing this tip!

I use it ok with I2cAnything to send/receive all kind of variables data , but now i need to send data from 3 Arduino slave to 1 master read. the code for I2canything is reverse, it mean that slave read, master send. from Gammon, can you help me , please.