Etiquetas: , , , ,

Puede ser práctico, especialmente en proyectos de automatización del hogar, comunicarse entre varios dispositivos. Una de las técnicas más utilizadas es el protocolo I2C (o TWI). El protocolo I2C es un método que permite conectar varias tarjetas «Maestras» y varias tarjetas «Esclavas» y comunicar hasta 128 dispositivos. Permite conexiones asíncronas entre varios componentes para compartir información a través de un «bus común». Habíamos visto la comunicación a través del puerto serie (llamado UART) que se usa para enviar el código al Arduino por una computadora o para conectar dos dispositivos en particular en Bluetooth.

Equipo

  • Computadora
  • Arduino UNO x2 o más
  • Cable de puente M / M x3 veces el número de tarjetas

Diagrama de conexión del bus I2C entre placas Arduino

Con el protocolo I2C, también es posible comunicarse entre diferentes sistemas (sensores, pantalla LCD, Raspberry Pi, etc.). Un ejemplo interesante es la comunicación entre varias placas Arduino. Para esto, necesitamos escribir al menos dos programas, uno para la tarjeta «Maestra» (Maestro) y el otro para las tarjetas «Esclavos».

Una comunicación I2C se define mediante un bus de dos hilos (a veces llamado TWI, interfaz de dos hilos) y una dirección. Los pines utilizados por la comunicación I2C generalmente son fijos para cada dispositivo. Uno en el que se envían los datos (línea de datos en serie SDA) y en el otro el reloj de sincronización (línea de reloj en serie SLC).

Pines I2C / TWI:

  • Uno, Ethernet A4 (SDA), A5 (SCL)
  • Mega2560 20 (SDA), 21 (SCL)
  • Leonardo 2 (SDA), 3 (SCL)
  • Due 20 (SDA), 21 (SCL), SDA1, SCL1

En este ejemplo utilizamos una placa Arduino Uno, por lo que los pines A4 y A5.

Para que las dos tarjetas se comuniquen entre sí, deben estar conectadas correctamente (A4 con A4 y A5 con A5) y no olvides conectar las tierras (GND) como se muestra en el siguiente diagrama.

Precaución: si los pines A4 y A5 están conectados a los pines de una tarjeta sin alimentación, el código se congelará en el momento de la transmisión.

Generalmente, una tarjeta enviará información (Escritor) y otra la recibirá (Lector).

 

Código de configuración del bus I2C

La biblioteca Wire.h le permite definir fácilmente la comunicación en serie en el bus I2C. Las funciones son similares a la biblioteca en serie.

  • Wire.begin () inicializa la dirección del dispositivo. El argumento de función puede estar vacío para dispositivos maestros
  • Wire.write () le permite enviar bytes.
  • Wire.requestFrom () maneja la función de recepción de solicitud
  • Wire.beginTransmission () comienza a transmitir datos y define el receptor.
  • Wire.endTransmission finaliza la transmisión de datos
  • Wire.onRequest () maneja la función de recepción de solicitud
  • Wire.onRecieve () gestiona la función de recepción de datos

Código de la tarjeta «Master»

#include <Wire.h>

# define I2C_SLAVE1_ADDRESS 11
# define I2C_SLAVE2_ADDRESS 12

#define PAYLOAD_SIZE 2

int n=0;

void setup()
{
  Wire.begin();        
  Serial.begin(9600);  

  Serial.println(F("-------------------------------------I am the Master"));
  delay(1000);

  //Request value of n to slave
  Wire.requestFrom(I2C_SLAVE1_ADDRESS, 1);   
  n = Wire.read(); 
  Serial.print(F("recieved value : "));
  Serial.println(n);

  //Send value 12 to slave
  Wire.beginTransmission(I2C_SLAVE1_ADDRESS); 
  Wire.write(12); 
   Serial.print(F("sending value : "));
  Serial.println(12);              
  Wire.endTransmission();   

  Serial.print(" ");

  //Request value of n to slave after change
  Wire.requestFrom(I2C_SLAVE1_ADDRESS, 1); 
  n = Wire.read();
  Serial.print(F(" new recieved value : "));
  Serial.println(n); 
}


void loop()
{
  delay(100);
}

 

Código de tarjeta «esclavo»

#include <Wire.h>

# define I2C_SLAVE_ADDRESS 11 // 12 pour l'esclave 2 et ainsi de suite

#define PAYLOAD_SIZE 2

void setup()
{
  Wire.begin(I2C_SLAVE_ADDRESS);
  Serial.begin(9600); 
  Serial.println("-------------------------------------I am Slave1");
  delay(1000);               
  Wire.onRequest(requestEvents);
  Wire.onReceive(receiveEvents);
}

void loop(){}

int n = 0;

void requestEvents()
{
  Serial.println(F("---> recieved request"));
  Serial.print(F("sending value : "));
  Serial.println(n);
  Wire.write(n);
}

void receiveEvents(int numBytes)
{  
  Serial.println(F("---> recieved events"));
  n = Wire.read();
  Serial.print(numBytes);
  Serial.println(F("bytes recieved"));
  Serial.print(F("recieved value : "));
  Serial.println(n);
}

 

Abra el monitor en serie de la tarjeta esclava antes que el monitor de la tarjeta maestra.

En el monitor en serie de la tarjeta «Master»:

En el monitor en serie de la tarjeta «Slave 1»:

 

Podemos ver que las dos tarjetas están intercambiando información. Es muy fácil extender este ejemplo a varias placas Arduino (Leonardo, Mini, etc.) adaptando el cableado y la dirección de los componentes en el código «Esclavo».

 

Código para identificar los dispositivos conectados al bus I2C

Una buena prueba para saber si sus dispositivos se comunican bien entre sí es usar el siguiente código (I2CScanner) que devuelve todas las direcciones de los dispositivos conectados a la tarjeta Master.

    #include <Wire.h>
     
     
    void setup()
    {
      Wire.begin();
      Serial.begin(9600);
      while (!Serial);             // Leonardo: wait for serial monitor
      Serial.println(F("\nI2C Scanner"));
    }
     
     
    void loop()
    {
      byte error, address;
      int nDevices;
     
      Serial.println(F("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(F("No I2C devices found\n"));
      else
        Serial.println(F("done\n"));
     
      delay(5000);           // wait 5 seconds for next scan
    }

 

Si tiene dificultades para configurar la comunicación I2C entre diferentes dispositivos, no dude en dejarnos un comentario o contactarnos.

 

Sources

Encuentre otros tutoriales y ejemplos en el generador de código automático
Arquitecto de Código