Durante nuestro curso de Arduino, ya hemos visto la forma más simple de programar nuestra placa para controlar otros dispositivos con el formato más simple de señal entrada salida.
Al fin y al cabo, es cuestión de comunicar información de un dispositivo a otro. Pero las comunicaciones entre componentes pueden ser más avanzadas y definir todo un protocolo.
En tutoriales anteriores ya vimos los formatos más simples de comunicación.
- Comunicación Serial – también denominada comunicación UART
- Comunicación SoftwareSerial
- PWM – Control de servomotores
- Motores paso a paso
Nos falta por estudiar los formatos de comunicación más avanzados disponibles en Arduino.
- Comunicación I2C
- Comunicación por SPI – ICSP
Aunque existen unos cuantos más como la comunicación ModBus, CANBus, etc… Pero que no vamos a ver en este curso, ya que la mayoria de componentes de Arduino se encuentran adaptados para funcionar por I2C o por SPI.
¿Qué es I2C?
I2C es un sistema de comunicación bidireccional basado en 2 hilos, el SDA (Datos) y el SCL (reloj) muy parecido al formato de comunicación Serial. I2C significa Inter-Integrated Circuit (Inter-Circuitos Integrados). desarrollada en el año 1980 por Philips cuya patente caducó en 2006. La velocidad es de 100 kbit/s en el modo estándar, aunque también permite velocidades de 3.4 Mbit/s.
Tres reglas son suficientes para comprender el protocolo I2C.
- Los componentes I2C contienen una dirección física de acceso.
- El protocolo I2C es síncrono
- El protocolo se basa en peticiones «Master – Slave» ( Maestro – Esclavo )
Dirección Física
Se basa en un sistema de comunicación por dirección física de los elementos, esto quiere decir que si conectamos más de un componente por I2C, al usar solo dos cables de transmisión de datos para todo, la placa debe reconocer cada uno de los componentes por un ID o dirección física interna para diferenciarlos.
Esta dirección se encuentra dentro de la señal y todos los componentes conectados cuyo ID no coincide con su dirección dejará pasar la señal para otro componente y solo atenderá a la señar que contiene la suya.
Protocolo síncrono
Uno de los aspectos más importantes a entender de la señal I2C, es que es síncrona. Eso quiere decir que el envío y recepción de datos está sincronizado con una señal de reloj que comparte con la placa de Arduino.
I2C usa solo 2 cables, uno para el reloj (SCL) y otro para el dato (SDA). Esto significa que el maestro y el esclavo envían datos por el mismo cable, el cual es controlado por el maestro, que crea la señal de reloj. I2C no utiliza selección de esclavo, sino direccionamiento.
Maestro esclavo
El microcontrolador principal (Master) se encarga de hacer las peticiones a las direcciones físicas de los dispositivos y con ordenes concretas a los accesos de memoria y de cómo esté programado internamente cada dispositivo.
Dispositivos más utilizados para comunicación por I2C
Los dispositivos que se suelen utilizar con Arduino por I2C dependerán de las necesidades del fabricante, pero en esencia podemos definir los siguientes componentes que nos ayudarán en nuestros proyectos con Arduino.
- Pantallas LCD – Muy útil para no realizar cableado infinito
- Acelerómetro, giroscopio, magnetómetro – IMU MPU6050 – MPU9250
- Lector tarjetas RFID
- Shields de extensión para servomotores
- Algunas pantallas OLED
Es importante reconocer cuáles son los pines I2C a conectar con nuestra placa. Para las placas Arduino UNO o NANO, usaremos siempre el pin analógico A4 y A5 para conectar los pines SDA y SCL respectivamente.
En caso de conectar con otras placas podemos consultar los pines de conexión en la siguiente tabla.
Board | I2C / TWI pins |
Uno, Ethernet | A4 (SDA), A5 (SCL) |
Mega2560 | 20 (SDA), 21 (SCL) |
Leonardo | 2 (SDA), 3 (SCL) |
Due | 20 (SDA), 21 (SCL), SDA1, SCL1 |
Como programar y detectar la dirección física de nuestros módulos
El protocolo I2C requiere de la librería Wire que viene instalada por defecto en Arduino.
Las funciones más básicas que podemos encontrar en la librería Wire, son las siguientes.
- begin() – Inicia la librería Wire y especifica si es master o slave
- requestFrom() – Usado por el maestro para solicitar datos del esclavo
- beginTransmission() – Comenzar transmisión con esclavo.
- endTransmission() – Finaliza la transmisión que comenzó con un esclavo y transmite los bytes en cola.
- write() – Escribe datos desde un esclavo como respuesta a una petición del maestro o pone en cola la transmisión de un maestro.
- available() – Devuelve el número de bytes para leer
- read() – Lee un byte transmitido desde un esclavo a un maestro o viceversa
- onReceive() – Llama a una función cuando un esclavo recibe una transmisión de un maestro. Registra una función de callback.
- onRequest() – Llama a una función cuando un maestro solicita datos de un maestro. Registra una función de callback.
#include <Wire.h> void setup() { Wire.begin(); Serial.begin(9600); while (!Serial); // Leonardo: wait for serial monitor Serial.println("\nI2C Scanner"); } void loop() { byte error, address; int nDevices; Serial.println("Scanning..."); nDevices = 0; for(address = 1; address < 127; address++ ) { Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address < 16) Serial.print("0"); Serial.print(address,HEX); Serial.println(" !"); nDevices++; } else if (error==4) { Serial.print("Unknow error at address 0x"); if (address<16) Serial.print("0"); Serial.println(address,HEX); } } if (nDevices == 0) Serial.println("No I2C devices found\n"); else Serial.println("done\n"); delay(5000); // wait 5 seconds for next scan }
Al abrir el monitor serie nos encontrará las direcciones de los componentes I2C que luego usaremos en posteriores programas.
Si nuestro proyecto contiene múltiples componentes I2C, aunque ya sepamos cuál es su dirección, este programa debería ser el primero a programar para revisar cuáles son las direcciones físicas que posteriormente utilizaremos para mandar los datos.
Una vez completado este tutorial, puedes acceder al siguiente nivel.
Los ejercicios de código, proyectos y recursos que desarrollaremos durante el curso se pueden consultar a través de nuestro Github.