Envío de datos por I2C con sensor MPU

Hola,
Tengo dos Arduinos conectados por I2C, como master tengo un Arduino MEGA y como esclavo un UNO, estoy teniendo un pequeño problema al intentar enviar los datos del sensor MPU GY-521.

He conseguido obtener los datos del sensor (eje x,y,z) con el sketch que viene en la librería. Y también conseguí enviar 3 variables siguiendo los ejemplos del siguiente tema: http://forum.arduino.cc/index.php?topic=45445.0

El código que tengo es este:

Master

#include <Wire.h>

const byte slaveAddress = 2;
const byte dataCount = 3;

union
  {
  float floatData [dataCount];
  byte  rawData [dataCount * sizeof (float)];
  } myData;

unsigned long lastSerialPrint = 0;

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  digitalWrite(SDA,LOW);
  digitalWrite(SCL,LOW);
}  // end of setup

void loop()
{
    if (Wire.requestFrom (slaveAddress, sizeof myData) == sizeof myData)
      {
      for (int i = 0; i < sizeof myData; i++)
         myData.rawData [i] = Wire.read ();
      }  // end if
         
    if(millis() - lastSerialPrint > 1000) //Like the Blink without delay example, true once a second
      {
      for (int i = 0; i < dataCount; i++)
        {
          int axis = (int) myData.floatData[i];
          Serial.print ("var ");
          Serial.print (i);
          Serial.print (" Value: ");
          Serial.println ();  
        } // end for
      lastSerialPrint = millis(); //Snapshot of when this happened, in milli seconds
      }  // end if
}  // ene of loop

Esclavo

#include <Wire.h>
#include "I2Cdev.h"
#include "MPU6050.h"

MPU6050 accelgyro;// class default

int16_t ax, ay, az;//accelerograph

#define OUTPUT_READABLE_ACCELGYRO//values in decimal
//#define OUTPUT_BINARY_ACCELGYRO//values in binary (16-bits)

volatile byte* Float1ArrayPtr; 
volatile byte* Float2ArrayPtr; 
volatile byte* Float3ArrayPtr;  

int Address = 2;  //This slave is address number 2
float floatData[3]; 

void setup()
{
  Wire.begin(Address);
  digitalWrite(SDA,LOW);
  digitalWrite(SCL,LOW);
  Wire.onRequest(requestEvent); // register event
  
  Serial.begin(38400);

  // initialize device
  Serial.println("Initializing I2C devices...");
  accelgyro.initialize();

  // verify connection
  Serial.println("Testing device connections...");
  Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  
}

void loop()
{
  accelgyro.getAcceleration(&ax, &ay, &az);
 
  floatData[0] = ax;    //axis x
  floatData[1] = ay;    //axis y
  floatData[2] = az;    //axis z
}

void requestEvent()
{
  byte* Data;
  Float1ArrayPtr = (byte*) &floatData[0];
  Data[0] = Float1ArrayPtr[0]; 
  Data[1] = Float1ArrayPtr[1]; 
  Data[2] = Float1ArrayPtr[2]; 
  Data[3] = Float1ArrayPtr[3]; 
  Float2ArrayPtr = (byte*) &floatData[1];
  Data[4] = Float2ArrayPtr[0];
  Data[5] = Float2ArrayPtr[1];
  Data[6] = Float2ArrayPtr[2];
  Data[7] = Float2ArrayPtr[3];
  Float3ArrayPtr = (byte*) &floatData[2];
  Data[8] = Float3ArrayPtr[0]; 
  Data[9] = Float3ArrayPtr[1]; 
  Data[10] = Float3ArrayPtr[2]; 
  Data[11] = Float3ArrayPtr[3]; 
  Wire.write(Data,12); //Send the 12 bytes (3 floats)
}

He realizado varias pruebas pero no sé donde podría estar el error.

No dices donde esta el fallo ,no funciona como quieres,no compila bien..?si no compila bien pon los errores que te da.

Hola. Me parece que estás un poco perdido, o al menos así me parece, porque si entendieras bien el código del master, lo lógico es que en el esclavo hubieras aplicado la misma táctica. Concretando, el problema que he visto en el código del escavo, concretamente en el requestEvent, es que defines un puntero byte *data que en principio no apunta a ningún sitio, por mucho que luego asignes valores a las posiciones de memoria donde apunta (data[x]=...). Tal vez te funcione cambiando la definición byte *Data por byte Data[12] que no crea un puntero vacío, sino un puntero a una reserva de memoria de 12 bytes. No obstante, me parece que mareas mucho los datos en el sketch del esclavo. Podrías directamente crear una unión como la que usas en el master y leer en ella directamente los valores del gyro. Por cierto, ¿Por qué lees los valores del gyro en variables enteras (ax, ay y az) y luego las pasas a float? ¿Cuál sería el tipo de dato correcto?

Gracias por tu respuesta noter, como mencioné en el comienzo, el código lo tomé del link que dejé, pero creo que me he complicado mucho, lo que yo quería era que el esclavo tomase los datos del sensor y luego, cuando el master lo solicitase, se los diera, pero en otro post que hice en inglés me explicaron que no era posible hacerlo con 3 dispositivos I2C, era mas factible que el master los sacara directamente del sensor, pero no es lo que quería, asi es que ahora estoy trabajando con un sensor análogo.

Aún así, respondiendo a tu última pregunta, lo que yo estaba obteniendo los datos limpios del sensor, luego hay que convertirlos según ciertos requerimiento, por lo que se necesitaría que fuese float, pero como estoy probando el código lo he dejado así.

El problema que estoy teniendo ahora es que el esclavo se pega al enviar información después de x segundo, pero creo que comenzaré desde 0, por ahí vi que hay una forma más practica de pasar información.

Por lo que lei del hilo en inglés si que te has complicado. No hay punto que no criticaran. Como dijiste que vas a comenzar de nuevo. Que tal si vas informando de tu avance?

yo haria algo asi

void loop()
{
 accelgyro.getAcceleration(&ax, &ay, &az);


}

void requestEvent()
{

 Wire.write(ax,2); //Send the 2 bytes (16 bit int)
 Wire.write(ay,2); //Send the 2 bytes (16 bit int)
 Wire.write(az,2); //Send the 2 bytes (16 bit int)
}

y convertiría los datos en el maestro, para no enviar tantos bytes por el I2C

de todas formas por que quieres utilizar I2c? por que dos placas arduino? saludos

Gracias por tu respuesta GO_zalo, estoy usando dos placas, porque una de ellas, la maestra, será un servidor web y la otra estará leyendo constantemente el valor del acelerómetro y escribiéndolo en una SD, cuando intenté hacer todo en el mismo arduino (MEGA), pasado unos minutos este para de enviar información y había que reiniciarlo para que funcionase nuevamente, ya que las llamadas al servidor serán constante.

Con dos Arduinos funciona mucho mejor, ya que se aliviana el trabajo para cada uno de ellos.

Les resumiré las conclusiones que obtuve del tema iniciado en un post en inglés (http://forum.arduino.cc/index.php?topic=273328)

Inicialmente contaba con un acelerómetro que se conectaba vía I2C, por eso es que quería hacer todo por este bus, como no conocía los pro y los contra de utilizarlo, finalmente descarté de usar ese acelerometro, porque lo que necesitaba es que se estuviese leyendo constantemente la información del acelerógrafo, debido a eso, el bus estaría siempre ocupado, lo cual me generaba conflicto, además yo necesitaba escribir en una SD todos los datos del acelerógrafo. Asi es que lo mejor fue adquirir un acelerógrafo análogo, lo que solucionó todos mis problemas.

aquí está el código para el Arduino

Mestro

#include <Wire.h>
int x,y,z;

void setup()
{
  Wire.begin();
  Serial.begin(9600);

}

void loop()
{
  Wire.requestFrom(2, 6);// request 6 bits from address 2

  byte buffer[6];
  for(int i=0;i<6;i++) { 
    buffer[i] = Wire.read();
  }
  x = buffer[1];
  y = buffer[2];
  z = buffer[3];

  //show the data received
  print(x);print("\t");
  print(y);print("\t");
  print(z);println("\t");

  delay(500);
}

Esclavo

#include <Wire.h>

int table[]={0,0,0};
int x,y,z;

void setup()
{
  Serial.begin(9600);

//I2C 
  Wire.begin(2); 
  Wire.onRequest(requestEvent);
}

void loop()
{
  int temporary[3];

  //gets data from accelerometer
  temporary[0] = accelereometerDataX(); //change this for your accelerometer data X
  temporary[1] = accelereometerDataY(); //change this for your accelerometer data Y
  temporary[2] = accelereometerDataZ(); //change this for your accelerometer data Z

  // Disable the interrupts for a short time.
  noInterrupts();
  table[0]=temporary[0];
  table[1]=temporary[1];
  table[2]=temporary[2];
  interrupts();

  //Print data
  Serial.print(table[0]);
  Serial.print('\t');
  Serial.print(table[1]);
  Serial.print('\t');
  Serial.print(table[2]);
  Serial.print('\n');

}

void requestEvent()
{
  Wire.write((const uint8_t *) table,sizeof(table));   
}

Los arduinos siguen interconectados por I2C, pero el acelerógrafo se conecta directamente al esclavo y hace lo que necesito, cuando el master solicita la lectura actual del sensor, este la envía sin problema.