BUS I2C/TWI, su uso con Arduino

Introducción al BUS I2C también conocido como TWI

I2C (Inter-Integrated Circuit) es un protocolo de conexión de interfaz de bus serie. También se le llama TWI (Two Wire Interface) ya que utiliza sólo dos cables para la comunicación. Estos dos cables son SDA (datos en serie) y SCL (reloj serie).

I2C es un protocolo de comunicación basado en el acuse de recibo, es decir, el transmisor comprueba si el receptor envía un acuse de recibo después de transmitir los datos para saber si los datos son recibidos por el receptor correctamente.

I2C funciona en dos modos, a saber,

  • Modo maestro
  • Modo esclavo

El cable SDA (datos en serie) se utiliza para el intercambio de datos entre el dispositivo maestro y el esclavo.

SCL (reloj serial) se utiliza para el reloj síncrono entre el dispositivo maestro y el esclavo.

El dispositivo maestro inicia la comunicación con un dispositivo esclavo. Requiere la dirección de un dispositivo esclavo para iniciar la conversación. El dispositivo esclavo responde a un dispositivo maestro cuando es direccionado por un dispositivo maestro.

El dispositivo I2C tiene una dirección única de 7 o 10 bits. Por lo tanto, para acceder a estos dispositivos, un maestro debe direccionarlos mediante la dirección única de 7 o 10 bits.

I2C se utiliza en muchas aplicaciones como la lectura de RTC (reloj en tiempo real), el acceso a la memoria externa EEPROM. También se utiliza en módulos de sensores como giroscopios, magnetómetros, etc.

El protocolo I2C utiliza 2 líneas de comunicación:

  • Reloj serial (SCL): Es una señal de reloj. Los datos se enviarán a otros dispositivos en el evento de marcación de reloj. Sólo el dispositivo maestro tiene control sobre esta línea SCL.
  • Datos en serie (SDA): Es una línea de datos en serie que se utiliza para el intercambio de datos entre el dispositivo maestro y el esclavo.

scl sda

El bus I2C es una configuración de drenaje abierto, lo que significa que pueden bajar la línea de señal correspondiente pero no pueden hacerla subir. Por lo tanto, la línea entrará en estado desconocido. Para evitar esto, las resistencias de tracción deben conectarse a las clavijas SCL y SDA.

Pines Arduino I2C

La placa Arduino Uno tiene un pin I2C que se muestra en la imagen de abajo.

arduino pinsLa placa Arduino Uno sólo tiene un módulo I2C, pero proporciona estas líneas SDA y SCL en dos ubicaciones diferentes.
Al comunicarse con dispositivos que utilizan el protocolo de comunicación I2C, se deben utilizar resistencias pull-up. El valor de las resistencias pull-up puede variar dependiendo de los dispositivos utilizados.

Funciones I2C para Arduino

Wire.write (data)

Se utiliza para escribir (transmitir) datos al dispositivo maestro o esclavo.

Parameter

data puede ser un valor de byte único, cadena, matriz de datos.

Returns

Número de bytes escritos.

Wire.write(7); //send data byte

Wire.write(“i2c”); //send string to slave device

Wire.write(a, 6); //here a is an array

Wire.available()

Esta función es utilizada por un maestro o un esclavo para comprobar si los datos solicitados están disponibles o no. Devuelve el número de bytes disponibles.

Wire.read()

Permite leer los datos solicitados por el maestro del esclavo o leer los datos transmitidos de un maestro a un esclavo.

Funciones para el Maestro Arduino I2C

Cada dispositivo esclavo I2C tiene una dirección única. Mientras se comunica usando el protocolo I2C, esta dirección de esclavo debe ser usada por el Maestro.

Arduino tiene una Wire Library que nos permite comunicarnos con dispositivos I2C.

Wire.begin ()

Inicia la biblioteca Wire y se une al bus como maestro.

Wire.beginTransmission (slave address)

Esta función inicia una transmisión con el dispositivo esclavo I2C con una dirección de esclavo especificada.

slave address Dirección de 7 bits del dispositivo con el que queremos comunicarnos.

por ejemplo Wire.beginTransmisión (50) //comienza la transmisión con el esclavo con dirección 50

Wire. requestFrom(address, no of byte) o Wire. requestFrom(address, no of byte, stop)

Esta función es utilizada por el maestro para solicitar o recibir datos del dispositivo esclavo. Los datos solicitados pueden ser leídos usando Wire.read().

Parametros

Address dirección del dispositivo con el que queremos comunicarnos
No. of byte número de bytes que necesita solicitar
Stop

Es un booleano.

true – envía un mensaje de parada después de la solicitud, liberando el autobús,

false – envía continuamente un reinicio después de la petición, manteniendo la conexión activa

Returns

Número de bytes devueltos desde el dispositivo esclavo.

Wire.requestFrom(50, 4) //request 4 nº de bytes del esclavo con dirección 50

Wire.requestFrom(50, 4, true) // dejará de recibir datos después de 4 bytes, liberando el bus

Wire.endTransmission()

Finaliza una transmisión a un dispositivo esclavo que fue iniciado por beginTransmission() y transmite los bytes que estaban en cola por write().

Returns

Byte de retorno que indica el estado de la transmisión

Funciones para Arduino I2C Slave

Wire.begin (address)

Inicia la librería Wire y se une al bus I2C como un esclavo con dirección especificada.

Parametro

Address

Dirección del esclavo de 7 bits, si no se especifica, unirse al bus como maestro

Wire.onReceive(handler)

La función handler a la que se debe llamar cuando un dispositivo esclavo recibe datos transmitidos de un maestro.

Ejemplo:

void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output
}
void receiveEvent (int howmany){
while (1 < Wire.available()) { // loop through all but the last
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
}

Wire.onRequest (handler)

Función handler a la que se debe llamar cuando el maestro lo solicita desde el dispositivo esclavo, no toma ningún parámetro y no devuelve nada.

Por ejemplo:

void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
}
void loop() {
delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup ()
void requestEvent() {
Wire.write("hello "); // respond with message of 6 bytes
// as expected by master
}

Diagrama de interfaz

Comunicación I2C entre dos Arduino

Comunicación I2C entre dos Arduino

Transferir datos desde el equipo maestro al esclavo. Aquí usaremos dos Arduino, uno como maestro y otro como esclavo.

Usaremos el ejemplo incorporado de la librería Wire proporcionado por Arduino junto con su IDE para la comunicación I2C.

Desde la librería Wire, estamos usando aquí master_writer para Arduino como maestro y slave_receiver para Arduino como esclavo. Este ejemplo transferirá el número de maestro a esclavo y el esclavo lo mostrará en un monitor serial.

Puede utilizar esta biblioteca desde

File -> Examples -> Wire -> master_writer

File -> Examples -> Wire -> master_receiver

Sketch para Arduino como maestro escritor

// Wire Master Writer
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Writes data to an I2C/TWI slave device
// Refer to the "Wire Slave Receiver" example for use with this

// Created 29 March 2006

// This example code is in the public domain.

#include <Wire.h>

void setup() {
Wire.begin(); // join i2c bus (address optional for master)
}

byte x = 0;

void loop() {
Wire.beginTransmission(8); // transmit to device #8
Wire.write("x is "); // sends five bytes
Wire.write(x); // sends one byte
Wire.endTransmission(); // stop transmitting

x++;
delay(500);
}

Sketch para Arduino como receptor esclavo

// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.

#include <Wire.h>

void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output
}

void loop() {
delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
while (1 < Wire.available()) { // loop through all but the last
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}

Salida de monitor en serie del esclavo

Slave’s Serial Monitor Output

Comunicación bidireccional entre dos Arduino usando I2C

Escribamos un programa donde enviaremos un mensaje de Hola al esclavo y el esclavo responderá al mensaje recibido con Hola. Dos Arduino Unos se usan como maestro y esclavo.

Sketch para el Maestro

#include <Wire.h>

void setup() {
Serial.begin(9600); /* begin serial comm. */
Wire.begin(); /* join i2c bus as master */
Serial.println("I am I2C Master");
}

void loop() {
Wire.beginTransmission(8); /* begin with device address 8 */
Wire.write("Hello Slave"); /* sends hello string */
Wire.endTransmission(); /* stop transmitting */

Wire.requestFrom(8, 9); /* request & read data of size 9 from slave */
while(Wire.available()){
char c = Wire.read();/* read data received from slave */
Serial.print(c);
}
Serial.println();
delay(1000);
}

Sketch para el esclavo

#include <Wire.h>

void setup() {
Wire.begin(8); /* join i2c bus with address 8 */
Wire.onReceive(receiveEvent); /* register receive event */
Wire.onRequest(requestEvent); /* register request event */
Serial.begin(9600); /* start serial comm. */
Serial.println("I am I2C Slave");
}

void loop() {
delay(100);
}

// function that executes whenever data is received from master
void receiveEvent(int howMany) {
while (0 <Wire.available()) {
char c = Wire.read(); /* receive byte as a character */
Serial.print(c); /* print the character */
}
Serial.println(); /* to newline */
}

// function that executes whenever data is requested from master
void requestEvent() {
Wire.write("Hi Master"); /*send string on request */
}

Salida de Monitor Serial del Maestro

Master Serial Monitor Output

Salida de monitor en serie del esclavo

Slave Serial Monitor Output

Pin It on Pinterest

Shares