Tutorial I2C para Arduino, ESP8266 y ESP32

En este tutorial aprenderás la teoría de la comunicación I2C y empezarás directamente con ejemplos prácticos como el escáner I2C HEX y la pantalla LCD

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ónI2CSPIUART
Inventado por1982 por Philips Semiconductor1970 por Motorola1960 por Gordon Bell en Digital Equipment Corporation
Transferencia de datos síncronaSe necesita una línea de reloj para sincronizar la comunicaciónVerdaderoVerdaderoFalso
Transferencia de datos asíncronaEn lugar de una señal de reloj, el propio vapor de datos contiene señales de inicio y de paradaFalseFalseTrue
RendimientoDe 10.000 a 1.000.000 de bits/sHasta 10.000.000 de bits/sHasta 115.200 bits/s
El esclavo necesita una dirección únicaVerdaderoFalsoFalso
Número de pines necesarios242
Protocolo de comprobación de erroresVerdaderoFalsoVerdadero
Multi-maestroPuede tener varios maestros que controlen uno o varios esclavosVerdaderoFalsoFalso
Multi-esclavoPuede conectar varias salves a un solo maestroVerdaderoVerdaderoFalso
Conmutación de paquetesLos datos transferidos se agrupan en paquetes/mensajes, compuestos por una cabecera y una carga útilVerdaderoFalsoFalso
Single-endedLos datos se transfieren por un solo cableTrue
Datos en serie (SDA)
Falso
Master in Slave Out (MISO)
Master Out Slave In (MOSI)
False
Conexión serieLos datos se transfieren bit a bit a lo largo de un solo cableVerdaderoVerdaderoVerdadero

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)

Pinout NodeMCU

Arduino Nano

SDA: A4
SCL: A5

Pinout Arduino Nano

Arduino Uno

SDA: PIN18
SCL: PIN19
(sin etiqueta en la parte frontal de la PCB, solo visible desde el lateral)

Pinout Arduino Uno

Arduino Mega

SDA: PIN20
SCL: PIN21
(sin etiqueta en la parte frontal de la PCB, solo visible desde el lateral)

Mega Pinout de Arduino

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.
Presentación de I2C

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 de parada de arranque I2C
  1. Condición inicial: SDA: ALTA → BAJA cuando SCL es ALTA
  2. 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.

  1. 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.
  2. Bit de lectura / escritura
    • Escritura: el maestro envía datos al esclavo: 0
    • Leer: el maestro solicita datos al esclavo: 1
  3. 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.
  4. 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

Escritura I2C

Comunicación de lectura I2C

Lectura I2C

Repita las condiciones de inicio

Inicio repetido I2C

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:

  1. SCL 0 → 0
  2. SDA 0 → 1
  3. SCL 0 → 1
  4. 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 NanoAmazonAliExpress
Arduino Pro MiniAmazonAliExpress
Arduino UnoAmazonAliExpress
Arduino MegaAmazonAliExpress
ESP32 ESP-WROOM-32AmazonAliExpress
ESP8266 NodeMCUAmazonAliExpress
ESP8266 WeMos D1 MiniAmazonAliExpress
Kit de botonesAmazonAliexpress
Pantalla LCD de 20×4AmazonAliexpress
Pantalla LCD 16×2AmazonAliexpress

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.

I2C Fritzing Arduino Uno

Arduino Uno

GND
5V
PIN18
PIN19

Pantalla LCD I2C

GND
VCC
SDA
SLC

I2C Fritzing NodeMCU

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

Salida serial del escáner I2C

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.

Ejemplo de pantalla de cristal líquido

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.

Multiplexor I2C

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.

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.


Deja un comentario