big number over i2c

Hi i have one Arduino in slave mode (i2c connection) that reads some sensors and among of them a barometer that reads value of : 989.06 (hpa)

what is the best method to transfer this big number via i2c to the master arduino ?

the other 3 sensors giving me analog readings that i can map them and sending them with a structure

struct {
  uint8_t InData1;  // AnalogReadA0
  uint8_t InData2;  // AnalogReadA1
  uint8_t InData3;  // AnalogReadA2
  uint8_t InData4;  // Barometer

} SendData;

what methods should i check and read

ps: i am not a skill programmer.. i am a self training with no previous education in programing languages

It looks like your current struct has a single byte (uint8_t) dedicated to the barometer reading. However, for a reasonable resolution, you need a float (4 bytes). Also, the I2C buffer is usually 4 32 bytes so you probably have to send two (or more) data "packets" in order to transmit all that data from all sensors to the receiver.

Edit: Corrected having seen @Koepel's post. Of course. 32 bytes, not 32 bits.

I2C Bus handles data one byte at a type. Therefore, your data item (float or integer) must be converted into 8-bit chunks (the bytes) in order to transfer them over I2C Bus. The simple way of converting your given float data (989.06) is to use the following codes:

union
{
    float x;
    byte myData[4];
}data;

data.x = 989.06;   //myData[] contains the bytes with lower byte in lower location

Thanks Both for your answers

I have found an other way to do what i wanted (maybe is not the best method but was easier to understand what had to do to make it work)

i split my number in a array : and then in master i added all together to bring my number back

void SensorsRead() {

  ReadAnalog_0 ();
  ReadAnalog_1 ();
  ReadAnalog_2 ();
  ReadAnalog_3 ();



  float num_dia;
  uint32_t  dia;
  num_dia = pressure;
  dia = (num_dia * 100);
  barometer[0] = (dia / 100000 % 10 ) ;
  barometer[1] = (dia / 10000 % 10 ) ;
  barometer[2] = (dia / 1000 % 10 ) ;
  barometer[3] = (dia / 100 % 10 ) ;
  barometer[4] = (dia / 10 % 10 ) ;
  barometer[5] = (dia  % 10 ) ;


  DataSend.OutData1 = ValueA0 ;
  DataSend.OutData2 = ValueA1 ;
  DataSend.OutData3 = ValueA2 ;
  DataSend.OutData4 = ValueA3 ;
  DataSend.OutData5 = barometer[0];
  DataSend.OutData6 = barometer[1];
  DataSend.OutData7 = barometer[2];
  DataSend.OutData8 = barometer[3];
  DataSend.OutData9 = barometer[4];
  DataSend.OutData10 = barometer[5];

and then in master i added all together to bring my number back :

  Serial.print(F("Presure: "));
  Serial.print(DataReceived.InData5 * 1000 + DataReceived.InData6 * 100 + DataReceived.InData7 * 10 + DataReceived.InData8 + DataReceived.InData9 * 0.1 + DataReceived.InData10 * 0.01);
  Serial.println(F(":  hpa"));



  num_barometer = (DataReceived.InData5 * 1000 + DataReceived.InData6 * 100 + DataReceived.InData7 * 10 + DataReceived.InData8 + DataReceived.InData9 * 0.1 + DataReceived.InData10 * 0.0);

  Serial.print(num_barometer);
  Serial.println(F(":  hpa"));
  Serial.println(F(" "));

the only problem with that solution is that i didnt manage to make a variable to store / apearing the second digit after ,
But is not big problem asi don’t think that would need so much accuracy

(what type of Variable is the best for this kind of numbers? )

here are both master and slave test codes :

MASTER CODE

/*
 * Master code
 * Two Arduinos in i2c connection
 * Master sends comands to slave to send package of data 
 * Caslor 05/05/2020
 */



//////////////////////////////////////////////////////////////////////////

#include <Wire.h>
const int SLAVE_ADDR = 5; // Define Slave I2C Address

////////////////////////////////////////////////////////////////////

uint8_t button = 4; // pin to read button


struct {
  uint8_t InData1;
  uint8_t InData2;
  uint8_t InData3;
  uint8_t InData4;
  uint8_t InData5;
  uint8_t InData6;
  uint8_t InData7;
  uint8_t InData8;
  uint8_t InData9;
  uint8_t InData10;
  uint8_t b1;
} DataReceived;


const int ANSWERSIZE = sizeof(DataReceived); // Define Slave answer size


char *AnalogState[] = {"No ", "yes", "Error"};
int n = 0;

//uint32_t  num_barometer;
//long  num_barometer;
//int32_t  num_barometer;
//int  num_barometer;
//unsigned long num_barometer;
double num_barometer;



void setup() {
  // put your setup code here, to run once:
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
  pinMode(button, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (digitalRead(button) == LOW  ) {
    Command2Slave() ;
    delay(500);
    ReceiveSlave();
    Decode();
  }
  else if (digitalRead(button) == HIGH ) {
    Serial.println(F("Stand By mode"));
    delay(200);
  }
}

void Command2Slave()  {
  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write('U');
  Wire.endTransmission();
}

void ReceiveSlave()  {
  Wire.requestFrom(SLAVE_ADDR, ANSWERSIZE);
  DataReceived.InData1 = Wire.read();  // for A0 Analog reading
  DataReceived.InData2 = Wire.read();  // for A1 Analog reading
  DataReceived.InData3 = Wire.read();  // for A2 Analog reading
  DataReceived.InData4 = Wire.read();  // for A3 Analog reading
  DataReceived.InData5 = Wire.read();  // Receiving 1st digit of barometer
  DataReceived.InData6 = Wire.read();  // Receiving 2nd digit of barometer
  DataReceived.InData7 = Wire.read();  // Receiving 3nd digit of barometer
  DataReceived.InData8 = Wire.read();  // Receiving 4th digit of barometer
  DataReceived.InData9 = Wire.read();  // Receiving 5th digit of barometer
  DataReceived.InData10 = Wire.read(); // Receiving 6th digit of barometer
  DataReceived.b1 = Wire.read();  // pin state read
}


void Decode() {

  Serial.print(F("AnalogA0: "));
  Serial.print(DataReceived.InData1);
  Serial.println(F("%"));

  Serial.print(F("AnalogA1: "));
  Serial.print(DataReceived.InData2);
  Serial.println(F("%"));




  decodeSensor1( "AnalogA2", DataReceived.InData3);

  Serial.println(AnalogState[n]); //AnalogA2

  Serial.print(F("AnalogA3: "));
  Serial.print(DataReceived.InData4);
  Serial.println(F("%"));

  Serial.println(F(" "));


  Serial.print(F("Presure: "));
  Serial.print(DataReceived.InData5 * 1000 + DataReceived.InData6 * 100 + DataReceived.InData7 * 10 + DataReceived.InData8 + DataReceived.InData9 * 0.1 + DataReceived.InData10 * 0.01);
  Serial.println(F(":  hpa"));



  num_barometer = (DataReceived.InData5 * 1000 + DataReceived.InData6 * 100 + DataReceived.InData7 * 10 + DataReceived.InData8 + DataReceived.InData9 * 0.1 + DataReceived.InData10 * 0.0);

  Serial.print(num_barometer);
  Serial.println(F(":  hpa"));
  Serial.println(F(" "));

  Serial.print(F( "Button is " ));
  if ( DataReceived.b1 == HIGH ) {
    Serial.println(F( " HIGH " ));
  }
  else {
    Serial.println(F( " LOW " ));
  }


  delay(500);

}

void decodeSensor1( const char *msg, uint8_t val ) {
  Serial.print( msg );
  Serial.print(F( " is :" ));
  if (val <= 1) {
    n = 0;

  }
  else if (val >= 1 && val < 10 ) {
    n = 1;

  }
  else if (val >= 10 && val < 50 ) {
    n = 2;

  }
  else {
    n = 3;

  }
}

SLAVE CODE

/*
 * Slave code
 * Two Arduinos in i2c connection
 * Master sends comands to slave to send package of data 
 * Slave split big recorded number of barometer sensor in a array and sending to master with other recorded values
 * Caslor 05/05/2020
 */

/////////////////////////////////////////////////////////////
#include <Wire.h>
const int SLAVE_ADDR = 5;
///////////////////////////////////////////////////////////////////////
const byte AnalogReading0 = A0 ;
int ValueA0;
const byte AnalogReading1 = A1 ;
int ValueA1;
const byte AnalogReading2 = A2 ;
int ValueA2;
const byte AnalogReading3 = A3 ;
int ValueA3;
///////////////////////////////////  BMP085 Barometer /////////////////////////////////////

const byte testbutton = 4;


struct {
  uint8_t OutData1; // AnalogReadA0
  uint8_t OutData2; // AnalogReadA1
  uint8_t OutData3; // AnalogReadA2
  uint8_t OutData4; // AnalogReadA3
  uint8_t OutData5;
  uint8_t OutData6;
  uint8_t OutData7;
  uint8_t OutData8;
  uint8_t OutData9;
  uint8_t OutData10;
  uint8_t b1;
} DataSend;

//////////////////////////////////////////////////////////////////////////////////////
#include <Wire.h>
#include <SFE_BMP180.h>
SFE_BMP180 bmp180;
//int Altitude = 220; //current altitude in meters
int Altitude = 7; //current altitude in meters
float pressure;
////////////////////////// soil temp thermistor ////////////////////////////////////////////////

#define THERMISTORPIN A1  // Soil Temp

// resistance at 25 degrees C
#define THERMISTORNOMINAL 10000
// temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 25
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES 5
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 3950
// the value of the 'other' resistor
#define SERIESRESISTOR 9800  //SERIESRESISTOR 10000

int samples[NUMSAMPLES];
int tempSoil;
//////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////     Wind  sensor   ////////////////////////////////////////////////

#define windPIN A2  // Soil Temp

// how many samples to take and average, more takes longer
// but is more 'smooth'
#define windSamples 5

int samples2[windSamples];
int wind;
//////////////////////////////////////////////////////////////////////////////////////////////////
int barometer[5];
///////////////////////////////////////////////////////////////////////

void setup() {

  Serial.begin(9600);  // start serial for
  Wire.begin(SLAVE_ADDR);

  Wire.onRequest(requestEvent);  // Function to run when data requested from master
  Wire.onReceive(receiveEvent); // register event
  pinMode(testbutton, INPUT_PULLUP);

  bool success = bmp180.begin();
  if (success) {
    Serial.println("BMP180 init success");
  }

  delay(500);
  SensorsRead();
}

void loop()
{

  Pressure() ;
  SensorsRead();
  delay(500);
}



/////////////////////////////////// Void requestEvent   ///////////////////////////

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {

  // as expected by master
  Wire.write(DataSend.OutData1);  //for A0 Analog reading
  Wire.write(DataSend.OutData2);  //for A1 Analog reading
  Wire.write(DataSend.OutData3);  //for A2 Analog reading
  Wire.write(DataSend.OutData4);  //for A3 Analog reading
  Wire.write(DataSend.OutData5);  // sending 1st digit of barometer
  Wire.write(DataSend.OutData6);  // sending 2nd digit of barometer
  Wire.write(DataSend.OutData7);  // sending 3nd digit of barometer
  Wire.write(DataSend.OutData8);  // sending 4th digit of barometer
  Wire.write(DataSend.OutData9);  // sending 5th digit of barometer
  Wire.write(DataSend.OutData10); // sending 6th digit of barometer
  Wire.write(DataSend.b1);  // pin state read
}
//////////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////// Void receiveEvent   ///////////////////////////

void receiveEvent(int howMany) {
  if (Wire.available()) {
    char c = Wire.read();
    if (c == 'U') {
      SensorsRead();
    }
  }
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// Void SensorsRead   ///////////////////////////

void SensorsRead() {

  ReadAnalog_0 ();
  ReadAnalog_1 ();
  ReadAnalog_2 ();
  ReadAnalog_3 ();



  float num_dia;
  uint32_t  dia;
  num_dia = pressure;
  dia = (num_dia * 100);
  barometer[0] = (dia / 100000 % 10 ) ;
  barometer[1] = (dia / 10000 % 10 ) ;
  barometer[2] = (dia / 1000 % 10 ) ;
  barometer[3] = (dia / 100 % 10 ) ;
  barometer[4] = (dia / 10 % 10 ) ;
  barometer[5] = (dia  % 10 ) ;


  DataSend.OutData1 = ValueA0 ;
  DataSend.OutData2 = ValueA1 ;
  DataSend.OutData3 = ValueA2 ;
  DataSend.OutData4 = ValueA3 ;
  DataSend.OutData5 = barometer[0];
  DataSend.OutData6 = barometer[1];
  DataSend.OutData7 = barometer[2];
  DataSend.OutData8 = barometer[3];
  DataSend.OutData9 = barometer[4];
  DataSend.OutData10 = barometer[5];

  DataSend.b1 = digitalRead(testbutton);
  Serial.print("AnalogA0 = ");
  Serial.println(ValueA0);
  Serial.print("AnalogA1 = ");
  Serial.println(ValueA1);
  Serial.print("AnalogA2 = ");
  Serial.println(ValueA2);
  Serial.print("AnalogA3 = ");
  Serial.println(ValueA3);
  Serial.print("pressure = ");
  Serial.println(pressure);

}


void ReadAnalog_0 () {

  int ReadingA0;
  ReadingA0 = analogRead(AnalogReading0);
  ValueA0 = map(ReadingA0, 0, 1023, 0, 255);

}


void ReadAnalog_1 () {

  int ReadingA1;
  ReadingA1 = analogRead(AnalogReading1);
  ValueA1 = map(ReadingA1, 0, 1023, 0, 200);

}



void ReadAnalog_2 () {

  int ReadingA2;
  ReadingA2 = analogRead(AnalogReading2);
  ValueA2 = map(ReadingA2, 0, 1023, 0, 100);

}

void ReadAnalog_3 () {

  int ReadingA3;
  ReadingA3 = analogRead(AnalogReading3);
  ValueA3 = map(ReadingA3, 0, 1023, 0, 255);

}


void Pressure() {
  char status;
  double T, P;
  bool success = false;

  status = bmp180.startTemperature();

  if (status != 0) {
    delay(1000);
    status = bmp180.getTemperature(T);

    if (status != 0) {
      status = bmp180.startPressure(3);

      if (status != 0) {
        delay(status);
        status = bmp180.getPressure(P, T);

        if (status != 0) {
          float comp = bmp180.sealevel(P, Altitude);
          pressure = comp;
          Serial.print("Pressure: ");
          Serial.print(comp);
          Serial.print("  -  ");
          Serial.print(pressure);
          Serial.println(" hPa");

          Serial.print("Temperature: ");
          Serial.print(T);
          Serial.println(" C");
        }
      }
    }
  }
}

May I turn everything upside down ?

It is okay to do analogRead() hundreds or thousands times per second. You can do that in the loop() continuously. I don't know how often the BMP180 data can be requested. You can make a millis() timer to update it every 2 seconds in the loop(). Then you don't need the 'onReceive' anymore.

Update the struct continuously with the newest values.

Four analog values and one float is:

volatile struct {
  int Analog0;
  int Analog1;
  int Analog2;
  int Analog3;
  float barometer;
} DataSend;

The Arduino Uno and Nano and Leonardo and Mega 2560 have a buffer of 32 bytes for I2C. So you can add things to the structs up to 32 bytes. Are both the Slave and the Master of the Uno/Nano/Mega type ?

In the 'onRequest', use Wire.write( DataSend, sizeof(DataSend)). That's all, nothing else in that function. There is probably a cast needed to a char * or uint8_t * for DataSend.

In the Master:

int n = Wire.requestFrom(SLAVE_ADDR, sizeof( DataReceived));
if( n == sizeof( DataReceived))
{
  Wire.readBytes( DataReceived, sizeof( DataReceived));
}

You can use a fixed number of the size of the struct. The 'sizeof()' is something for the compiler, the compiler will put there the right size of that variable. When you add something to the struct, then it will automatically use the new size with 'sizeof()'.

I think this will make it shorter and more straightforward.