Librerías I2C que entran en conflicto

Hola, buenas tardes.

En un proyecto que tengo en mente ahora mismo empleo dos chips (concretamente el RTC DS1307 y el acelerómetro+giróscopo MPU6500). Ambos chips comunican con mi Arduino UNO para aportarle información externa. El problema viene a la hora de escribir el código. Sé de buena tinta (por haber usado cada uno por separado) que ambas librerías preestablecen que los pines SDA y SCL se comunican con los pines analógicos A4 y A5 de Arduino.

A la hora de utilizar ambos chips en el mismo código... ¿No supondrá esto un conflicto? ¿Cómo puedo hacer para poder llevar a cabo la comunicación con ambos elementos?

Gracias por adelantado.

Arduino-Tiny-RTC-I2C-modules-24C32-memory-DS1307-clock.jpg


mpu-6050.jpg
 
si las dos librerias usan rutinas identicas pues si puede haber problema, tal vez tengas que modificar las librerias y revisar que no halla etiquetas y rutinas repetidas
 
La única forma de que haya conflicto es que los 2 esclavos i2c (el RTC y el mpu) tengan la misma dirección, cosa que no creo que pase.
I2C es un bus, está preparado para poder conectarse con hasta 127 esclavos (7 bits, la dirección 0x00 está reservada creo, también hay direccionamiento con 10 bits) .
Otro problema que podría haber es que un esclavo trabaje con 5V, el otro con 3V3; si el VCC es el mismo para todos entonces no te preocupes por eso.

La lógica de trabajo sería seleccionar un esclavo (indicando su dirección), hacer las operaciones de lectura/escritura que precises; luego seleccionar el otro esclavo, leer/escribir; y así.

No tengo experiencia con Arduino, pero buscando un rato no dudo en que puedas encontrar ejemplos multi-esclavo.
 
Una vez leo del RTC inicio una funcion en la que unicamente entra en juego el MPU. Por tanto no tendria problema en eso de jugar con los tiempos de escritura/lectura de cada esclavo.

Las librerías que usan son las siguientes:

- Para el RTC: Librería Wire.h
- Para el MPU: Librería I2Cdevlib
 
Ah ya veo... tu pregunta es si esas 2 librerías se pueden usar a la par sin generar conflicto (es decir, que si estoy leyendo algo usando la librería i2cdevlib no quede una transacción pendiente que me impida acceder al rtc usando la librería wire).
Eso ya depende de como esté implementado i2cdevlib, si trabaja con interrupciones, si las funciones de lectura/escritura son síncronas/asíncronas o bloqueantes/no bloqueantes.

Viendo el código fuente mpu6050.cpp veo que las funciones que usa son
i2cdev::writebit(s)/readbit(s)/writebyte(s)/readbyte(s)
y esas funciones según veo en i2cdev.cpp son todas bloqueantes, es decir, al llamarlas se comunica con el esclavo i2c, solicita escritura/lectura de datos, y espera a que la transacción se termine antes de retornar.
Entonces en principio no deberías tener problema de usar la i2cdevlib a la par de wire.h

Pero también me parecería más seguro tratar de hacer todo con i2cdevlib (no mezclar una librería de bajo nivel como wire con una de más alto nivel como i2cdevlib).
Entonces por un lado usa las funciones para el mpu, y por el otro lado las funciones i2cdev::
Código:
static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data);
static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data);
para leer/escribir registros del rtc.
De esa forma te olvidas del begintransmission, endtransmission, hacer lectura/escritura de bytes individuales; todas cosas que ya resuelve i2cdevlib.
 
Muchas gracias, Ardogan. Esa era una de mis dudas sobre los conflictos.
La otra duda es, si ahora empleo la librería i2cdevlib para ambos dispositivos, ¿cómo hago para seleccionar uno u otro a la hora de leer bytes de información?
 
Con el parámetro devaddr en las funciones que puse arriba. Esa es la dirección del esclavo i2c.
Son funciones para trabajar con registros de los esclavos. Lo que se especifica en los argumentos es dirección I2C del esclavo, dirección del registro a leer/escribir, y dato o puntero a buffer (desde donde se recibe/envía información)
Pero como dije, para el mpu usa directamente las funciones para leer aceleración/dirección/etc (porque para hacer algo de eso hay que acceder a múltiples registros, y leer decenas de páginas de la hoja de datos del mpu, y depurar, y...).

PERO NO HAGAS CASO A LO DE ARRIBA

Recién ahora veo que i2cdevlib también tiene una librería hecha para el ds1307

Entonces para leer datos de tu programa bastaría con algo como (no tengo experiencia con Arduino, tomalo con pinzas):

Código:
//Ver ejemplo RTC: https://github.com/jrowberg/i2cdevlib/blob/master/Arduino/DS1307/Examples/DS1307_tick/DS1307_tick.ino
//Ver ejemplo mpu6050: https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/MPU6050/Examples

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#include "Wire.h"
// I2Cdev and DS1307 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "DS1307.h"
#include "MPU6050.h"

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// but this device only supports one I2C address (0x68)
DS1307 rtc;
uint16_t year;
uint8_t month, day, dow, hours, minutes, seconds;

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
//MPU6050 accelgyro;
MPU6050 accelgyro(0x69); // <-- use for AD0 high

int16_t ax, ay, az;
int16_t gx, gy, gz;

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    Wire.begin();
    
    rtc.initialize();
    accelgyro.initialize();

    rtc.setDateTime24(2014, 9, 06, 9, 40, 0);    //le damos fecha y hora inicial al RTC

}

void loop() {
    // read raw accel/gyro measurements from device
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

    //Listo, ya tenes la información cruda del mpu6050 en esas variables
    //resto de tu programa... no se que querrás hacer con esos datos

    //Luego en alguna parte querés leer fecha y hora:
    rtc.getDateTime24(&year, &month, &day, &hours, &minutes, &seconds);

}
Aaaahhhh, ya veo donde viene el problema, el mpu6050 tiene dirección i2c 0x68 igual (!!!) que la dirección i2c del RTC.
La dirección del RTC no se puede cambiar, pero la del mpu6050 si se puede cambiar si la pata AD0 se pone a VCC.

Pero hay otro problema!!!!. El mpu6050 trabaja a 3.3V, el RTC a 5V, y el arduino uno a 5V. Entonces no se puede conectar AD0 a +5V, tiene que ser a 3.3V (podrías soldar ese terminal a algún punto interno de la placa donde haya 3.3V, yo elegiría el positivo del capacitor de tantalio) (si no queres meterle soldador a la placa del mpu, podes hacer un divisor de tensión con los 5V del arduino uno, con 2.5V debería alcanzar: 2 resistores iguales).

Vas a precisar un traductor de nivel (voltage translator, o I2C level shifter) entre el mpu6050 y el resto:
http://playground.arduino.cc/Main/I2CBi-directionalLevelShifter
http://playground.arduino.cc/Main/MPU-6050

Se complico la cosa... ley de Murphy :rolleyes:
 
Última edición:
No, en eso no hay problema. Arduino tiene dos patillas de alimentación para suministrar 5 V y 3.3 V, respectivamente.

¿Cómo se relacionan las direcciones I2C con los diferentes pines analógicos que tiene Arduino? Perdón, supongo que igual es un pregunta demasiado básica pero es que no tengo ni idea de I2C...
 
No, en eso no hay problema. Arduino tiene dos patillas de alimentación para suministrar 5 V y 3.3 V, respectivamente.
Lamentablemente, sí, hay problema. No me refería a la alimentación (la placa del mpu6050 ya trae un regulador de 3v3) sino a las líneas de señal: cuando el arduino maneja las líneas de reloj y datos del I2C, para él un '1' va a ser = 5V; y esos 5V se van a aplicar directamente a la pata del mpu6050, que soporta máximo 3,3V (en cualquiera de sus patas).

Y por lo que veo del esquemático, los 5V se conectan directamente a la alimentación del atmega328:
http://arduino.cc/en/uploads/Main/arduino-uno-schematic.pdf
buo2JLREAEREAERCBnAkujVOXcSWq7CIiACIiACIjA8AksxfTf8LtBLRQBERABERABEcidgJSq3HtQ7RcBERABERABERgEASlVg+gGNUIEREAEREAERCB3AlKqcu9BtV8EREAEREAERGAQBKRUDaIb1AgREAEREAEREIHcCUipyr0H1X4REAEREAEREIFBEJBSNYhuUCNEQAREQAREQARyJyClKvceVPtFQAREQAREQAQGQUBK1SC6QY0QAREQAREQARHInYCUqtx7UO0XAREQAREQAREYBAEpVYPoBjVCBERABERABEQgdwJSqnLvQbVfBERABERABERgEASkVA2iG9QIERABERABERCB3AlIqcq9B9V+ERABERABERCBQRCQUjWIblAjREAEREAEREAEcicgpSr3HlT7RUAEREAEREAEBkFAStUgukGNEAEREAEREAERyJ2AlKrce1DtFwEREAEREAERGAQBKVWD6AY1QgREQAREQAREIHcCUqpy70G1XwREQAREQAREYBAEpFQNohvUCBEQAREQAREQgdwJSKnKvQfVfhEQAREQAREQgUEQkFI1iG5QI0RABERABERAWzw7OgAAAqhJREFUBHInIKUq9x5U+0VABERABERABAZBQErVILpBjRABERABERABEcidgJSq3HtQ7RcBERABERABERgEASlVg+gGNUIEREAEREAERCB3AlKqcu9BtV8EREAEREAERGAQBKRUDaIb1AgREAEREAEREIHcCUipyr0H1X4REAEREAEREIFBEJBSNYhuUCNEQAREQAREQARyJyClKvceVPtFQAREQAREQAQGQUBK1SC6QY0QAREQAREQARHInYCUqtx7UO0XAREQAREQAREYBAEpVYPoBjVCBERABERABEQgdwJSqnLvQbVfBERABERABERgEASkVA2iG9QIERABERABERCB3AlIqcq9B9V+ERABERABERCBQRCQUjWIblAjREAEREAEREAEcicgpSr3HlT7RUAEREAEREAEBkFAStUgukGNEAEREAEREAERyJ2AlKrce1DtFwEREAEREAERGAQBKVWD6AY1QgREQAREQAREIHcCUqpy70G1XwREQAREQAREYBAEpFQNohvUCBEQAREQAREQgdwJSKnKvQfVfhEQAREQAREQgUEQkFI1iG5QI0RABERABERABHInIKUq9x5U+0VABERABERABAZBQErVILpBjRABERABERABEcidgJSq3HtQ7RcBERABERABERgEASlVg+gGNUIEREAEREAERCB3AlKqcu9BtV8EREAEREAERGAQBKRUDaIb1AgREAEREAEREIHcCUipyr0H1X4REAEREAEREIFBEJBSNYhuUCNEQAREQAREQARyJyClKvceVPtFQAREQAREQAQGQUBK1SC6QY0QAREQAREQARHInYCUqtx7UO0XAREQAREQAREYBAEpVYPoBjVCBERABERABEQgdwJSqnLvQbVfBERABERABERgEAT+DyLmSurRX5pDAAAAAElFTkSuQmCC

Eso es una pena... hubieran puesto un jumper que permita seleccionar alimentar al micro con 3.3V o 5V y ese problema no existiría.
Quizás me equivoco, quizás se pueda hacer que la linea de 5V trabaje con 3.3V porque el atmega puede trabajar a baja tensión.... acá vi esto (reemplaza regulador para hacer trabajar arduino a 3v3):
https://learn.adafruit.com/arduino-tips-tricks-and-techniques/3-3v-conversion

Pero aun haciendo eso todavía está el tema de que el RTC trabaja a 5V, prrrrfffff.
Me mantengo en lo que dije, solución = trasladar tensión del bus i2c:
http://www.nxp.com/documents/application_note/AN10441.pdf
https://learn.sparkfun.com/tutorials/using-the-logic-level-converter

¿Cómo se relacionan las direcciones I2C con los diferentes pines analógicos que tiene Arduino? Perdón, supongo que igual es un pregunta demasiado básica pero es que no tengo ni idea de I2C...

Te sugiero buscar algún tutorial. i2c requiere solo dos pines. Todas las transacciones i2c las inicia un maestro (el arduino). Una transacción puede ser de lectura o escritura. Se transmite 1ro la dirección del esclavo más 1 bit indicando lectura/escritura... en fin, es largo y ya hay mucha información al respecto, a buscar!!!:
https://learn.sparkfun.com/tutorials/i2c
 
Atrás
Arriba