Wire

De ArduWiki
Revisión del 21:58 4 may 2019 de Kike GL (Discusión | contribuciones) (Ejemplo 2)

Saltar a: navegación, buscar

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

Metodos disponible librería Wire.h
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 num_esclavo = 42;

// various commands we might send
enum {
   CMD_ID = 1,
   CMD_READ_A0 = 2,
   CMD_READ_D8 = 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(){
  byte val;
  sendCommand(CMD_READ_A0, 2);
  val = Wire.read();
  val <<= 8;
  val |= Wire.read();
  Serial.print("Value of A0: ");
  Serial.println(val, DEC);
  sendCommand(CMD_READ_D8, 1);
  val = Wire.read();
  Serial.print("Value of D8: ");
  Serial.println(val, DEC);
  delay (500);   
}

void sendCommand (const byte cmd, const byte responseSize){
   Wire.beginTransmission(num_esclavo);
   Wire.write(cmd);
   Wire.endTransmission();
   Wire.requestFrom(num_esclavo, responseSize);  //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_D8 = 3
    };

void setup(){
   pinMode(8, 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] = val >> 8;    //Capturamos 1er byte
   buf[1] = val & 0xFF;  //Capturamos 2do 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 esclavo
     break;
  case CMD_READ_A0: 
     sensor(A0);         //Envia dato sensor en A0
     break;
  case CMD_READ_D8: 
     Wire.write(digitalRead(8));   //Envia estado de pin 8
     break;
  } 
}

Vea también


Referencias externas