En este tutorial profundizamos en el protocolo de comunicación I2C.
Se aprende qué ejemplos prácticos:
- qué pines necesita el microcontrolador Arduino y ESP8266 para conectar dispositivos a través de I2C.
- las ventajas y desventajas de este protocolo de comunicación
- cómo utilizar un multiplexor I2C
La comunicación I2C es uno de los tres posibles protocolos de comunicación, el Arduino / ESP8266 puede comunicarse con otros dispositivos como pantallas OLED, sensores de presión barométrica, etc. Los otros dos protocolos de comunicación son SPI y UART.
I2C significa Inter-Integrated Circuit fue inventado en 1982 por Philips Semiconductor, ahora NXP Semiconductors.
I2C tiene varias características que también se comparan en la siguiente tabla:
- Sincrónico: La salida de los bits se sincroniza en el muestreo de los bits mediante una señal de reloj compartida entre el maestro y el esclavo.
- Multi-maestro: puede tener varios maestros controlando uno o más esclavos.
- Multi-esclavo: puede conectar múltiples ráfagas a un solo maestro como SPI.
- Paquete conmutado: los datos transferidos se agrupan en paquetes / mensajes, que constan de un encabezado y una carga útil.
- Unipolar: los datos se transfieren por un solo cable.
- Conexión en serie: los datos se transfieren bit a bit a lo largo de un solo cable
Descripción | I2C | SPI | UART | |
---|---|---|---|---|
Inventado por | 1982 por Philips Semiconductor | 1970 por Motorola | 1960 por Gordon Bell en Digital Equipment Corporation | |
Transferencia de datos síncrona | Se necesita una línea de reloj para sincronizar la comunicación | Verdadero | Verdadero | Falso |
Transferencia de datos asíncrona | En lugar de una señal de reloj, el propio vapor de datos contiene señales de inicio y de parada | False | False | True |
Rendimiento | De 10.000 a 1.000.000 de bits/s | Hasta 10.000.000 de bits/s | Hasta 115.200 bits/s | |
El esclavo necesita una dirección única | Verdadero | Falso | Falso | |
Número de pines necesarios | 2 | 4 | 2 | |
Protocolo de comprobación de errores | Verdadero | Falso | Verdadero | |
Multi-maestro | Puede tener varios maestros que controlen uno o varios esclavos | Verdadero | Falso | Falso |
Multi-esclavo | Puede conectar varias salves a un solo maestro | Verdadero | Verdadero | Falso |
Conmutación de paquetes | Los datos transferidos se agrupan en paquetes/mensajes, compuestos por una cabecera y una carga útil | Verdadero | Falso | Falso |
Single-ended | Los datos se transfieren por un solo cable | True Datos en serie (SDA) | Falso Master in Slave Out (MISO) Master Out Slave In (MOSI) | False |
Conexión serie | Los datos se transfieren bit a bit a lo largo de un solo cable | Verdadero | Verdadero | Verdadero |
Diseño de referencia I2C con diagrama de tiempos
En su Arduino / ESP8266, encontrará dos GPIO (SDA y SCL) para la comunicación I2C. Si no está seguro de encontrar los pines coincidentes, consulte las siguientes imágenes o para obtener el pinout completo, puede verificar los siguientes elementos:
- Pinout ESP8266
- Pinout Arduino Nano
- Pinout Arduino Uno
- Pinout Arduino Mega
ESP8266 (NodeMCU)
SDA: D2 (I2C -> Datos)
SCL: D1 (I2C -> Reloj)
Arduino Nano
SDA: A4
SCL: A5
Arduino Uno
SDA: PIN18
SCL: PIN19
(sin etiqueta en la parte frontal de la PCB, solo visible desde el lateral)
Arduino Mega
SDA: PIN20
SCL: PIN21
(sin etiqueta en la parte frontal de la PCB, solo visible desde el lateral)
Los dos pines que necesita para la comunicación I2C son los siguientes:
- SDA (Serial Data): conexión entre maestro y esclavo para enviar y recibir datos.
- SCL (Serial Clock): comparte la señal del reloj entre el maestro y el esclavo, donde el maestro siempre controla la señal del reloj.
La línea de datos en serie y la línea de reloj en serie se activan con resistencias. Por lo tanto, cuando no hay transmisión de datos en el bus, SDA y SCL son ALTOS. Por qué se necesita resistencia, consulte la subsección “Capa física”. Los voltajes típicos son + 5V y + 3.3V y los dispositivos pueden comunicarse a 100kHz o 400kHz.
Todos los dispositivos I2C están conectados al bus con un colector abierto o clavijas de drenaje abiertas para tirar de la línea BAJA. La comunicación entre el maestro y el esclavo se produce al cambiar las líneas tirando de LOW y soltando HIGH. Los bits también se sincronizan en los bordes descendentes del reloj.
Puede haber cuatro posibles modos de operación para un dispositivo de bus dado, aunque la mayoría de los dispositivos solo usan una función y sus dos modos:
- transmisión maestra: el nodo maestro envía datos a un esclavo,
- recepción maestra: el nodo maestro recibe datos de un esclavo,
- transmisión esclava: el nodo esclavo envía datos al maestro,
- recepción de esclavos: el nodo esclavo recibe datos del maestro.
Protocolo de mensajes I2C
El protocolo de mensajes I2C se divide bit a bit en secciones fijas. En la siguiente parte del artículo, analizaremos más de cerca las seis secciones diferentes del protocolo.
- Condición inicial: SDA: ALTA → BAJA cuando SCL es ALTA
- Condición de parada: SDA: BAJA → ALTA cuando SCL es ALTA
Las condiciones de inicio y parada son las únicas dos veces en toda la comunicación I2C, donde la línea SDA cambia cuando la línea SCL es ALTA. En todas las demás condiciones, la línea SDA solo cambia de estado cuando la línea SCL es BAJA.
- Trama de dirección: la trama de dirección es una secuencia de 7 o 10 bits para identificar a cada esclavo del maestro. El identificador es único en todos los esclavos. Cada esclavo compara la dirección enviada por el maestro con su propia dirección. Si la dirección coincide, devuelve un ACK → 0 bit al maestro. Si la dirección no coincide, el esclavo no hace nada y la línea SDA permanece alta.
- Bit de lectura / escritura
- Escritura: el maestro envía datos al esclavo: 0
- Leer: el maestro solicita datos al esclavo: 1
- Bit ACK / NACK. Si una trama de dirección o trama de datos se ha recibido con éxito, se devuelve un bit ACK → 0 al remitente desde el dispositivo receptor.
- Trama de datos: una vez que el maestro detecta el bit ACK del esclavo, la primera trama de datos está lista para ser enviada. La trama de datos siempre tiene una longitud de 8 bits y va seguida de un bit ACK / NACK para verificar que la trama se recibió correctamente. El maestro continuará generando pulsos de reloj a intervalos regulares.
Debido a que después de cada trama de datos se transfiere un bit ACK / NACK, el protocolo de comunicación I2C tiene una sobrecarga de datos.
Comunicación de escritura I2C
Comunicación de lectura I2C
Repita las condiciones de inicio
Es posible que el maestro intercambie varios mensajes a la vez, sin permitir que otro dispositivo maestro tome el control del bus. Por lo tanto, una condición de inicio repetida se define de la siguiente manera:
- SCL 0 → 0
- SDA 0 → 1
- SCL 0 → 1
- SDA 1 → 0
Tenga en cuenta que no hubo ninguna condición de parada.
Estiramiento del reloj
En algunos casos, la velocidad de datos del maestro excederá la capacidad de los esclavos para proporcionar los datos solicitados. Por lo tanto, el esclavo puede mantener presionada la línea SCL después de que el maestro libera la línea SCL. El maestro esperará hasta que el esclavo libere la línea de clic antes de pasar al siguiente cuadro.
Capa fisica
A diferencia de las conexiones UART o SPI, los controladores de bus I2C son de «drenaje abierto», lo que significa que pueden tirar de la línea de señal correspondiente hacia abajo, pero no pueden llevarla al nivel alto. Por lo tanto, no puede haber comunicación cuando un dispositivo intenta impulsar la línea mientras otro intenta apagarla. Esta arquitectura evita errores de comunicación.
Pero, ¿cómo es posible elevar la línea de señal? Cada línea de señal tiene una resistencia pull-up para restaurar la señal alta cuando ningún dispositivo afirma la línea baja.
Una regla general para elegir una resistencia es 4.7 kΩ. Cuantos más dispositivos estén conectados a la comunicación I2C, menor debe ser la resistencia.
I2C permite flexibilidad en la conexión de dispositivos con diferentes voltajes de E / S. Para una placa Arduino con un nivel de voltaje de 5 V como maestro, un esclavo de 3.3 V funcionará sin problemas. Pero si el voltaje del esclavo será inferior a 3,3 V, por ejemplo 2,5 V, existe la posibilidad de comprar una placa de cambio de nivel I2C.
Modos de velocidad I2C
- Modo de baja velocidad: 10 kbit / s
- Modo estándar: 100 kbit / s
- Modo rápido: 400 kbit / s
- Modo rápido más: 1 Mbps
- Modo de alta velocidad: 3,4 Mbps
- Modo ultrarrápido: 5 Mbps
Ventajas y desventajas de la comunicación I2C
Ventajas
- Solo usa dos cables
- Admite múltiples maestros y múltiples esclavos
- Protocolo bien conocido y ampliamente utilizado
Desventajas
- Velocidad de transferencia de datos más lenta que SPI
- El tamaño de la trama de datos está limitado a 8 bits.
Ejemplos de I2C
La siguiente tabla le brinda una descripción general de todos los componentes y partes que utilicé para este tutorial.
Arduino Nano | Amazon | AliExpress |
Arduino Pro Mini | Amazon | AliExpress |
Arduino Uno | Amazon | AliExpress |
Arduino Mega | Amazon | AliExpress |
ESP32 ESP-WROOM-32 | Amazon | AliExpress |
ESP8266 NodeMCU | Amazon | AliExpress |
ESP8266 WeMos D1 Mini | Amazon | AliExpress |
Kit de botones | Amazon | Aliexpress |
Pantalla LCD de 20×4 | Amazon | Aliexpress |
Pantalla LCD 16×2 | Amazon | Aliexpress |
En la siguiente sección, dejamos atrás la teoría y miramos ejemplos prácticos. Antes de que podamos controlar un dispositivo I2C, primero debemos saber su dirección HEX. Por lo tanto, nuestro primer ejemplo será un escáner de direcciones I2C HEX. Después de averiguar la dirección HEX de la pantalla LCD I2C, controlaremos la pantalla en consecuencia para enviar mensajes desde Arduino o NodeMCU a través de I2C a la pantalla LCD.
Las siguientes imágenes muestran la conexión entre Arduino Uno en el lado izquierdo y NodeMCU en el lado derecho con la pantalla LCD I2C.
Arduino Uno
GND
5V
PIN18
PIN19
Pantalla LCD I2C
GND
VCC
SDA
SLC
NodeMCU
GND
VINO
D2
D1
Pantalla LCD I2C
GND
VCC
SDA
SLC
¿Cómo encontrar la dirección HEX?
#include "Wire.h" void setup(){ Serial.begin(115200); while(!Serial){} // Waiting for serial connection Serial.println(); Serial.println("Start I2C scanner ..."); Serial.print("rn"); byte count = 0; Wire.begin(); for (byte i = 8; i < 120; i++) { Wire.beginTransmission(i); if (Wire.endTransmission() == 0) { Serial.print("Found I2C Device: "); Serial.print(" (0x"); Serial.print(i, HEX); Serial.println(")"); count++; delay(1); } } Serial.print("rn"); Serial.println("Finish I2C scanner"); Serial.print("Found "); Serial.print(count, HEX); Serial.println(" Device(s)."); } void loop() {}
La biblioteca «Wire.h» permite que el microcontrolador se comunique con dispositivos I2C. Por lo tanto, esta biblioteca es esencial siempre que desee utilizar la comunicación I2C.
Este boceto solo usa la función de configuración, ya que solo queremos escanear una vez todos los dispositivos conectados. Primero establecemos la velocidad en baudios en 115200 y memorizaremos para establecer la velocidad en baudios del monitor en serie en el mismo valor. Luego esperamos a que se establezca la conexión serial para poder escanear los dispositivos. Después de configurar algunas impresiones nuevas en el monitor de serie, establecemos un número de variable en cero. La variable se incrementará cuando encontremos un dispositivo I2C y por lo tanto corresponde a la suma de los dispositivos I2C conectados.
Con Wire.begin (), el microcontrolador se une al bus I2C como maestro o esclavo. Si no se proporciona una dirección en la función, como Wire.begin (dirección), el dispositivo se unirá como maestro como queramos. Para escanear todas las posibles direcciones I2C HEX, usamos un bucle for. Para iniciar la transmisión al posible esclavo I2C, usamos la función Wire.beginTransmission (dirección). Si hay un esclavo I2C válido, obtenemos un 0 al finalizar la transmisión al esclavo a través de Wire.endTransmission (). Imprimimos la dirección HEX del dispositivo conectado en el monitor en serie. Además, si encontramos un dispositivo I2C, aumentamos el contador en 1 y usamos un pequeño retraso antes de intentar conectarnos al siguiente dispositivo.
Al final del script, imprimimos el número total de dispositivos I2C encontrados. No usamos la función de bucle.
Si miramos el monitor de serie, el resultado es el siguiente
Encontramos la pantalla LCD I2C conectada con dirección HEX 0x27. Necesitaremos esta dirección para nuestro próximo ejemplo.
Controlar una pantalla LCD
Con el escáner I2C HEX, descubrimos que la dirección HEX de la pantalla LCD es 0x27. Ahora podemos programar el script para comunicarse con la pantalla LCD. Para este boceto, necesitamos la biblioteca LiquidCrystal_I2C. También hay un artículo separado en la pantalla LCD con información técnica más detallada.
#include "Wire.h" #include "LiquidCrystal_I2C.h" // set the LCD address to 0x27 for a 16 chars and 2 line display LiquidCrystal_I2C lcd(0x27, 20, 4); void setup() { lcd.init(); lcd.backlight(); lcd.setCursor(1, 0); lcd.print("This is"); lcd.setCursor(1, 1); lcd.print("DIYI0T.com"); } void loop(){}
Primero, debemos incluir la biblioteca Wire que conocemos por el código del escáner I2C HEX y la nueva biblioteca LiquidCrystal_I2C que toma el enorme trabajo de proporcionarnos una interfaz fácil de usar para la pantalla LCD.
Necesitamos establecer la dirección HEX de nuestra pantalla y qué pantalla estamos usando como 16 × 2 o 20 × 4. Estoy usando la pantalla de 20 × 4 en este ejemplo.
En la función de configuración, usamos lcd.init () para inicializar la conexión entre el microcontrolador y la pantalla. Después de la inicialización, necesitamos encender la luz de fondo con lcd.backlight ().
Una vez configurada la pantalla, podemos colocar el cursor en la posición (columna = 1, fila = 0) y escribir nuestra primera parte del texto. Luego colocamos el cursor en la siguiente línea y escribimos el resto de la cadena.
Multiplexor I2C
¿Si desea conectar muchos sensores a su Arduino y su conexión I2C normal está llegando a un límite? Quizás los sensores tengan la misma dirección I2C. La solución a su problema es la extensión PCF8574 1 a 8 I2C. El Breakout PCF8574 permite la comunicación con varios dispositivos I2C que tienen la misma dirección, lo que facilita su interfaz. El PCF8574 es un módulo de expansión I2C de ocho canales que permite controlar ocho dispositivos I2C separados mediante un único bus I2C de host.
El PCF8574 es un módulo de expansión de entrada / salida (E / S) de 8 bits para el bus bidireccional de dos líneas (I2C) y está diseñado para voltajes operativos entre 2,5 V y 6 V.
El PCF8574 está conectado al Arduino de la siguiente manera:
VCC -> 5 V
GND -> GND
SDA -> PIN18
SCL -> PIN19
P0… P7 son la entrada / salida del puerto P con una estructura de diseño push-pull. Aquí conecta sus dispositivos I2C al PCF8574. Hemos conectado el LED a P0.
A0… A2 son entradas de dirección para el propio PCF8574. No los necesitamos y por lo tanto los conectamos con GND.
Haga clic en aquí, si desea consultar la ficha técnica completa del PCF8574.
El código del programa para el control del escáner y del dispositivo es el mismo que el anterior.
Si desea saber cómo reducir la cantidad de pines de entrada para un teclado de 8 a solo 2 pines I2C, utilizando el multiplexor I2C, visite el tutorial de teclado para Arduino, ESP32 y ESP8266.