conexión i2c Arduino

Conexión i2C entre modelos de Arduino diferentes y voltajes diferentes. i2C entre Arduinos diferentes

En ocasiones es necesario conectar, para enviar/recibir información, Arduinos de voltajes diferentes y por tanto modelos de Arduinos diferentes. En esta entrada vamos a explicar como conectar dos Arduinos de 3.3V a uno de 5.0V. Es decir, vamos a enviar información de dos Arduinos Nano 33 IoT a un Arduino Mega 2560 (puede ser otro Arduino de 5.0V, por ejemplo un UNO). Para ello necesitaremos: cables, una placa protoboard, dos resistencias de 4.0 KOhms, un Level Shifter y evidentemente los tres Arduinos a interconectar. Las resistencias son en conexión Pull-Up. También se explica en que consiste la conexión i2C y que ventajas e inconvenientes.

 

¿Porqué el bus I2C?

Una de las ventajas del bus I2C respecto al puerto serie UART o bus SPI, es la gran cantidad de dispositivos comerciales que disponen de conexión en I2C, además de la gran cantidad de dispositivos que se pueden conectar a un Arduino (hasta 127).

El bus I2C significa Inter-Integrated Circuit y fue desarrollado por Phillips en 1982. El I2C requiere de como mínimo dos cables, uno para la señal de reloj (CLK) y otro para el envío de datos (SDA). Normalmente se requiere de un tercer cable para la interconexión de las tierras (GND).

Cada dispositivo conectado al Arduino dispone de una única dirección y dicha dirección viene determinada por el fabricante del dispositivo o modificado vía software.

El bus I2C tiene una estructura maestro-esclavo. Estos términos están siendo reemplazados por ser políticamente incorrectos. Ahora se habla de principal-secundario, líder-seguidor o emisor-receptor. 

El maestro es quien inicia la comunicación y los esclavos responden o simplemente reciben datos. Además los esclavos no hablan entre ellos directamente. Además, es posible disponer de más de un maestro y uno o varios esclavos. 

 

Comunicación síncrona

A diferencia de otros protocolos de comunicación, la comunicación mediante el protocolo I2C es síncrona. Es decir, a señal de reloj es común para todos los dispositivos y oscila entre un valor alto y bajo a un ritmo determinado. Este ritmo hace de compás, permitiendo transmitir un bit durante los niveles altos de la señal de reloj. 

 

Ventajas y desventajas

Como en casi todos los aspectos de la vida, el protocolo I2C tiene ciertas ventajas y ciertos inconvenientes que hay que sopesar. 

Las ventajas son :

  • Teóricamente requiere de pocos cables. Luego veremos que existen excepciones.
  • Dispone de mecanismos para verificar que la señal ha llegado.
  • Elevado número de dispositivos a conectar. 

Las desventajas:

  • La velocidad de comunicación es media-baja.
  • No es full-dúplex, es decir, no envía y recibe datos simultáneamente.
  • No hay verificación de que el contenido del mensaje es correcto. 
  • El I2C sólo se puede emplear para rangos de comunicación de muy pocos centímetros, entre 20 y 30 cm solamente. 
  • No se pueden enviar paquetes de más de 32 bytes. Por lo que es posible mandar mensajes muy largos.

Nota: Puede suceder (no siempre), que en arquitecturas SAMD ARM la comunicación produzca errores al trabajar como esclavo. 

 

La librería Wire.h y las resistencias Pull-Up

La librería Wire viene por defecto en el IDE estándar de Arduino. Pero hay que saber que es necesario instalar resistencias externas del tipo pull-up cuando intercambiamos información entre Arduinos con voltajes y modelos distintos.

La librería Wire.h utiliza por defecto resistencias internas del tipo pull-up. Eso es porque el protocolo I2C prevé el empleo de resistencias internas pull-up en las líneas de voltaje (Vcc) de alimentación con valores de 20 a 30 k. Esto puede resultar demasiado blando para algunos proyectos, por lo que los flancos de subida de la señal serán menos rápidas. Para corregir dicha situación que puede dar errores, se suele emplear resistencias externas en pull-up de 1 a 4 k. 

 

Escáner de direcciones

Una forma fácil. de conocer las direcciones de los dispositivos conectados en el bus I2C es un código llamado «scanner I2C». ¿Porqué? Pues no todos los fabricantes facilitan las direcciones. La dirección es algo parecido al concepto de la IP en las redes de ordenadores.

// https://playground.arduino.cc/Main/I2cScanner/
#include <Wire.h>

void setup()
{
  Wire.begin();
 
  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}
 
 
void loop()
{
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknown error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
 
  delay(5000);           // wait 5 seconds for next scan
}

 

¿Porqué necesitamos un protocolo?

Imaginemos que de forma casera quisiéramos enviar el número 10 de un Arduino a otro Arduino. Una forma sencilla de hacerlo sería convertir el 10 en código binario, es decir el 1010. Entonces mediante el digital write y el digital read enviaríamos y recibiríamos sólo altos y bajos. Es decir, por un lado convertiríamos el 10 a binario, lo enviaríamos y en el otro extremo (en otro Arduino) lo reconstruiríamos pasándolo de binario a decimal. 

Esto que parece fácil, no lo es si por ejemplo queremos enviar el número 127 de un Arduino a otro Arduino. El 127 es en binario el 1111111, es decir, siete veces un uno. En otras palabras, siete veces un HIGH. Entonces, la pregunta principal es: ¿cómo interpreta el otro Arduino (el receptor) que no es un único 1? Hay varias maneras de hacerlo, pero una de las formas es empleando el tiempo, es decir, el reloj. Después quedan otras preguntas por responder, imaginemos que el Arduino que envía, manda el 1010, pero el Arduino receptor empieza a leer tarde y recibe el 010. Finalmente, ¿cómo enviamos datos a la vez a más de un dispositivo? 

En fin, todo lo anterior y más hace necesario de un protocolo estándar de comunicación que sea fiable, seguro y rápido. 

 

Diferencias entre comunicación serie y protocolo I2C

Hay varias diferencias fundamentales entre UART e I2C

UART

  • Tipo de comunicación: asíncrona
  • Complejidad del Hardware: Poca (2 cables + GND)
  • Número de másteres: no hay
  • Reloj: Cada dispositivo tiene el suyo
  • Dispositivos a interconectar: Sólo el transmisor y receptor. Es decir dos. 

I2C

  • Tipo de comunicación: síncrona
  • Complejidad del Hardware: Puede ser grande si hay varios maestro/esclavos y si se necesita de un level shifter.
  • Número de másteres: uno o varios.
  • Reloj: Señal común entre los esclavos y másteres. 
  • Dispositivos a interconectar: hasta 127 dispositivos. 

 

Velocidad del reloj

Por defecto la velocidad del reloj es de 100 kHz pero se puede incrementar hasta los 400 kHz con la función de la libraría Wire llamada «setClock()». Este incremento, aumenta cuatro veces la velocidad de comunicación haciendo también más probable la transmisión de datos erróneos. 

 

Código propio del maestro y del esclavo

Algo siempre muy interesante es identificar el código del maestro y del esclavo fácilmente de manera que podamos reconocer quién hace de maestro y quien de esclavo.

 

El maestro: Éstas son funciones típicas de maestro.

Wire.begin(); //Con los paréntesis vacíos (no parámetro).
Wire.beginTransmision(address); //Tiene como parámetro la dirección a la que se destina el mensaje.
Wire.endTransmision(); //Finaliza la transmisión de datos del maestro.
Wire.requestFrom(); //Solicita datos a los esclavos.

 

El esclavo: Éstas son funciones típicas de esclavo.

Wire.begin(Address); //Tiene como parámetro la dirección. Escucha la dirección indicada.
Wire.onReceive(función); //Lo que debe hacer el esclavo al recibir datos del maestro.
Wire.onRequest(); //Lo que hará el esclavo cuando se reciban los datos del maestro.

 

El protocolo

Para finalizar explicaremos brevemente y secuencialmente que hace éste protocolo.

  1. Arranca el protocolo con un bit de inicio que es un cero.
  2. Arranca el reloj.
  3. Se envía la dirección hexadecimal convertida a binario de siete bits. Nota: en el código veremos algo cómo esto: «I2C_SLAVE_ADDR = 0x20;». Este 0x20 es la dirección en hexadecimal que luego el protocolo convierte a binario de siete bits.
  4. Se le pide al esclavo si debe leer o escribir. Un 1 es lectura y un 0 es escritura.
  5. Luego se manda un bit de confirmación. En donde el 0 es un OK y un 1 es un error.
  6. Posteriormente se manda la dirección de memoria. 
  7. Después se envía propiamente todos los bits de datos.
  8. Finalmente se manda un bit de validación. 

 

Comunicación entre uno o varios Arduino

El Arduino Nano 33 IoT trabaja a 3.3V. Si le quisiéramos conectar un dispositivo que proporcionara un voltaje superior, casi seguro que dañaríamos la placa. 

Luego, los pines A4 y A5 tienen un pull-up interno y están diseñados para usarse como bus I2C. Por lo tanto, no se recomienda el uso de A4 y A5 como entradas analógicas.

Hay que saber que si queremos comunicar un Arduino Nano 33 IoT a un MEGA 2560 que trabaja a 5V hay que hacer algo. Si mandamos directamente una señal a un MEGA de menos de 5V probablemente no reconozca la señal y de error, o no haya ningún tipo de comunicación. Al revés, si mandamos una señal de un MEGA a un NANO 33 IoT probablemente dañemos la placa. Por esta razón hay que poner un intermediario, es decir, un «Level Shifter».

Un adaptador de nivel o «level shifter» es un dispositivo electrónico (muy económico) que permite convertir señales lógicas de distintos niveles de tensión. Lo que hace es pasar la señal de 3.3V a 5V y al revés, puesto que suelen ser bidireccionales.

 

level shifter Arduino
Level shifter o Adaptador de Nivel

 

 


 

Más información

Deseamos que te haya gustado este post de «i2C entre Arduinos diferentes». Si deseas más información sobre cómo programar en Arduino consulta en la web oficial de Arduino. Para cualquier otra consulta, puedes contactar con nosotros. También nos puedes ayudar escribiendo un comentario y descargando nuestra APP de Servicios Profesionales, freelancers y autónomos.

Leave a Comment

Your email address will not be published. Required fields are marked *

Información básica sobre protección de datos
Responsable Francisco de Asís Benavente Delgado +info...
Finalidad Gestionar y moderar tus comentarios. +info...
Legitimación Consentimiento del interesado. +info...
Destinatarios No se cederán datos a terceros, salvo obligación legal +info...
Derechos Acceder, rectificar y cancelar los datos, así como otros derechos. +info...
Información adicional Puedes consultar la información adicional y detallada sobre protección de datos en nuestra página de política de privacidad.