Dominando la Comunicación I2C con Arduino: Tutorial Práctico
En este tutorial aprenderemos cómo funciona el protocolo de comunicación I2C y también haremos un ejemplo práctico con la placa Arduino y un sensor que usa este protocolo. Puedes ver el siguiente video o leer el tutorial escrito a continuación. El bus de comunicación I2C es muy popular y ampliamente utilizado por muchos dispositivos electrónicos porque se puede implementar fácilmente en muchos diseños electrónicos que requieren comunicación entre un maestro y múltiples dispositivos esclavos o incluso múltiples dispositivos maestros. La fácil implementación viene con el hecho de que solo se requieren dos cables para la comunicación entre hasta casi 128 (112) dispositivos cuando se usa direccionamiento de 7 bits y hasta casi 1024 (1008) dispositivos cuando se usa direccionamiento de 10 bits. ¿Cómo es posible una comunicación entre tantos dispositivos con solo dos cables? Bueno, cada dispositivo tiene un ID preestablecido o una dirección de dispositivo única para que el maestro pueda elegir con qué dispositivos se comunicará. Los dos cables, o líneas, se llaman Reloj Serial (o SCL) y Datos Seriales (o SDA). La línea SCL es la señal de reloj que sincroniza la transferencia de datos entre los dispositivos en el bus I2C y es generada por el dispositivo maestro. La otra línea es la línea SDA que transporta los datos. Las dos líneas son de "drenaje abierto" (open-drain), lo que significa que se necesitan resistencias pull-up conectadas a ellas para que las líneas estén en alto porque los dispositivos en el bus I2C son activos en bajo. Los valores comúnmente usados para las resistencias son de 2K para velocidades más altas alrededor de 400 kbps, a 10K para velocidades más bajas alrededor de 100 kbps. La señal de datos se transfiere en secuencias de 8 bits. Así que después de una condición de inicio especial viene la primera secuencia de 8 bits que indica la dirección del esclavo al que se envían los datos. Después de cada secuencia de 8 bits sigue un bit llamado Acknowledge. Después del primer bit Acknowledge en la mayoría de los casos viene otra secuencia de direccionamiento pero esta vez para los registros internos del dispositivo esclavo. Justo después de las secuencias de direccionamiento siguen las secuencias de datos tantas como sean necesarias hasta que los datos se envíen completamente y termina con una condición de parada especial. Veamos más de cerca estos eventos. La condición de inicio ocurre cuando la línea de datos baja a nivel bajo mientras la línea de reloj aún está en alto. Después de esto el reloj comienza y cada bit de datos se transfiere durante cada pulso de reloj. La secuencia de direccionamiento del dispositivo comienza con el bit más significativo (MSB) primero y termina con el bit menos significativo (LSB) y en realidad está compuesta por 7 bits porque el 8º bit se usa para indicar si el maestro escribirá en el esclavo (lógica baja) o leerá de él (lógica alta). El siguiente bit AKC/NACK es usado por el dispositivo esclavo para indicar si ha recibido correctamente la secuencia previa de bits. En este momento el dispositivo maestro cede el control de la línea SDA al dispositivo esclavo y si el dispositivo esclavo ha recibido correctamente la secuencia anterior, bajará la línea SDA a la condición llamada Acknowledge. Si el esclavo no baja la línea SDA, la condición se llama Not Acknowledge, y significa que no recibió correctamente la secuencia anterior, lo cual puede ser causado por varias razones. Por ejemplo, el esclavo podría estar ocupado, podría no entender los datos o el comando recibido, no puede recibir más datos, etc. En tal caso, el dispositivo maestro decide cómo procederá. Siguiente es el direccionamiento de registros internos. Los registros internos son ubicaciones en la memoria del esclavo que contienen varias informaciones o datos. Por ejemplo, el acelerómetro ADX345 tiene una dirección de dispositivo única y direcciones de registros internos adicionales para los ejes X, Y y Z. Así que si queremos leer los datos del eje X, primero necesitamos enviar la dirección del dispositivo y luego la dirección del registro interno particular para el eje X. Estas direcciones se pueden encontrar en la hoja de datos del sensor. Después del direccionamiento, las secuencias de transferencia de datos comienzan ya sea desde el maestro o el esclavo dependiendo del modo seleccionado en el bit R/W. Después de que los datos se envían completamente, la transferencia terminará con una condición de parada que ocurre cuando la línea SDA pasa de bajo a alto mientras la línea SCL está en alto. Como ejemplo usaré la placa breakout GY-80 que consiste en 5 sensores diferentes y la placa breakout GY-521 que consiste en 3 sensores diferentes. Así que podemos obtener datos de 8 sensores diferentes con solo dos cables con el bus I2C. Puedes conseguir estos componentes en cualquiera de los siguientes sitios: Aquí está cómo conectaremos las placas. El pin de Reloj Serial de la placa Arduino se conectará a los pines de Reloj Serial de las dos placas breakout, lo mismo para los pines de Datos Seriales y alimentaremos las placas con el pin Gnd y el pin 5V de la placa Arduino. Nota aquí no estamos usando resistencias pull-up porque las placas breakout ya las tienen. Ahora, para comunicarnos con estos chips o sensores necesitamos conocer sus direcciones únicas. Podemos encontrarlas en las hojas de datos de los sensores. Para la placa breakout GY-80 tenemos las siguientes 4 direcciones: un hexadecimal 0x53 para el sensor Acelerómetro de 3 ejes, un hexadecimal 0x69 para el Giroscopio de 3 ejes, un hexadecimal 0x1E para el Magnetómetro de 3 ejes y un hexadecimal 0x77 para el sensor Barómetro y Termómetro. Para la placa breakout GY-521 tenemos solo una dirección y esa es un hexadecimal 0x68. También podemos obtener o verificar las direcciones usando el sketch Arduino I2C Scanner que se puede encontrar en el sitio web oficial de Arduino. Así que aquí si subimos y ejecutamos ese sketch, obtendremos las direcciones de los dispositivos conectados en el bus I2C. Número de Parte del Sensor | Dirección I2C Acelerómetro de 3 ejes Analog Devices ADXL345 | 0x53 | Hoja de datos Giroscopio de 3 ejes ST Microelectronics L3G4200D | 0x69 | Hoja de datos Magnetómetro de 3 ejes Honeywell MC5883L | 0x1E | Hoja de datos Barómetro + Termómetro Bosch BMP085 | 0x77 | Hoja de datos Después de haber encontrado las direcciones de los dispositivos también necesitamos encontrar las direcciones de sus registros internos para leer los datos de ellos. Por ejemplo, si queremos leer los datos para el eje X del sensor Acelerómetro de 3 ejes de la placa breakout GY-80, necesitamos encontrar la dirección del registro interno donde se almacenan los datos del eje X. Desde la hoja de datos del sensor, podemos ver que los datos para el eje X están realmente almacenados en dos registros, DATAX0 con una dirección hexadecimal 0x32 y DATAX1 con una dirección hexadecimal 0x33. Ahora hagamos el código que obtendrá los datos para el eje X. Así que usaremos la librería Wire de Arduino que tiene que ser incluida en el sketch. Aquí primero tenemos que definir la dirección del sensor y las dos direcciones de registros internos que encontramos anteriormente. La función Wire.begin() iniciará la librería Wire y también necesitamos iniciar la comunicación serial porque usaremos el Monitor Serial para mostrar los datos del sensor. En el loop() comenzaremos con la función Wire.beginTransmission() que comenzará la transmisión al sensor particular, el Acelerómetro de 3 ejes en nuestro caso. Luego con la función Wire.write() pediremos los datos particulares de los dos registros del eje X. La función Wire.endTransmission() terminará la transmisión y transmitirá los datos de los registros. Ahora con la función Wire.requestFrom() solicitaremos los datos transmitidos o los dos bytes de los dos registros. La función Wire.available() devolverá el número de bytes disponibles para recuperación y si ese número coincide con nuestros bytes solicitados, en nuestro caso 2 bytes, usando la función Wire.read() leeremos los bytes de los dos registros del eje X. Al final imprimiremos los datos en el monitor serial. Aquí están esos datos pero ten en cuenta que estos son datos crudos y se necesita hacer algunas matemáticas para obtener los valores correctos del eje X. Puedes encontrar más detalles para eso en mi próximo tutorial para usar acelerómetros con la placa Arduino porque no quiero sobrecargar este tutorial ya que su objetivo principal era explicar cómo funciona la comunicación I2C de Arduino.Resumen

Cómo Funciona I2C

Protocolo I2C



Ejemplo


Código Arduino I2C
/*
* Cómo funciona el Protocolo de Comunicación I2C - Tutorial Arduino I2C
*
* por Dejan, www.HowToMechatronics.com
* */
#include <Wire.h>
int ADXLAddress = 0x53; // Dirección del dispositivo en la que también está incluido el bit 8 para seleccionar el modo, lectura en este caso.
#define X_Axis_Register_DATAX0 0x32 // Dirección hexadecimal para el registro interno DATAX0.
#define X_Axis_Register_DATAX1 0x33 // Dirección hexadecimal para el registro interno DATAX1.
#define Power_Register 0x2D // Registro de Control de Energía
int X0,X1,X_out;
void setup() {
Wire.begin(); // Inicia la librería Wire
Serial.begin(9600);
delay(100);
// Habilitar medición
Wire.beginTransmission(ADXLAddress);
Wire.write(Power_Register); // Bit D3 Alto para habilitar medición (0000 1000)
Wire.write(8);
Wire.endTransmission();
}
void loop() {
Wire.beginTransmission(ADXLAddress); // Iniciar transmisión al Sensor
//Pedir los registros particulares para datos
Wire.write(X_Axis_Register_DATAX0);
Wire.write(X_Axis_Register_DATAX1);
Wire.endTransmission(); // Termina la transmisión y transmite los datos de los dos registros
Wire.requestFrom(ADXLAddress,2); // Solicita los dos bytes transmitidos de los dos registros
if(Wire.available()<=2) {
// X0 = Wire.read(); // Lee los datos del registro
X1 = Wire.read();
}
Serial.print("X0= ");
Serial.print(X0);
Serial.print(" X1= ");
Serial.println(X1);
}Lenguaje: Arduino (arduino)
Proceso de manufactura
- Integración I2C Fluida entre Arduino y Raspberry Pi 2 para Proyectos IoT con Sensores
- Construye un Monitor de Energía y Registrador de Datos Fiable con Arduino – Guía Paso a Paso
- Registrador de Temperatura y Humedad con Arduino, DHT11 y Ethernet Shield
- Control Arduino UNO desde Python 3 – Envío de Comandos y Demo LED
- Conexión de Arduino a NMEA‑0183: Guía Paso a Paso
- Construye JARVIS v1: Automatización del hogar con Arduino Nano – Tutorial paso a paso
- Domina el Multihilo en Arduino con Protothreading: Tutorial Paso a Paso
- Domine el nRF24L01: Comunicación inalámbrica, integración con Arduino, circuitos y guía de código
- Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino
- Rastreo de orientación con Arduino y acelerómetro ADXL345: Guía paso a paso
- Construye redes Arduino de largo alcance fiables con el módulo HC‑12