Comunicación I2C en Arduino

Conexión de dos Arduinos utilizando bus I2C.

La comunicación I2C (Inter-Integrated Circuit) es un protocolo de comunicación serie síncrono muy popular en la electrónica, especialmente en dispositivos embebidos y microcontroladores como los que se encuentran en las distintas placas de Arduino. Fue desarrollado por Philips Semiconductor (ahora NXP Semiconductors) en la década de los 80 y es utilizado para la comunicación entre dispositivos. Permitiendo que múltiples periféricos se conecten al microcontrolador utilizando solo dos pines. De esta forma, I2C se destaca por su simplicidad y eficiencia.

Hardware necesario

  • Dos placas Arduino
  • Dos resistencias de 4,7 kΩ
  • Cables de conexión
  • Protoboard

Características del I2C

Los protocolos de comunicación síncrona se caracterizan por enviar la señal de reloj junto a la señal de datos. En este caso, se utilizan dos líneas para la comunicación:

  1. SDA (Serial Data Line): Es la línea de datos que transmite la información entre los dispositivos.

  2. SCL (Serial Clock Line): Es la línea de reloj que sincroniza la transferencia de datos entre los dispositivos.

Esquema de bus I2C.

En un bus I2C, siempre hay un dispositivo maestro que controla la comunicación y uno o más dispositivos esclavos que responden a las solicitudes del maestro. Cada dispositivo esclavo tiene una dirección única de 7 o 10 bits que lo identifica en el bus I2C. Esto permite que el maestro se comunique con un dispositivo específico. Todos los dispositivos se conectan al mismo bus de datos lo que permite la comunicación con muchos dispositivos utilizando sólo dos pines de la placa.

Información

La dirección de los dispositivos es común que pueda cambiarse. En algunos casos se puede cambiar mediante software modificando un registro. En otros casos se puede modificar mediante hardware ya sea a través de interruptores, jumpers o soldaduras.

I2C en Arduino

Arduino incluye soporte para I2C en la mayoría de sus placas, lo que facilita la comunicación con sensores, pantallas y otros dispositivos. Las placas Arduino como la Uno, Mega y Nano utilizan los siguientes pines para la comunicación I2C:

Placa SDA SCL SDA1 SCL1 SDA2 SCL2
UNO SDA/A4 SCL/A5
Nano A4 A5
MKR D11 D12
GIGA D20 D21 D102 D101 D9 D8
Mega y Due D20 D21
Información

Los pines marcados como SCL y SDA en las versiones UNO R3 son los mismos A4 y A5, están conectados en la misma placa por razones de compatibilidad con los nuevos Shields. Es indistinto conectarlo en unos o en otros. O sea, son los mismos pines en dos posiciones distintas. De esta forma al igual que si los utilizaras para I2C, puedes usarlos como pines analógicos siempre que no los estés usando para I2C.

Ejemplo de comunicación entre dos UNO

Arduino proporciona la librería Wire para trabajar con I2C. Esta librería permite configurar el dispositivo como maestro o esclavo y enviar/recibir datos de manera sencilla.

Supongamos que queremos establecer una comunicación entre dos placas Arduino. Una actuará como maestro y otra como esclavo. En este ejemplo, el maestro enviará un mensaje al esclavo, y este lo responderá.

El esquema de conexión es muy sencillo sólo debemos conectar los pines SDA y SCL de cada arduino y agregarles una resistencia de pull-up. Además debemos conectar los pines GND de cada placa para tener la misma referencia.

Esquema de conexión de dos Arduinos utilizando bus I2C.
Advertencia

Nunca olvides conectar los pines GND de las dos placas Arduino.

Código para el Arduino maestro

 1// Ejemplo de Arduino para utilizar bus i2c - master 
 2// Más información: https://www.3dpellet.com
 3
 4#include <Wire.h>
 5
 6void setup() {
 7  Wire.begin();       // unirse al bus i2c (la dirección es opcional para el maestro)
 8  Serial.begin(9600); // iniciar la comunicación serial para la salida
 9}
10
11void loop() {
12  Wire.requestFrom(8, 6);    // solicitar 6 bytes del dispositivo periférico #8
13
14  while (Wire.available()) { // el periférico puede enviar menos de lo solicitado
15    char c = Wire.read();    // recibir un byte como carácter
16    Serial.print(c);         // imprimir el carácter
17  }
18
19  delay(500);
20}

Código para el Arduino esclavo

 1// Ejemplo de Arduino para utilizar bus i2c - slave 
 2// Más información: https://www.3dpellet.com
 3
 4#include <Wire.h>
 5
 6void setup() {
 7  Wire.begin(8);                // unirse al bus i2c con la dirección #8
 8  Wire.onRequest(requestEvent); // registrar el evento
 9}
10
11void loop() {
12  delay(100);
13}
14
15// función que se ejecuta cada vez que el maestro solicita datos
16// esta función está registrada como un evento, ver setup()
17void requestEvent() {
18  Wire.write("hello "); // responder con un mensaje de 6 bytes
19  // como se espera en el maestro
20}

Consejos al trabajar con I2C

  1. Resistencias pull-up: Las líneas SDA y SCL necesitan resistencias pull-up para funcionar correctamente. En plataformas como Arduino, es común omitir estos componentes físicos, ya que la biblioteca Wire habilita automáticamente resistencias internas integradas en el microcontrolador, pero en proyectos externos es común usar valores de 4.7kΩ o 10kΩ.

  2. Evita direcciones en conflicto: Asegúrate de que los dispositivos en el bus tengan direcciones I2C únicas. Consulta la hoja de datos del dispositivo para más información.

  3. Longitud de los cables: Mantén los cables lo más cortos posible para evitar problemas de capacitancia y ruido.

Información

El uso de resistencias de elevación con valores elevados (llamadas “débiles”) provoca que las transiciones de bajo a alto en la señal (flanco de subida) sean más lentas. Esto limita la velocidad máxima de comunicación y reduce la distancia operativa confiable entre dispositivos. Para optimizar el rendimiento en aplicaciones que requieren mayor velocidad de transferencia o conexiones más extensas, se sugiere incorporar resistencias externas con valores inferiores, generalmente entre 1 kΩ y 4.7 kΩ. Estas permiten una transición más rápida de la señal, mejorando la integridad y alcance de la comunicación.

Conclusión

I2C es una interfaz poderosa y sencilla que facilita la comunicación entre dispositivos electrónicos, especialmente en proyectos con Arduino. Su implementación mediante la librería Wire permite un desarrollo rápido y efectivo, haciendo que esta tecnología sea indispensable.