Conectar 2 Arduino por I2C

Fecha: 24 mayo, 2018 Autor: JADM en: Arduino

En un principio, para proyectos simples, no parece muy útil. Pero al empezar a explorar la posibilidad de interconectar dos o más placas Arduino entre sí, las alternativas, ocasiones y necesidad de usar este sistema se multiplican muchísimo. Por ejemplo, algunas situaciones en que la interconexión de Arduinos nos permiten saltear problemas de desarrollo. Especialmente porque podremos aprovechar al máximo la capacidad de cada una de las placas que interconectemos, haciéndolas conversar entre ellas para que se presten los recursos.

Falta de memoria

No la tuya, sino la de Arduino. Sketchs extensos o intensivo uso de variables puede hacer directamente que nuestros programas no carguen o que durante la ejecución aparezcan errores productos de la corrupción de la memoria: extraños contenidos en las variabes, funciones que no devuelven los valores esperados, cuelgues diversos…

En estos casos se puede “repartir” el sketch entre dos o más Arduinos, haciendo que uno consulte el resultado de funciones almacenado en el otro o utilizando la EPROM de ambos para almacenar datos que puedan ser consultados por uno u otro cuando se necesiten. Un buen uso de Arduino en estos casos puede producir una diferencia similar a utilizar una PC con un sólo núcleo o una con varios, porque estaremos repartiendo la carga de la ejecución del sketch en varios procesadores e incluso podremos programar procesos que corran en paralelo e independientes de la manera más pura.

Como ejemplo, podríamos utilizar un Arduino para la comunicación con el usuario, controlando un display, teclado y menúes y otro Arduino para que se encargue de relevar estado de sensores y activar o desactivar dispositivos comunicando los datos al otro cuando lo solicite.

Falta de pines, entradas o salidas

En especial cuando usamos Pro Mini o Nano, podemos encontrarnos con que nos resulten insuficientes los pines analógicos o digitales para determinadas funciones. PWM por ejemplo. Sumar Arduinos suma tambien sus puertos I/O permitiéndonos expandir nuestro proyecto todo lo que necesitemos.

Falta de velocidad

Los microcontroladores con que se equipan las placas Arduino son más que suficientes para la mayoría de las aplicaciones para las que fueron planeados, pero no son un Ryzen ni un i7. Aplicaciones complejas pueden funcionar de maravillas pero decepcionarnos un poco con los tiempos de respuesta. Tal como explicaba en el caso de falta de memoria, repartir la carga del sketch entre varios Arduinos mejora notablemente los tiempos de ejecución. La única limitación será la habilidad, creatividad y talento del programador. Y el presupuesto disponible para placas, pero de eso no me voy a ocupar… o sí? Sí, tambien:

Presupuesto

En un proyecto reciente, actual de hecho… en realidad todavía en proceso… por los requerimientos de memoria y pines opté por iniciarlo sobre una Mega cuyo costo en Argentina es de unos u$s 20.- y a poco de avanzar me resultaron insuficientes los puertos de I/O para ciertas funciones. Buscando como saltar el problema, pensé en la conexión I2C con una Pro Mini y de ese modo sumar puertos. Y allí me dí cuenta de que dos placas Pro Mini me daban los recursos necesarios y, a u$s 4.- cada una, a menos de la mitad del costo. Tambien hay que tener en cuenta el mejor aprovechamiento del espacio en el circuito final y por ende, un menor costo en fabricación y materiales de un posible PCB.

Y, la mejor parte: todo esto…

Así de Fácil

La imagen muestra el diagrama de conexión, usando en este caso dos placas Pro Mini, pero sea cual sean las placas a conectar se trata de usar una conexión a masa común (unir los pines GND de las placas y la alimentación), conectar los +5V de la fuente de alimentación a la entrada correspondiente en las placas y, la parte que nos importa, unir el pin SDA de una placa con el SDA de la otra, y el SCL de una con el SCL de la otra.

Para las placas Uno, Pro Mini y Nano, el puerto SDA corresponde al pin A4 y el SCL al pin A5. En las placas Mega y Due el puerto SDA corresponde al pin 20 y el puerto SCL corresponde al pin 21

 

Acá voy a hacer una aclaración importante: este recurso no se limita a interconectar dos placas sino que pueden sumarse tantas placas como sea necesario casi sin límite. Simplemente uniendo todos sus pines SDA por un lado y los SCL por otro. Es más, tambien pueden conectarse de este modo, en la misma línea, otros dispositivos que requieran de interconexión IC2.

Esto es así, porque luego en la programación veremos que cada dispositivo tendrá un identificador único que se utilizará en la comunicación para diferenciarlo de todos los demás. Así, si el dispositivo (o la placa) nro. 1 necesita un dato de la placa (o el dispositivo) nro. 8, enviará la pregunta al dispositivo identificado como “8” y este enviará la respuesta al dispositivo identificado como “1”, permitiendo que las conexiones entre todos viajen por los mismos cables sin confundirse.

A trabajar

Con todo conectado, vamos a escribir un primer sketch para probar el sistema. En realidad, vamos a escribir 2: uno para el Arduino que hará las veces de Master y otro para el que hará de Slave.

Master

 
// la librería encargada de proporcionarnos todos los comandos necesarios para la comunicación I2C
#include <Wire.h>
 
void setup() {
 
    Wire.begin(1); // Iniciamos el bus I2C identificando este dispositivo como 1. En el caso del Master el "1" es opcional y podríamos obtener el mismo resultado escribiendo Wire.begin();
 
}
 
void loop() {
 
    byte x = 0; // definimos x como variable tipo byte (podrá contener un valor entero entre 0 y 255)
 
    Wire.beginTransmission(8); // preparamos el bus para transmitir datos al dispositivo nro. 8
    Wire.write("x es ");        // envía 5 bytes (un caracter = un byte)
    Wire.write(x);              // envía un byte
    Wire.endTransmission();    // finaliza la transmisión
 
    x++;
 
    if (x>255) {
 
        x=0; // si x es mayor a 255 lo volvemos a 0 para no superar los valores permitidos para una variable tipo byte
 
    }
 
    delay(500); // una pausa necesaria para dar tiempo a la transmisión completa
 
}

Slave

#include <Wire.h> // la librería encargada de proporcionarnos todos los comandos necesarios para la comunicación I2C
 
void setup() {
    Wire.begin(8);                // Conectamos al bus I2c identificando a este dispositivo como 8
 
    Wire.onReceive(receiveEvent); // Se registra la función receiveEvent, que será llamada cada vez que se reciba un dato por I2C
    Serial.begin(9600);           // Iniciamos el puerto serie para imprimir la salida por el monitor serie de Arduino
 
}
 
void loop() {
    delay(100); // pausa para esperar la recepción y completar la transmisión de respuestas
}
 
void receiveEvent(int cuantosBytes) {
 
    while (1 < Wire.available()) { // loop para leer todos los bytes recibidos, menos el último
        char c = Wire.read(); // lee un byte recibido y lo convierte a caracter
        Serial.print(c);         // imprime el caracter en el monitor serie
    }
    int x = Wire.read();    // lee un último byte y lo convierte a integer
    Serial.println(x);         // imprime el valor por el monitor serie
 
}

El resultado será algo así:

X es 0

X es 1

X es 2

… nada demasiado útil ni emocionate en sí mismo, pero date cuenta que habrás logrado interconectar y hacer interactuar dos microcontroladores independientes. Master calcula el valor de x y le transmite a  Slave la frase “x es..” y el valor. Slave recibe la frase y se encarga de imprimirla a tu monitor a través del puerto serie.

Con el mismo procedimiento podés hacer que Master envíe órdenes que sean interpretadas y obedecidas por Slave.

Por ejemplo, Master envía “T”. Slave recibe un byte y si ese byte corresponde al caracter “T”, lee el valor del sensor de temperatura y lo devuelve a Master, que lo lee y si es menor a una temperatura predeterminada activa el relé de un calefactor. Ya no es tan inútil, no?

Con un poco de imaginación y talento no te será difícil crear tu propio “protocolo” de comandos para intercambiar órdenes y respuestas entre un Master y un Slave, o varios. Te será muy útil y necesario seguramente aprender o refrescar un poco las bases de la comunicación seríal basada en transmisión de bytes y un poco de sistemas numéricos para ayudarte a transmitir valores mayores a 255 o menores a 0 u otro tipo de datos.

Esa parte, se la dejo a Google.