Comunicacion I2C entre Arduinos.

Antes que nada hay que explicar:

¿Que es Arduino?

Arduino es una plataforma de hardware libre, basada en una placa con un microcontrolador y un entorno de desarrollo, diseñada para facilitar el uso de la electrónica en proyectos multidisciplinarios.

¿Que es I²C?

El bus I²C, un estándar que facilita la comunicación entre microcontroladores, memorias y otros dispositivos con cierto nivel de “inteligencia”, sólo requiere de dos líneas de señal y un común o masa. Fue diseñado a este efecto por Philips y permite el intercambio de información entre muchos dispositivos a una velocidad aceptable, de unos 100 Kbits por segundo. La metodología de comunicación de datos del bus I²C es en serie y sincrónica. Una de las señales del bus marca el tiempo (pulsos de reloj) y la otra se utiliza para intercambiar datos.

Mas tarde subiremos una entrada explicando exactamente que es cada cosa. Por ahora basta con tener un Arduino y saber que es una placa de desarrollo electrónico por medio de programación, y que el I²C es un protocolo de comunicación serie entre microcontroladores, un maestro y hasta 127 esclavos conectados a la misma linea de datos.

En esta entrada vamos a hacer una pequeña introducción rápida de uso de este protocolo para la comunicación entre estas maravillosas placas. Vamos a realizar dos ejemplos, uno en que el Maestro enviá una petición a un Esclavo y muestra la respuesta por el puerto serie del IDE Arduino, una cadena de caracteres, y el segundo ejemplo el Maestro va a enviar un dato a un Esclavo, y sea lo que sea este le devolverá la lectura de un pin analógico para que el Maestro lo imprima por el puerto serie del IDE Arduino. En próximas entradas seguro habrá mas ejercicios con este protocolo.

Conexiones

Para poder empezar a comunicar a los Arduino entre si, primero hay que cablearlos, para que los bit’s fluyan! En nuestro caso contamos con un Arduino Nano y un Arduino Uno, y hemos decidido usar el Nano como Maestro (o Master) por comodidad para cablear desde el protoboard con el Arduino Uno, por ende el Uno es el Esclavo (o Slave).

La conexión es muy sencilla y solo hace falta enlazar con cables los pines A4 y A5 (serian las entradas Analógicas de la placa) del Maestro con los mismos pines del Esclavo, osea A4 con A4 y A5 con A5. Y obviamente un tercer cable de GND o masa. Lo hacemos de la siguiente manera:

Conexión de dos arduinos, arduino nano y arduino uno por medio de protocolo serial I2C

En este conexionado es indistinto cual es el Maestro o el Esclavo. También hay que apreciar que el Arduino Uno también necesita una alimentación, que es brindada por el Arduino Nano, y este a su vez es alimentado por medio de la conexión USB, por eso el cable GND es acompañado por uno de 5V.

Si vos tenes un Arduinos Mega la conexión es distinta ya que el pin SDA es el pin 20 y se conecta con el A4 de los Arduinos con atmega328, y SCL es el pin 21 y va conectado con el pin A5 de los Arduinos con atmega328. Por otros Arduinos consulta la pagina oficial de Arduino.

Ejercicio 1:

Como primer ejercicio vamos a establecer al Arduino Nano como Maestro, y este va a solicitar una respuesta de 12 bytes  (una “request”) al Esclavo numero 1, recordemos que podemos tener un montón de Esclavos. Y el Esclavo le va a responder, en este caso una cadena de caracteres, como se ve en la siguiente imagen:

Captura del IDE Arduino, imprimiendo la informacion serial.
Captura del IDE Arduino, imprimiendo la información serial.
El programa que hay que cargar en el Maestro (en este caso el Nano) es el siguiente:
  1. #include <Wire.h>                // Incluimos la librería de comunicación I2C
  2. void setup()                   // Secuencia de configuración, solo se ejecuta una vez
  3. {
  4. Wire.begin();              // Iniciamos la comunicación I2C, en el maestro la dirección no es obligatoria
  5. Serial.begin(9600);       // Iniciamos la comunicación por el puerto serie para mostrar los datos
  6. }
  7. void loop()              // Secuencia en bucle, se repite una y otra vez
  8. {
  9. Wire.requestFrom(1, 12);  // Manda una petición al esclavo numero 1 de 12 bytes
  10. while(Wire.available())  // Mientras tengamos datos en el buffer seguimos leyendo
  11. {
  12. char Datos = Wire.read(); // Leemos un byte y lo pasamos a una variable de tipo char
  13. Serial.print(Datos);     // Lo mostramos en el puerto serie (esto es un bucle donde van llegando uno por uno cada carácter y se van imprimiendo por el serial)
  14. }
  15. delay(1500);        // Esperamos 1,5 segundos para que sea posible ver las respuestas
  16. Serial.println();  // Imprimimos una nueva linea, sino la respuestas van a ir pegadas
  17. }

O podes descargar el sketch desde ACA.

El programa que hay que cargar en el Esclavo (en este caso el Uno) es el siguiente:
  1. #include <Wire.h>
  2. void setup()
  3. {
  4. Wire.begin(1);                                // Nos añadimos al bus como esclavo, con la dirección 1
  5. Wire.onRequest(requestEvent); // Registro de eventos
  6. }
  7. void loop()
  8. {
  9. delay(100);                    // retraso de 100 mili-segundos
  10. }
  11. void requestEvent()      // Función que se ejecuta cuando recibe una petición desde el maestro
  12. {
  13. Wire.write(“Hola maestro”);   // Responde a la petición del maestro de enviarle 12 bytes
  14. }

O podes descargar el sketch desde ACA.

Ejercicio 2:

Bueno hasta acá fue fácil, ahora vamos a realizar el siguiente ejemplo donde ya dijimos que vamos a hacer que  el Maestro envié un dato a un Esclavo, y sea lo que sea este le devolverá la lectura de un pin analógico para que el Maestro lo imprima por el puerto serie del IDE Arduino. En este caso hicimos que la lectura del pin analógico A0 se corresponda a la división de tensión entre un LDR y una resistencia de 1KΩ (Marrón-Negro-Rojo), como se ve en el siguiente esquema de conexión:

Fotometro I2C con dos Arduinos.
Lectura analógica I2C con dos Arduinos.

El esquema anterior fácilmente podría ser una especie de “fotómetro”  si no fuera porque los LDR’s son tan poco precisos. Pero este mismo ejemplo podría servir con un LM35 y tener un termómetro I²C.

El programa que hay que cargar en el Maestro (en este caso el Nano) es el siguiente:
  1. #include <Wire.h>              //Incluimos la librería i2c
  2. void setup()
  3. {
  4.   Wire.begin();               //Iniciamos el bus I2C
  5.   Serial.begin(9600);         //Iniciamos el Serial a 9600 baudios
  6. }
  7. void loop()
  8. {
  9.   unsigned int lectura;
  10.   Wire.beginTransmission(1);  // Enviamos a la dirección del esclavo 1
  11.   Wire.write(1);              // Enviamos un 1
  12.   Wire.endTransmission();     // Terminamos la transmisión
  13.   delayMicroseconds(100);     // Esperamos para poder hacer visibles los datos (posiblemente no haga falta en otras circunstancias)
  14. Wire.requestFrom(1, 1);     // Pedimos 1 bytes al esclavo 1
  15. while(Wire.available())     // Mientras tengamos datos en la entrada
  16. {
  17. lectura = Wire.read();    // Leemos el resultado y lo asignamos a la variable lectura
  18. }
  19. Serial.println(lectura);    // Imprimimos la lectura en el serial (podría ser un lcd también)
  20. delay(500);                 // Damos un tiempo de refresco
  21. }

O podes descargar el sketch desde ACA.

El programa que hay que cargar en el Esclavo (en este caso el Uno) es el siguiente:
  1. #include <Wire.h>                     // Incluimos la librería i2c
  2. unsigned int lectura=0;            // Establecemos una variable entera global, y la seteamos en cero
  3. void setup()
  4. {
  5.   Wire.begin(1);                          // Nos asignamos el numero 1 como esclavos (de ser maestro va vacio esto)
  6.   Serial.begin(9600);                 // Iniciamos el serial 9600 baudios, para testear
  7.   Wire.onRequest(respuestaEvento);  // Al activarse el evento de peticion, se ejecuta la función respuestaEvento
  8.   Wire.onReceive(recibidoEvento);   // Al activarse el evento de lectura, se ejecuta la funcion recibidoEvento
  9. }
  10. void loop()
  11. {
  12.  lectura = analogRead(A0)/4;     // La variable global es igual a la lectura de A0 dividido en 4 para que entre en un byte (0 a 255)
  13. delay(100);                                    // Damos un respiro
  14. }
  15. void respuestaEvento()               // Evento de peticion se activa cuando un master nos pide que le enviemos algún dato
  16. {
  17. Wire.write(lectura);                      // Enviamos el resultado de la lectura al maestro que lo solicito
  18. Serial.println(lectura);                // Enviamos el resultado por el puerto serie para testear
  19. }
  20. void recibidoEvento(int recepcion)  // Evento de recepción
  21. {
  22. unsigned int pedido;
  23. while( Wire.available())             // Leemos hasta que no haya datos, osea el 1 que va a enviar el maestro
  24. {
  25. pedido = Wire.read();                  // Leemos el 1
  26. Serial.println(pedido);               // Imprimimos el 1 por serial para testear
  27. }
  28. }

O podes descargar el sketch desde ACA.

Acá podemos ver los dos programas corriendo, y como cada uno enviá a su respectivo puerto serial la información que se le programo, en el caso del Maestro solo nos enviá la respuesta del Esclavo (lo que se ve en la consola USB0), y el esclavo nos enviá la pregunta hecha por el Maestro (el 1 que se ve en la consola ACM7) seguido del valor leído en el pin A0.

Captura de los IDE's Arduinos del Maestro y el Esclavo trabajando juntos por I2C y Serial RS-232
Captura de los IDE’s Arduinos del Maestro y el Esclavo trabajando juntos por I2C y Serial RS-232

El valor que imprime el Maestro, que a su vez le envió el Esclavo, va desde el 0 hasta el 255, osea 256 valores. Por eso si el pin A0 se pone a GND leeríamos 0, y si se pone a VCC leeríamos 255:

Galeria de Imagenes:

Anuncios

9 comentarios sobre “Comunicacion I2C entre Arduinos.

  1. Gracias por los ejemplos y las explicaciones. Dos apuntes: ¿No son necesarias dos resistencias de pull-up en los pines de datos?
    Por otro lado, falta en el esquema Frtizing la conexión del divisor de tensión al pin analógico A0.

    Gracias de nuevo y saludos.

    1. Buenas! Así es, faltan las resistencias, increíble que me lo halla olvidado, pero anduvo así!
      En Frtizing si que no las pude dibujar, no se porque pero cada vez que ponía mas de una R se cerraba el programa 😦

      1. Gracias por responder. Cierto es que en otros tutoriales no las jncluyen. Necesitaba tus ejemplos para una llave electrónica con un Nano en el que éste activa a otro Arduino al conectar ambos por USB, pidiéndole una clave o similar.

        Gracias de nuevo y saludos.

  2. Hola. Es estupendo¡¡¡. ¿como conseguiriamos comunicarnos con un circuito integrado cuya direccion la elegimos nosotros? Me refiero a integraos tipo i2c para display etc… gracias !!!!

    1. Buenas noches, en principio es muy parecido. Cuando haces un request pasas el valor de la dirección que tenga el chip esclavo. Habría que leer la hoja de datos del chip para ver qué “pedidos” le tenés que hacer. Si me decís que estás haciendo trataría de ayudarte.

  3. Hola que distancia máxima podrían tener de separación los arduinos?

    Que sección de cable recomiendas para una distancia de 10 metros por ejemplo?

    La idea que tengo es domotizar una planta de mi casa, tres dormitorios y baño. Pero para no cambiar el cableado usaría esta programación metiendo un arduino en cada estancia.

    Gracias

    1. Buenas tardes. El i2c es un protocolo de comunicación intra placa. Osea para comunicar integrados dentro de la placa. No se recomienda una distancia mayor a 50cm. Para domótica el protocolo de comunicación tiene que ser inmune al ruido eléctrico y con largas distancias. Por fortuna existe y se llama rs-485. Para usarlo con un arduino es necesaria una capa física, para adaptar el puerto serie. Todavía no hice ningún tutorial sobre rs-485 pero si varios trabajadores. Si necesitas ayuda estoy a disposición.

      1. Entonces tendría q comunicarlos por rs485. Estoy intentando modificar el programa para mandar palabras o frases desde el maestro y que actúe o responda el esclavo, pero me da error la configuración del esclavo.

        Podría comunicarlos por Bluetooth o WiFi?

  4. Más que palabras tendrías que enviar un carácter nomas, o un número. Es más eficiente. Podrías usar WiFi, lo más económico que hay son los ESP8266. Esos módulos originalmente eran modems para conectar un microcontrolador a una red wifi, pero hay modulos ESP8266 como el ESP-07 o el ESP-12e que los podés programar directamente y aprovechar su gran cantidad de pones y periféricos. Si querés empezar te recomiendo los clones de una placa llamada NodeMCU, yo uso un clon marca lolin.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s