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.
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.
La 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
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
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
Salida de monitor en serie del esclavo
https://youtu.be/gqsVMZrlEUQ
Debe estar conectado para enviar un comentario.