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):
| Dispositivo | Dirección típica | Ejemplo |
|---|---|---|
| BME280 (Temp/Hum) | 0x76 o 0x77 | Sensor ambiental |
| MPU6050 (IMU) | 0x68 o 0x69 | Giroscopio |
| OLED SSD1306 | 0x3C o 0x3D | Pantalla pequeña |
| RTC DS3231 | 0x68 | Reloj tiempo real |
| EEPROM 24C32 | 0x50-0x57 | Memoria |
⚡ Ventajas de I2C en IoT
- Ahorro de pines: Solo 2 cables para múltiples dispositivos
- Fácil expansión: Agregar sensores sin rewiring completo
- Detección automática: Escaneo de dispositivos disponibles
- Error handling: ACK/NACK para confirmar transmisión
- 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:
- START: Maestro inicia comunicación
- Dirección + R/W: Envía dirección del esclavo + bit de lectura/escritura
- ACK: Esclavo confirma recepción
- Datos: Intercambio de información
- 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
| Protocolo | Cables | Velocidad | Dispositivos | Complejidad |
|---|---|---|---|---|
| I2C | 2 | Media | Múltiples | Media |
| SPI | 4+n | Alta | Múltiples | Baja |
| UART | 2 | Variable | 1 a 1 | Baja |
🎯 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