En este ejemplo voy a explicar de forma muy sencilla cómo podemos conectar dos Arduinos por I2C. Esto puede ser muy útil para conectar por ejemplo un Arduino UNO o MEGA y una Arduino MKR1000.
Si comparamos los precios entre un shield WiFi y un Arduino MKR1000, la diferencia es muy grande. Por lo tanto es más interesante comprar un Arduino MKR1000 y utilizarlo como master. Para que te hagas una idea te voy a explicar como sería el conjunto del sistema.
Indice de contenidos
Esto nos permite, por ejemplo, tener más salidas disponibles disponibles y como, no solo podemos conectar un solo Arduino por I2C, la escalabilidad está asegurada con este protocolo. Antes de continuar veamos a grandes rasgos como funciona la comunicación I2C.
I2C(Inter-Integrated Circuit)
Lo primero hay que decir que estamos hablando de una comunicación estándar. Siempre que oigas esto es algo bueno. Seguramente que organizaciones independientes de los fabricantes velan para que los equipos y dispositivos se puedan entender entre ellos sea cual sea su marca. I2C es una comunicación de este tipo.
Fue diseñado para facilitar la comunicación entre diferentes tipos de dispositivos entre los que se encuentran los microcontroladores.
La comunicación se realiza a través de un bus. Un bus no es más que un cableado al que se conectan dispositivos de una determinada forma. Pero la comunicación no puede ser anárquica, debe seguir las normas que dictamina el protocolo de comunicación, en este caso el I2C.
La primera norma es que debe haber uno o varios maestros (aconsejable utilizar un único maestro por su complejidad) y uno o varios esclavos, hasta 112. Los maestros son los que determinan los tiempos y a que esclavo se dirigen los datos. Los esclavos son los que reciben la señal de reloj y los datos.
Se trata de una comunicación síncrona es decir, el maestro dirá «ehhhhh esclavo 1 aquí van los datos». El esclavo 1 leerá los datos hasta que el maestro diga «ya he terminado de enviarte datos esclavo 1». Así sería la comunicación síncrona de forma muy resumida.
Por otro lado está la señal de reloj. Esto permite sincronizar la comunicación entre los dispositivos conectados al bus y además determinará la velocidad. La velocidad máxima que pueden alcanzar en Arduino es de 100 kbits por segundo. Pongamos un ejemplo. Si una letra se codifica con 8 bits = 1 byte, cada segundo podremos enviar, aproximadamente este texto: hola mundo!!
Lo más importante en la comunicación I2C es conocer las señales es decir, las conexiones que tenemos que hacer en Arduino. Hay 3 señales:
- SCL (Serial Clock Line) Es el reloj del sistema y se utiliza para transmitir los datos de forma sincronizada.
- SDA (Serial Data Line) Es la señal donde viajan los datos del sistema.
- GND (Ground) Es la señal a masa que deben compartir todos los dispositivos conectados al bus.
En el caso de tener varios esclavos deben compartir las líneas de reloj y de datos entre ellas es decir, conectar las señales SDA y SCL juntas. Además, como ya he dicho, todos los dispositivos deben compartir la toma de tierra GND.
Y esto es todo lo que necesitamos saber del I2C.
Conectar dos Arduinos
Ahora llega lo interesante, vamos a conectar dos Arduinos. Es muy simple, solo tenemos que conocer que pin es el SDA y que pin es el SCL puesto que el GND todos lo conocemos. Te dejo a continuación una lista de diferentes modelos con los pines que corresponden a cada señal.
- UNO, PRO MINI -> SDA = A4 y SCL = A5
- MEGA, DUE -> SDA = 20 y SCL = 21
- LEONARDO, YUN -> SDA = 2 y SCL = 3
- MKR1000 -> SDA = 11 y SCL = 12
Como ejemplo voy a conectar dos Arduino UNO. El esquema sería el siguiente.
Como ves es muy simple, solo necesitamos 3 cables y conectar los pines A4, A5 y GND. Vamos a probar algo un poco más complejo. Incorporemos al esclavo 5 LEDs que manejaremos desde el maestro.
Código
Vamos a tener que cargar dos códigos, un código al que hace de master y otro código al que hace de esclavo (slave). En los dos casos haremos uso de la librería Wire, que nos proporcionará todos los métodos y propiedades para poder utilizar el protocolo I2C de una forma sencilla.
Empecemos con el código del master. El objetivo de la aplicación es encender los LEDs conectados a los pines 0, 1, 2, 3, 4 con un retardo de un segundo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
/* Programarfacil https://programarfacil.com Autor: Luis del Valle @ldelvalleh Comunicación I2C entre dos Arduinos, maestro */ #include <Wire.h> void setup() { // Unimos este dispositivo al bus I2C Wire.begin(); } byte pin[] = {2, 3, 4, 5, 6}; byte estado = 0; void loop() { for (int i = 0; i < 5; i++) { // Comenzamos la transmisión al dispositivo 1 Wire.beginTransmission(1); // Enviamos un byte, será el pin a encender Wire.write(pin[i]); // Enviamos un byte, L pondrá en estado bajo y H en estado alto Wire.write(estado); // Paramos la transmisión Wire.endTransmission(); // Esperamos 1 segundo delay(1000); } // Cambiamos el estado if (estado == 0) { estado = 1; } else { estado = 0; } } |
El código del esclavo es diferente. Lo primero que hay que destacar es que tendremos un evento que se disparará cuando reciba un dato del dispositivo master. La primera parte leerá un entero (int) y la segunda parte leerá un carácter (char). Dependiendo de si el carácter es H o L pondrá en estado alto (H) o bajo (L).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
/* Programarfacil https://programarfacil.com Autor: Luis del Valle @ldelvalleh Comunicación I2C entre dos Arduinos, esclavo */ #include <Wire.h> void setup() { // Pines en modo salida pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); pinMode(6, OUTPUT); // Unimos este dispositivo al bus I2C con dirección 1 Wire.begin(1); // Registramos el evento al recibir datos Wire.onReceive(receiveEvent); // Iniciamos el monitor serie para monitorear la comunicación Serial.begin(9600); } void loop() { delay(300); } // Función que se ejecuta siempre que se reciben datos del master // siempre que en el master se ejecute la sentencia endTransmission // recibirá toda la información que hayamos pasado a través de la sentencia Wire.write void receiveEvent(int howMany) { int pinOut = 0; int estado = 0; // Si hay dos bytes disponibles if (Wire.available() == 2) { // Leemos el primero que será el pin pinOut = Wire.read(); Serial.print("LED "); Serial.println(pinOut); } // Si hay un byte disponible if (Wire.available() == 1) { estado = Wire.read(); Serial.print("Estado "); Serial.println(estado); } // Activamos/desactivamos salida digitalWrite(pinOut,estado); } |
Y esto es todo. Si quieres replicarlo con otros modelos sería exactamente igual teniendo en cuenta los pines correspondientes al SDA y SCL.