I²C – Wire en Arduino
Para utilizar el bus I²C hay un premisa que se puede resumir en “uno escribe y el resto leen”.
Su nombre proviene de Inter-Integrated Circuit y fue creado originalmente por Philips Semiconductors en 1982 y publicada la especificación para su uso por otros fabricantes en 1992.
Consiste en un bus de 2 líneas (Reloj y Datos) por el que viajan paquetes de bits (8 en el caso de Arduino). Para diferenciar cada uno de los dispositivos, en Arduino, se utilizan 7bit (eso significa que puede haber hasta 127 dispositivos diferentes) siendo el último bit el que determina si el maestro va va a escribir o leer en el bus. La hoja de características del dispositivo que conectemos nos dirá cuál es la dirección del mismo y si es necesario enviar comandos así como el formato de los datos que nos dará dicho dispositivo, en Arduino utilizaremos la librería Wire nos facilitará enormemente la tarea.
Arduino Uno tiene las 2 líneas del BUS en los pines A4 y A5:
- A5: SCL (línea del reloj).
- A4: SDA (línea para los datos en serie).
Cuando se quiera utilizar la librería Wire, en nuestros programas hay que añadir un fichero antes de la función setup():
1 |
#include <Wire.h> |
Y dentro de la función setup() hay que inicializar la comunicación en el puerto, como parámetro se introducirá el número (entre 1 y 127) que usaremos como esclavo. Si no se proporciona ningún número, el Arduino será el maestro del bus I²C.
1 |
Wire.begin(direccion); //entre 1 y 127, vacío para ser Maestro |
Desde este momento se pueden usar las funciones correspondientes al I²C:
1 2 3 4 5 6 7 8 |
requestFrom() beginTransmission() endTransmission() write() available() read() onReceive() onRequest() |
Se recomienda visitar la web oficial de la librería Wire de Arduino.
Para los 2 siguientes ejemplos (se encuentran en el menú Wire de los ejemplos de Arduino IDE) se requieren 2 Arduinos pues uno será el maestro y el otro el esclavo (importante: unir también GND).
Ejemplo Wire: master_reader / slave_sender
Se encuentran en Archivo => Ejemplos => Wire => master_reader y slave_sender
En este ejemplo el Arduino que hace de…
- …maestro pide 4 byte al esclavo número 2.
- …esclavo responde con 4 byte, por ejemplo: “hola”.
Arduino MAESTRO – En el setup()
1 |
Wire.begin(); //Será el maestro en el bus I²C |
Arduino MAESTRO – En el loop()
1 2 3 4 5 6 |
Wire.requestFrom(2, 4); //Se piden 4 byte al esclavo número 2 while (Wire.available()) //Esperando a que termine { char c = Wire.read(); //Recibir cada byte como un "char" Serial.print(c); //Mostrar resultado por consola } |
Arduino ESCLAVO – En el setup()
1 2 |
Wire.begin(2); //Unirse al I²C como esclavo número 2 Wire.onRequest(funcionDeRespuesta); //Estará fuera del loop() |
Arduino ESCLAVO – En el loop()
Vacío, no requiere código.
Arduino ESCLAVO – Fuera de loop, (por ejemplo al final)
1 2 3 4 |
void funcionDeRespuesta() { Wire.write("hola"); //Cuando Maestro pida, se responde con 4byte } |
Para ejecutar estos ejemplos será necesario también unir las masas ó GND de ambas placas.
Ejemplo Wire: master_writer / slave_receiver
Se encuentran en Archivo => Ejemplos => Wire => master_writer y slave_receiver
En este ejemplo el Arduino que hace de…
- …maestro inicia una transmisión de datos al esclavo 4, le enviará 5 bytes de texto y al final un byte de tipo entero (int).
- …esclavo, al recibir una orden del maestro empieza a leer bytes en modo char (mientras los recibe los va enviando al puerto serie), el último byte lo lee como un número entero (int).
Arduino MAESTRO – En el setup()
1 |
Wire.begin(); //Maestro del bus I2C |
Arduino MAESTRO – En el loop()
1 2 3 4 5 |
Wire.beginTransmission(4); //Enviar datos al nº4 Wire.write("x es "); //Enviar 5 bytes Wire.write(x); //Enviar 1 byte Wire.endTransmission(); //Finalizar transmisión x++; //Incrementar valor |
Arduino ESCLAVO – En el setup()
Es igual que el otro ejemplo, sólo cambia el número:
1 2 |
Wire.begin(4); //Unirse al I2C como esclavo número 4 Wire.onRequest(funcionDeRespuesta); |
Arduino ESCLAVO – En el loop()
Vacío, no requiere código
Arduino ESCLAVO – Fuera de loop, (por ejemplo al final).
Cuando el maestro llame, se leen todos los datos que él nos envíe.
1 2 3 4 5 6 7 8 9 10 |
void funcionDeRespuesta() { while (1 < Wire.available()) //Leer todo, salvo el último { char c = Wire.read(); //Recibido como carácter (char) Serial.print(c); //Mostrar dato } int x = Wire.read(); //El último leído como entero (int) Serial.println(x); //Mostrar dato } |
Enlaces de interés
La web oficial de la librería Wire de Arduino detalla todas las funciones disponibles.
Para conocer más sobre el procotolo I²C se recomienda este tutorial (enlace en inglés).