Arduino + Protocolo Bus I2C

El protocolo de comunicación I2C, es un bus de comunicación sincrono que se diseño para comunicar circuitos integrados en una distancia corta (20cm aprox), su siglas en ingles significan Inter-Integrated Circuit, este bus solo posee dos lineas de comunicación, SDA y SCL, En este bus existen 2 integrantes maestros o esclavos, pero solo puede existir un maestro a la vez. donde el maestro es quien administra el bus, puede enviar y recibir datos de cualquier esclavo, mientras el esclavo solo envía y recibe datos al maestro.

  • SDA, Serial Data: en esta linea de comunicación se envía y reciben los bits de información de datos.
  • SCL, Serial Clock: Es la señal de sincronía el cual permite la lectura y escritura en el bus.

Este bus se pueden conectar varios dispositivos pues estos se diferencian en el bus por la dirección de estos, el maestro envía la cadena de transmisión con la dirección del dispositivo para cual va dirigido el mensaje, se observa mucho en los display lcd, los giroscopios, los potenciometros digitales, las arduino, etc.

la dirección de los dispositivo es dada por el fabricante, esta dirección tiene un tamaño de 7 bits, pero también la puedes modificar desde el hardware o mediante software, la mayoría es por hardware pues cada dispositivo se trae unos jumpers o pines que se puentean a tierra para cambiar los 3 últimos bits de dirección, se identifican como A0,A1,A2, ya que si tenemos por ejemplo 2 displays lcd con modulo I2C debemos cambiar la dirección de alguno de ellos, en este protocolo se puede se compuesto hasta por 112 dispositivos, aunque según las direcciones nos da un total de 128, pero el protocolo se reserva 16 direcciones para funciones especiales.

Trama de transmisión de datos

Envió de datos del Maestro al dispositivo esclavo:

  1. Se inicia la transmisión con el bit de inicio que es un 0.
  2. Seguido se envía los 7 bits de la dirección del esclavo seguido, del bit de escritura y lectura (W/R), donde se escribirá en el bus si es 0 y si es 1 leerá del bus (sera 0).
  3. Luego de enviar la dirección del esclavo a cual van dirigidos los datos junto con el bit de w/r, el esclavo que tiene esta dirección envía un bit de validación ACK, que esta listo para leer.
  4. Luego del que maestro valida el ACK, enviara los datos en 8 bits (1 byte), si se envían mas datos el maestro envía un NACK, el cual es un bit de validación, que se usa cuando el maestro no quiera enviar/recibir mas datos.
  5. Y por ultimo esta el bit de para que da por terminada la transacción.

Envió de datos del esclavo al dispositivo maestro:

  1. Se inicia la transmisión con el bit de inicio que es un 0.
  2. Seguido se envía los 7 bits de la dirección del esclavo seguido, del bit de escritura y lectura (W/R), donde se escribirá en el bus si es 0 y si es 1 leerá del bus,( sera 1).
  3. Luego de enviar la dirección del esclavo a cual van dirigidos los datos junto con el bit de w/r, el esclavo que tiene esta dirección envía un bit de validación ACK, que esta listo para escribir.
  4. Seguido el esclavo enviara los datos en tramas de 8bits.
  5. El maestro enviara activo el NACK cuando ya no quiera mas datos.
  6. Y por ultimo esta el bit de para que da por terminada la transacción.

y nuestras tarjetas arduino manejan este protocolo de Bus, con la librería wire.h, donde los pines  SDA y SCL son:

A las lineas SDA y SCL se le agrega una resistencia pull-up a vcc, esto permite mejorar la calidad de la comunicación.

Funciones de la librería wire.h:

  • begin(dirección); se escribe Wire.begin(7 bits de dirección), si no se especifica se asume como maestro, y con esta función se inicia la librería se agrega en el setup().
  • Wire.requestFrom(dirección,numero de bytes), esta función nos permite hacer un requerimiento de cuantos bytes son requeridos, de una dirección especifica.
  • Wire.beginTransmission(direccion); inicia la transmisión a un esclavo de la dirección especifica.
  • Wire.endTransmission(dirección); termina la transmisión al esclavo con el cual se inicio anteriormente con Wire.beginTransmission().
  • Wire.write(dato), con esta función enviamos información al esclavo, y se escribe entre las funciones Wire.beginTransmission() y Wire.endTransmission().
  • Wire.available(), esta funcion nos da el numero de bytes que estan en el bus esperando ser leidos, esta debe ser llamada despues de un Wire.requestFrom() o un Wire.onReceiver().
  • Wire.read(), recibe los byte enviados por el esclavo, se escribe depues del Wire.requestFrom().
  • Wire.setClock(frecuencia), esta funcion nos permite cambiar la velocidad de transmission de los datos, pues cambia la velocidad de SCL, por defecto esta 100KHz, pero este valor depende de la velocidad que soportan los dispositivos.
  • Wire.onReceive(numero de bytes), esta funcion permite al esclavo recibir una cantidad de bytes del maestro.
  • Wire.onRequest(), esta funcion es usada cuando en algun instante el maestro requiere un dato del esclavo.

Extra: si tienes un dispositivo que tiene bus I2C y desconoces su dirección puedes cargarle el siguiente código al arduino con tu dispositivo esclavo conectado y abres el monitor serial y te dará la dirección del dispositivo esclavo conectado, este código solo sirve con direcciones de 7 bits.

// --------------------------------------
// i2c_scanner
//Este codigo solo sirve para dispositivos con 7 bits de direccion
//
 
#include <Wire.h>
 
void setup()
{
  Wire.begin();
 
  Serial.begin(9600);
  while (!Serial);             // Leonardo: espera por monitor serial
  Serial.println("\nI2C Scanner");
}
 
 
void loop()
{ //variables
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print("Dispositivo I2C fue encontrado en la direccion 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Error desconocido en la direccion 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("Dispositivo I2C no fue econtrado\n");
  else
    Serial.println("Hecho.\n");
 
  delay(5000);           // espera 5 segundos para el siguiente scaneo
}

Espero que sea del máximo provecho para usted, no olvides seguirme en las redes sociales y suscribirte a mi canal de YouTube.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *