Ir al contenido principal

Protocolo I2C y Arduino.

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.

I2C
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 en 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.

Comentarios

Entradas populares de este blog

Creando firmas de virus para ClamAV

ClamAv es un antivirus opensource y multiplataforma creado por Tomasz Kojm muy utilizado en los servidores de correo Linux. Este antivirus es desarrollado por la comunidad, y su utilidad práctica depende de que su base de datos de firmas sea lo suficientemente grande y actualizado. Para ello es necesario que voluntarios contribuyan activamente aportando firmas. El presente artículo pretende describir de manera sencilla cómo crear firmas de virus para ClamAV y contribuir con ellas a la comunidad.

Ingeniería inversa de un parche de Microsoft Windows

A estas alturas ya hemos asumido que la seguridad total en Internet es, cuanto menos, un mito. Ningún software está libre de vulnerabilidades, y por mucha auditoría, test de intrusión o pruebas de fuzzing que nos empeñemos en hacer, ninguna metodología puede demostrar sin lugar a dudas que un software es 100% seguro. Ante este panorama, hay dos tendencias mayoritarias a la hora de hacer públicas las vulnerabilidades. Por un lado, están los que piensan que cuando se descubre un fallo ha de hacerse público de forma inmediata. En este escenario, la publicación de una vulnerabilidad es el pistoletazo de salida para una carrera entre el desarrollador para sacar el parche y los "malos" para lograr explotarla. Esta política es conocida como full disclosure . Por otro lado, tenemos a los siguen una política responsible disclosure , que abogan por mantener la vulnerabilidad en secreto hasta la salida del parche por parte del desarrollador. Sin entrar en cuestiones filosóficas que no...

Manejo de grafos con NetworkX en Python

El aprendizaje computacional es un área de investigación que en los últimos años ha tenido un auge importante, sobre todo gracias al aprendizaje profundo (Deep Learning). Pero no todo son redes neuronales. Paralelamente a estas técnicas, más bien basadas en el aprendizaje de patrones, también hay un auge de otras técnicas, digamos, más basadas en el aprendizaje simbólico. Si echamos la vista algunos años atrás, podemos considerar que quizá, la promesa de la web semántica como gran base de conocimiento ha fracasado, pero no es tan así. Ha ido transmutándose y evolucionando hacia bases de conocimiento basadas en ontologías a partir de las cuales es posible obtener nuevo conocimiento. Es lo que llamamos razonamiento automático y empresas como Google ya lo utilizan para ofrecerte información adicional sobre tus búsquedas. Ellos lo llaman Grafos de Conocimiento o Knowledge Graphs . Gracias a estos grafos de conocimiento, Google puede ofrecerte información adicional sobre tu búsqueda, ad...