Protocolo I2C y Arduino.

i2c hmc5883l

El protocolo I2C (Inter-integrated Circuit) es de uso común en multitud de dispositivos electrónicos y sensores. Permite la comunicación serie entre distintos elementos, por ejemplo, entre un microcontrolador y una pantalla LCD. Te preguntarás qué ventaja puede aportar I2C sobre un enlace serie normal (tipo RS-232). La primera diferencia es que I2C sigue un esquema maestro-esclavo en el que un maestro (por ejemplo, un microcontrolador) puede conectarse a múltiples esclavos (hasta un total de 1008 dispositivos). Otra diferencia es que, al contrario que RS-232, se trata de un protocolo síncrono, lo cuál simplifica bastante la circuitería y evita el uso de componentes adicionales como una UART.

Existen alternativas como SPI (Serial Peripheral Interface) que permiten la interconexión de más de un dispositivo, sin embargo, cada dispositivo que se añade complica el conexionado, ya que, como se ve en el siguiente esquema, se necesita una señal SS (Slave Select) para seleccionar el dispositivo esclavo con el que quiere “hablar”.

SPI on tres dispositivos

A diferencia de SPI, el protocolo I2C sólo necesita dos conexiones comunes con todos los dispositivos esclavos. Una línea llamada SCL para el reloj (recordemos que el protocolo I2C es síncrono) y otra línea llamada SDA para los datos.

Conexion I2C

Para evitar la contención del bus, los dispositivos pueden forzar la línea a nivel bajo, pero nunca a nivel alto. Se evita así que un dispositivo trate de forzar el bus a nivel alto mientras que otro trata de ponerlo a nivel bajo (lo que posiblemente podría dañar algún dispositivo). Las dos resistencias pull-up (Rp) mantienen el bus a nivel alto mientras ningún dispositivo la fuerce a nivel bajo.

A cambio de la simplicidad electrónica, el protocolo de comunicaciones I2C es algo más complejo que el usado por SPI o RS-232. Cómo todos los dispositivos esclavos están conectados a la misma línea de datos, necesitamos un mecanismo para seleccionar a quién van dirigidos los bits que se van a transmitir. Para ello se usan dos tipos de tramas de bits. Las de dirección (address frame) y las tramas de datos (data frames). Sin entrar en mucho detalle, el maestro introduce en el bus la dirección del dispositivo esclavo al que van destinados los datos, y seguidamente va enviando tramas de 8 bits de datos. El flujo de comunicación es el siguiente.

Transferencia de datos I2C

  • Instante S: SDA está a nivel bajo y SCL a nivel alto, lo que indica el inicio de la comunicación. Seguidamente SDA de pone a nivel alto y SCL a nivel bajo.
  • Instante B1: SCL se pone a nivel alto, lo que indica el envío del primer bit de la trama. Es decir se lee del bus de datos cuando SCL está a nivel alto. El proceso se repite en los instantes B2, B3,…, y Bn hasta completar la trama de bits.
  • Instante P: Finalmente un bit de parada indica el final de la trama manteniendo SCL y SDA en alto.

Un ejemplo con HMC5883L

Después de esta introducción teórica al protocolo I2C, veamos un ejemplo práctico de uso con Arduino. Para ello vamos a usar un módulo HMC5883L que es un magnetómetro de tres ejes (o sea, una brújula). El conexionado sería tal y como se puede ver en el esquema siguiente.

Conexión de HMC5883L con arduino

El módulo HMC5883L se alimenta a 3.3V, y en Arduino UNO, el pin 4A se conecta al SDA mientras que el 5A se conecta al SCL del bus I2C del HMC5883L.

El siguiente programa lee los valores enviados por el sensor y los muestra en la consola serie.

 

#include <Wire.h>  //Librería I2C de Arduino
#define address 0x1E //0011110b, Dirección I2C de 7bit del HMC5883

void setup() {
  Serial.begin(9600); // para mostrar las lecturas
  Wire.begin(); // iniciamos bus I2C
  
  // Ponemos HMC5883 en modo de medida continua
  Wire.beginTransmission(address); // seleccionamos la dirección de HMC5883
  Wire.write(0x02); // selección del registro de modo
  Wire.write(0x00); // Modo de medida continua
  Wire.endTransmission();
}

void loop() {
 int x,y,z; //datos de los ejes x,y,z

  // Indicamos al HMC5883L dónde empezar a leer datos
  Wire.beginTransmission(address); // seleccionamos la dirección de HMC5883
  Wire.write(0x03); // Registro 3
  Wire.endTransmission();
  
 
   // Lectura de los datos (dos registros por eje).
  Wire.requestFrom(address, 6);
  if(Wire.available() >= 6){
    x = Wire.read()<<8; // eje x msb
    x |= Wire.read(); // eje x lsb
    z = Wire.read()<<8; // eje z msb
    z |= Wire.read(); // eje z lsb
    y = Wire.read()<<8; // eje y msb
    y |= Wire.read(); // eje y lsb
  }
  
  //Mostrar datos
  Serial.print("x: ");
  Serial.print(x);
  Serial.print("  y: ");
  Serial.print(y);
  Serial.print("  z: ");
  Serial.println(z);
  Serial.flush();
  
  delay(500);

}

En Arduino podemos comunicarnos con un dispositivo I2C mediante la librería Wire. Como se ve en el ejemplo, el uso es sencillo:

  • La función beginTransmission() inicia la comunicación con el dispositivo cuya dirección pasamos como parámetro, en el caso del HMC5883L la dirección es 0X1E.
  • La comunicación finaliza con con endTrasmission().
  • Las funciones read() y write() nos permiten escribir y leer del bus.
  • La función requestFrom() solicita n bytes a un dispositivo. Los parámetros son la dirección del dispositivo y el número de bytes solicitados.
  • Tras la solicitud, podemos comprobar el número de bytes disponibles con la función available().

En la función setup() ponemos el HMC5883L en modo de lectura continua (puedes consultar la hoja de características de HMC883L para saber cuáles son sus modos de funcionamiento y sus registros). En la función loop() vamos obteniendo las lecturas del sensor tal y como se ve en la siguiente captura.

Lecturas HMC5883L

En conclusión, con la librería Wire de Arduino, usar el protocolo I2C para comunicarse con otros dispositivos no tiene ningún misterio, más allá del de conocer las características y el modo de funcionamiento del dispositivo con el que nos estamos conectando.

CompartirShare on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

2 Comentarios en "Protocolo I2C y Arduino."

  1. benito | en | Responder

    y como puedo cambiar el analogico por ejemplo en mi caso utilizo una arduino nano pero lo conecte a A6-scl y A7-sda

    • Alberto García | en | Responder

      Hola Benito,

      Hasta donde yo sé, el hardware interno del atmega para comunicaciones I2C está conectado a los pines A4 y A5 (también en el nano), por lo que no se puede cambiar. Una alternativa es usar una implementación I2C por software como la que hace la librería Software I2C Library: http://playground.arduino.cc/Main/SoftwareI2CLibrary

      Saludos.

Deja un comentario.

Tu dirección de correo no será publicada.


*