domingo, 24 de agosto de 2025

I2C: El Bus de Comunicación Inteligente para IoT

Comunicación I2C entre múltiples dispositivos

I2C: El Bus de Comunicación Inteligente para IoT

🔗 ¿Qué es I2C?

I2C (Inter-Integrated Circuit) es un protocolo de comunicación síncrona desarrollado por Philips que permite conectar múltiples dispositivos usando solo 2 cables. Es el protocolo favorito para sensores, pantallas pequeñas y módulos en proyectos IoT por su simplicidad y eficiencia.


📌 Características principales

  • Solo 2 cables: SDA (datos) y SCL (reloj)
  • Múltiples dispositivos: Hasta 127 esclavos en el mismo bus
  • Direccionamiento único: Cada dispositivo tiene una dirección de 7 bits
  • Maestro-esclavo: Un maestro controla toda la comunicación
  • Velocidades estándar: 100kHz (estándar), 400kHz (rápido), 1MHz (rápido+)

🔌 Conexiones del bus I2C

I2C utiliza solo 2 líneas de comunicación:

  • SDA (Serial Data): Línea bidireccional para datos
  • SCL (Serial Clock): Señal de reloj generada por el maestro
  • Resistencias pull-up: Necesarias en ambas líneas (típicamente 4.7kΩ)
        +3.3V
         |
    4.7kΩ│   4.7kΩ
         |     |
ESP32 ───┼─────┼─── Sensor 1
   SDA   │     │SCL    │
         │     │       │
         │     │    Sensor 2
         │     │       │
         │     │    Sensor 3

📍 Sistema de direccionamiento

Cada dispositivo I2C tiene una dirección única de 7 bits (0x08 a 0x77):

DispositivoDirección típicaEjemplo
BME280 (Temp/Hum)0x76 o 0x77Sensor ambiental
MPU6050 (IMU)0x68 o 0x69Giroscopio
OLED SSD13060x3C o 0x3DPantalla pequeña
RTC DS32310x68Reloj tiempo real
EEPROM 24C320x50-0x57Memoria

⚡ Ventajas de I2C en IoT

  1. Ahorro de pines: Solo 2 cables para múltiples dispositivos
  2. Fácil expansión: Agregar sensores sin rewiring completo
  3. Detección automática: Escaneo de dispositivos disponibles
  4. Error handling: ACK/NACK para confirmar transmisión
  5. Amplio soporte: Librería Wire en Arduino/ESP32

🛠️ Dispositivos comunes I2C en IoT

  • Sensores ambientales: BME280, SHT30, CCS811
  • IMU/Movimiento: MPU6050, ADXL345, LSM9DS1
  • Pantallas: OLED 128x64, LCD con backpack I2C
  • Tiempo real: DS3231, PCF8563
  • Expansión I/O: PCF8574, MCP23017
  • Memorias: EEPROM 24C series

💻 Ejemplo práctico: ESP32 + múltiples sensores

#include <Wire.h>
#include <Adafruit_BME280.h>
#include <MPU6050.h>

Adafruit_BME280 bme; // Sensor ambiental (0x76)
MPU6050 mpu;         // IMU (0x68)

void setup() {
  Serial.begin(115200);
  Wire.begin(); // Inicializar I2C (SDA=21, SCL=22 en ESP32)
  
  // Escanear dispositivos I2C
  scanI2CDevices();
  
  // Inicializar sensores
  if (!bme.begin(0x76)) {
    Serial.println("Error: BME280 no encontrado!");
  }
  
  if (!mpu.begin()) {
    Serial.println("Error: MPU6050 no encontrado!");
  }
  
  Serial.println("Sensores I2C inicializados correctamente");
}

void loop() {
  // Leer sensor ambiental
  float temp = bme.readTemperature();
  float humidity = bme.readHumidity();
  float pressure = bme.readPressure() / 100.0;
  
  // Leer IMU
  int16_t ax, ay, az;
  mpu.getAcceleration(&ax, &ay, &az);
  
  // Mostrar datos
  Serial.printf("Temp: %.1f°C | Hum: %.1f%% | Pres: %.1fhPa\n", 
                temp, humidity, pressure);
  Serial.printf("Accel X: %d | Y: %d | Z: %d\n", ax, ay, az);
  
  delay(2000);
}

void scanI2CDevices() {
  Serial.println("Escaneando dispositivos I2C...");
  
  for (byte address = 1; address < 127; address++) {
    Wire.beginTransmission(address);
    if (Wire.endTransmission() == 0) {
      Serial.printf("Dispositivo encontrado en 0x%02X\n", address);
    }
  }
  Serial.println("Escaneo completado\n");
}

🔄 Protocolo de comunicación I2C

Secuencia típica de lectura:

  1. START: Maestro inicia comunicación
  2. Dirección + R/W: Envía dirección del esclavo + bit de lectura/escritura
  3. ACK: Esclavo confirma recepción
  4. Datos: Intercambio de información
  5. STOP: Maestro termina comunicación
START | 0x68 | W | ACK | 0x3B | ACK | START | 0x68 | R | ACK | DATA | NACK | STOP
      └─ Dirección MPU6050 ─┘     └─ Registro ─┘   └─ Leer dato ─┘    └─ Fin ─┘

📊 I2C vs otros protocolos

ProtocoloCablesVelocidadDispositivosComplejidad
I2C2MediaMúltiplesMedia
SPI4+nAltaMúltiplesBaja
UART2Variable1 a 1Baja

🎯 Consejos para usar I2C en IoT

✅ Buenas prácticas:

  • Pull-ups obligatorias: 4.7kΩ en SDA y SCL
  • Cables cortos: Máximo 1-2 metros para 100kHz
  • Verificar direcciones: Usa el scanner para evitar conflictos
  • Alimentación estable: 3.3V limpio para todos los dispositivos

⚠️ Problemas comunes:

  • Sin pull-ups: Comunicación errática o nula
  • Conflicto de direcciones: Dos dispositivos con la misma dirección
  • Cables largos: Pérdida de señal, usar repetidores I2C
  • Ruido eléctrico: Usar condensadores de desacoplo

🔧 Configuración avanzada ESP32

// Pines personalizados I2C
Wire.begin(SDA_PIN, SCL_PIN); // Por defecto: SDA=21, SCL=22

// Velocidad personalizada
Wire.setClock(400000); // 400kHz (Fast mode)

// Segundo bus I2C (ESP32)
#include <Wire.h>
TwoWire I2C_2 = TwoWire(1);
I2C_2.begin(SDA2_PIN, SCL2_PIN); // Segundo bus independiente

🚨 Troubleshooting I2C

Problema: No se detectan dispositivos

// Verificar conexiones y pull-ups
void debugI2C() {
  Serial.println("Estado I2C:");
  Serial.printf("SDA (Pin %d): %s\n", SDA, digitalRead(SDA) ? "HIGH" : "LOW");
  Serial.printf("SCL (Pin %d): %s\n", SCL, digitalRead(SCL) ? "HIGH" : "LOW");
}

Problema: Comunicación intermitente

  • Verificar alimentación estable
  • Reducir velocidad del bus: Wire.setClock(100000)
  • Agregar delays entre transacciones

📈 Expansión del sistema I2C

Para proyectos grandes, considera:

  • Multiplexores I2C (TCA9548A): 8 canales independientes
  • Repetidores I2C: Extender distancias
  • Buffers I2C: Aislar secciones del bus
  • I2C sobre WiFi: ESP-NOW para comunicación remota

I2C es la columna vertebral de la mayoría de proyectos IoT. Su simplicidad para conectar múltiples sensores lo convierte en el protocolo ideal para estaciones meteorológicas, sistemas de monitoreo y dispositivos IoT complejos con