Wire
Contenido
Descripción
La librería Wire.h estandar de Arduino le permite comunicarse con dispositivos I2C. Usa dos lineas: SDA (datos) y SCL (reloj). Une los GND.
Nota: A partir de Arduino 1.0, la biblioteca hereda de la clase Stream, lo que la hace compatible con otras bibliotecas de lectura/escritura. Debido a esto, send() y receive() han sido reemplazados por read() y write().
Placas aplicables
Arduino | Pin SDA | Pin SCL |
---|---|---|
UNO, Ethernet | A4 | A5 |
MEGA | 20 | 21 |
Leonardo | 2 | 3 |
Debido | 20 | 21 |
Sintaxis
#include <Wire.h> Wire.begin();
Métodos
Métodos | Descripción |
---|---|
Wire.begin(num) | Inicie la libreria Wire y únase al bus I2C como maestro o esclavo. Esto normalmente debería llamarse solo una vez. En caso de varios esclavos es importante numerarlos (0~255). |
Wire.beginTrasnmission(num) | Comience una transmisión al dispositivo esclavo num. Posteriormente, coloque los bytes en cola para la transmisión con la función Wire.write() y transmítalos llamando a Wire.endTransmission(). |
Wire.read() | Lee un byte de dato desde el buffer que envío un maestro. |
Wire.write() | Pone en el buffer del maestro un byte de datos para ser transmitido a un esclavo. |
Wire.endTransmission() | Termina comunicación y libera pines. |
Comentarios
La libreria estándar de I2C para Arduino es Wire. Si bien esta libreria es suficiente la mayor parte del tiempo cuando desea comunicarse con dispositivos, hay situaciones en las que no es aplicable:
- Los pines de I2C (SDA/SCL) ya están en uso para otros fines,
- el código se ejecutará en un procesador ATtiny con 1 MHz en pines arbitrarios,
- tiene poca memoria (flash y RAM), o
- no desea usar las resistencias de activación habilitadas implícitamente porque sus dispositivos se ejecutan con 3 voltios.
Se adapto la libreria I2C de Peter Fleury que está escrito en ensamblador AVR, de peso extremadamente ligero (< 500 bytes de flash) y muy rápido. Incluso con un ATtiny de 1 MHz, uno todavía puede operar el bus con 33 kHz, lo que implica que puede controlar dispositivos esclavos que usan el protocolo SMBus (tiempo de espera si la frecuencia del bus es inferior a 10 kHz).
Si desea que se ejecute una solución en una MCU ARM (Due, Zero, Teensy 3.x), desea usar los pines en el puerto H o superior en un ATmega256, o si desea usar muchos buses I2C diferentes, esta biblioteca no es la solución adecuada para usted. En estos casos recomiendo SlowSoftI2CMaster, otra libreria I2C escrita en C++.
Advertencias
- Las direcciones I2C son de 7 bits para identificar a los esclavos ya que el 8vo bit determina si se está escribiendo o leyendo.
- Con 7 bits se puede obteniendo direcciones entre 0~127. Sin embargo, las direcciones de 0~7 están reservados.
- En caso de tener mas de un esclavo se deben numerar (8~127) con Wire.begin(num_esclavo) y para trasnmitir el maestro debe indentificar con Wire.begin Transmission(num_esclavo). 0 = todos los esclavos.
- Si tienes mas de un esclavo o usa cables largos, hay que poner un 4k7 como pull-up en cada linea SDA/SCL.
- No olvide conectar también todos los GND.
Ejemplo 1
#include <Wire.h>
byte valor = 0 ;
void setup() {
Wire.begin(); //unirse al bus i2c (dirección opcional para el maestro)
}
void loop() {
Wire.beginTransmission(44); //transmitir al dispositivo N° 44 (0x2c)
//la dirección del dispositivo se especifica en la hoja de datos
Wire.write(byte (0x00)); //envía un byte de instrucción
Wire.write(valor); //envía el valor del potenciómetro Byte
Wire.endTransmission(); //deja de transmitir
val ++; //incrementa el valor
if (valor == 64){ //si se alcanza la posición 64 (max)
valor = 0 ; //comienza desde el valor más bajo
}
delay(500) ;
}
Ejemplo 2
Conectar dos Arduinos y que el maestro envie una secuencia y el esclavo la ejecute. En este caso usaremos 3 LED en los pines 11, 12 y 13 del esclavo. En el maestro ponemos este código.
#include <Wire.h>
const byte pin[] = {11, 12, 13};
byte estado = 0;
void setup() {
Wire.begin(); //Iniciamos maestro
}
void loop() {
for (byte i=0; i<3; i++){
Wire.beginTransmission(1); //Nos queremos comunicar con el esclavo 1
Wire.write(pin[i]); //Enviamos primer byte, será el pin a encender
Wire.write(estado); //Enviamos segundo byte, sera el estado 0/1
Wire.endTransmission(); //Paramos la transmisión
delay(1000);
}
if (estado == 0){
estado = 1;
}else{
estado = 0;
}
}
Para el esclavo tendremos:
#include <Wire.h>
void setup() {
Serial.begin(9600);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
Wire.begin(1); //Unimos este dispositivo al bus I2C con dirección 1
Wire.onReceive(recive); //Evento a ejecutar al detectar recepcion
}
void loop() {
delay(100);
}
//Función que se ejecuta cada Wire.endTransmission() del maestro para recibir lo que manda con Wire.write().
void recive() {
byte pin = 0;
byte estado = 0;
if (Wire.available() == 2){
pin = Wire.read(); //Leemos primer byte que sera pin
Serial.print("LED: ");
Serial.println(pin);
estado = Wire.read(); //Leemos segundo byte que sera estado
Serial.print("Estado: ");
Serial.println(estado);
}
digitalWrite(pin, estado); //Prende o apagar LED
}
Ejemplo 3
En este ejemplo ilustramos como un maestro puede solicitar datos de un esclavo.
Código maestro:
#include <Wire.h>
const byte esclavo = 42;
enum {
CMD_ID = 1,
CMD_READ_A0 = 2,
CMD_READ_D13 = 3
};
void setup (){
Serial.begin(9600);
Wire.begin();
sendCommand(CMD_ID, 1);
if (Wire.available()) {
Serial.print("Id del esclavo: ");
Serial.println(Wire.read(), DEC);
}else{
Serial.println ("No responde el esclavo");
}
}
void loop(){
int val;
sendCommand(CMD_READ_A0, 2);
val = Wire.read(); //Recuperamos MSB
val <<= 8; //Desplazamos 8 bits a la izquierda
val |= Wire.read(); //Recuperamos LSB
Serial.print("Valor sensor en A0 del esclavo: ");
Serial.println(val);
sendCommand(CMD_READ_D13, 1);
val = Wire.read();
Serial.print("Estado del pin D13 del esclavo: ");
Serial.println(val);
delay(500);
}
void sendCommand (const byte cmd, const byte largo){
Wire.beginTransmission(esclavo);
Wire.write(cmd);
Wire.endTransmission();
Wire.requestFrom(esclavo, largo); //No continua hasta que tenga datos en el buffer
}
Código esclavo:
#include <Wire.h>
const byte esclavo = 42;
char comando = 0;
enum {
CMD_ID = 1,
CMD_READ_A0 = 2,
CMD_READ_D13 = 3
};
void setup(){
pinMode(13, INPUT_PULLUP); //Pulsador
pinMode(A0, INPUT); //Sensor analogico
Wire.begin(esclavo); //Numero del esclavo
Wire.onReceive(leer); //Cuando llega mensaje
Wire.onRequest(pedir); //Cuando maestro solicita mensaje
}
void loop(){
//Nada
}
void sensor(const byte pin){
int val = analogRead(pin);
byte buf[2];
buf[0] = highByte(val); //Capturamos MSB byte
buf[1] = lowByte(val); //Capturamos LSB byte
Wire.write(buf, 2); //Envia los 2 byte del sensor en A0
}
void leer(){
comando = Wire.read();
}
void pedir(){
switch (comando){
case CMD_ID:
Wire.write(42); //Envia numero del esclavo
break;
case CMD_READ_A0:
sensor(A0); //Envia dato sensor en A0
break;
case CMD_READ_D13:
Wire.write(digitalRead(13)); //Envia estado de pin 13
break;
}
}
Ejemplo 4
En este ejemplo queremos saber que esclavos estan activos.
Código maestro:
#include <Wire.h>
void setup(){
Serial.begin(115200);
Serial.println("Escaneando bus I2C...");
byte n = 0;
Wire.begin();
for (byte i=8; i<128; i++){
Wire.beginTransmission(i);
if (Wire.endTransmission() == 0){
Serial.print("Encontre esclavo: ");
Serial.println(i);
n++;
delay(1);
}
}
Serial.println("Fin de busqueda.");
Serial.print("Encontre ");
Serial.print(n);
Serial.println(" esclavo(s).");
}
void loop(){
//Nada
}
Vea también
Referencias externas
- Wire
- I2C - Nick Gammon
- Bus I2C - Enrique Crespo
- Soft I2C Master - otra libreria I2C
- Conectar 2 Arduino con I2C - Luis Del Valle