[solved] Sending array data with I2C

Hi,

Am actualy reading simultaneously the pulse from 12 Water Flow Hall Sensor with one arduino nano.

Am now triying to send this data to an arduino mega.

I look on the arduino page reference for the wire library and found: Wire.write(data, length) that look promising, but I have never been able read my data on the mega with this command.

Can someone explain me how it work and how to read the data on the mega, or have a beter idea to send the data of the 12 Water flow sensor to the arduino mega?

thanks :slight_smile:

Do you know this tutorial: Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino. There is also the I2C_Anything on that page, that some like to use.

The following tutorial may be helpful for the OP to send 4-byte data from NANO-Master to MEGA-Slave using I2C Bus.

1. Connect NANO (Master) and MEGA (Slave) using I2C Bus as follows. There is no need to connect pull-up resistors on the I2C bus as the MEGA Board has built-in 2x10k pull-up resistors with the SDA and SCL lines.

SDA (A4) of NANO -------> SDA (DPin-20) of MEGA
SCL (A5) of NANO --------> SCL (DPin-21) of MEGA
GND of NANO -------------> GND of MEGA

2. Upload the following sketch into the flash of NANO.

#include<Wire.h>
#define slaveAddress 0x08
byte dataArray[4] = {0x12, 0x34, 0x56, 0x78};

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  //-----------------------------------
  Wire.beginTransmission(slaveAddress); //address is queued for checking if the slave is present
  for (int i=0; i<4; i++)
  {
    Wire.write(dataArray[i]);  //data bytes are queued in local buffer
  }
  Wire.endTransmission(); //all the above queued bytes are sent to slave on ACK handshaking
  //--------------------------------------------------------------------
}

void loop()
{
  
}

3. Upload the following sketch into the flash of MEGA.

#include<Wire.h>
#define slaveAddress 0x08  //you have to assign an 8-bit address to Slave
byte dataArray[4];

void setup()
{
  Wire.begin(slaveAddress);
  Serial.begin(9600);
  //-----------------------------------
  Wire.onReceive(receiveEvent);//you need to declre it in setup() to receive data from Master
}

void loop()
{
  
}

void receiveEvent(int howmany) //howmany = Wire.write()executed by Master
{
  for(int i=0; i<howmany; i++)
  {
    dataArray[i] = Wire.read();
    Serial.print(dataArray[i], HEX);
  }
}

3. Press and hold the RESET buttons of both Arduinos.

4. RElease the RESET button of MEGA (the Slave).

5. Release the RESET button of NANO (the Master).

6. Check that the data byte 12345678 has appeared on the SM of MEGA.

7. Working Principles of the I2C Bus.
Place queries?

8. Working Principles of the Master/Slave Sketches.
Place queries?

Thanks for your anwsers :slight_smile: !

From the link : Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino (Very good tutorial on I2C !)
And the information found here : arduino.stackexchange.com

I finaly get my program to work.

The master send to the slave the array address requested and in response the slave send the requested data.

For people interested there is the code:

Master:

#include <Wire.h>

int start = 0;
int d;
int Adress;           //Store the array address
char t[10]={};     //create a array to receive the incoming data from the slave
int pulse[12]={};  //Store the usable received data



void setup() {
  Wire.begin();    //initialise I2C
  Serial.begin(9600);
}




void loop() {
if (start == 0){   //To run one time only the code
 
  for (int i=0;i<12;i++){         //to request the data from 12 array addresses

    Adress=i;
    Serial.println("I send");
    Serial.println(Adress);        //Print the array adcress requested by the master
    
    Wire.beginTransmission (8);    //Start I2C communication with the slave 
    Wire.write (Adress);                          
    Wire.endTransmission ();       
    
    delay(10);                  // Adding some delay to avoid error when changing from send to read...  (I tested without it, it's working, but I find safer to add it)
    
    Wire.requestFrom(8,5);     //request the slave to send the requested Data
    
  
    while (Wire.available()>2) {
    t[d] = Wire.read();         // Put the receving data in the array t
    d++;
    if (d>=3){d=0;}             // Return the cursor of array t to 0 when we receive the 3 wanted bytes
    }
    Serial.println("Received Data");
    Serial.println(t);          // Received ASII Data
    
    pulse[Adress]=((((((t[0])-48)*10)+((t[1])-48))*10)+((t[2])-48));  //Convert ASII to DECIMAL to store in a int.      In ASII 0 is 48, 1 is 49, 2 is 50.... so if we sustrac 48 to the ASII number we get an DECIMAL number
    Serial.println(pulse[Adress]);  //Print the received Data
  } // end of for loop

  
  Serial.print("\r\n");  //Skip one line
  Serial.println("All Received Data");  //Print all the received Data
  for (int y=0;y<12;y++){Serial.println(pulse[y]);}   //Display all the data received
  
  }   // end of if

  
  start =1;

}   //end of void loop ()

Slave:

#include <Wire.h>
char t[10]; //empty array where to put the data going to the master
int pulse[12]={245,255,265,275,285,295,305,315,325,335,345,355}; //Store random data to send to Master

volatile int Adress =10; // variable used by the master to sent data to the slave

void setup() {
  Wire.begin(8);           //slave address
  Wire.onRequest(requestEvent); //Create an Interrup when Master request data
  Wire.onReceive(receiveEvent); //Create an Interrup when receiving data from the Master
  Serial.begin(9600);  
  

}

void loop() {
  delay(500);
}


void receiveEvent()
{Adress = Wire.read();    //Read the data requested by the Master
}   


void requestEvent() {
   dtostrf(pulse[Adress], 3, 0, t);   //Convert the Data requested to ASII String   dtostrf(floatVar or intVar, minStringWidthIncDecimalPoint, numVarsAfterDecimal, empty array)         
   Wire.write(t);         //Send ASII String
}

Could you remove this: while (Wire.available()<2) {}
It is not safer, it is pure nonsense code.
Explanation: Common-mistakes#1

It is the same as this:

int i = 3;
while( i != 3);   // wait until the variable 'i' is created and has been made '3'.

You can make the voltatile ‘Adres’ a byte. A AVR microcontroller is 8-bits, that means an interrupt might occur right in the middle when reading the two bytes of an integer. A byte is safer.

You could transfer an integer. No one transmits readable ASCCII text over the I2C bus. Well, almost no one, I know the Arduino example does it, but that is a bad example.

When you transfer a 2 byte integer, the Slave sends those two bytes and the Master requests two bytes. That is easier because of the fixed length. There is no need to convert to text and convert it back.

I always advice to check the ‘howMany’ parameter. When you expect one byte, check if you have received one byte.

void receiveEvent( int howMany)
{
  if( howMany == 1)   // expecting one byte
  {
    Adress = Wire.read();    //Read the data sent by the Master
  }
}

1. I think that the execution of the Wire.available() instruction after the Wire.requestFrom(slaveAdddress, arg2)) instruction is redundant (or not needed at all). It is because --

Wire.requestFrom() is a looping instruction; it will address the slave; it will remain in loop until number of data bytes equal to arg2 are collected; finally, bus will be released. The Wire.available() function returns a value that is always equal to arg2.

2. howmany is always equal to the number of times the Master has executed the Wire.write() instruction; therefore, there is no need for the slave to check the condition for equality; it can simply read the value of howmany and comfortably read data bytes until howmany becomes zero.