Conectas un sensor nuevo a tu ESP32, subes el código de ejemplo… y nada. El monitor serial en blanco. Antes de dudar del sensor o del cableado, hay una pregunta que resuelve la mitad de estos casos: ¿en qué dirección I2C está respondiendo el dispositivo? Muchos módulos comparten familia pero cambian la dirección según una soldadura o un pin, y el datasheet no siempre es claro. La forma rápida y definitiva de averiguarlo es correr un escáner I2C.
En esta guía vas a crear un escáner I2C sobre ESP IDF (el framework nativo de Espressif, en VS Code) que recorre las 128 direcciones posibles y te lista cuáles tienen un dispositivo conectado. Lo probaremos con un sensor BME280, pero sirve para cualquier periférico I2C: pantallas, expansores de puertos, RTC, acelerómetros. Al terminar vas a saber crear un proyecto ESP IDF desde cero, entender cómo funciona el sondeo del bus y tener una herramienta de diagnóstico que reusarás en casi todos tus proyectos.
Qué es escanear el bus I2C
I2C usa direcciones de 7 bits, lo que da 128 combinaciones (de 0x00 a 0x7F). No todas son utilizables: los rangos 0x00 a 0x07 y 0x78 a 0x7F están reservados por el estándar, así que los dispositivos reales viven entre 0x08 y 0x77. Escanear consiste en enviar a cada dirección un mensaje de sondeo y ver quién contesta con un ACK. Quien responde, existe; el resto, silencio.
Por qué importa: dos sensores con la misma dirección no pueden convivir en el mismo bus (colisionan). El escáner te confirma la dirección real de cada uno antes de armar un montaje con varios periféricos, y te ahorra horas de depuración a ciegas.
Hardware
Necesitas un ESP32 (o ESP32-S3), un dispositivo I2C para probar (usamos un BME280), una protoboard y cables jumper. En un ESP32 clásico los pines I2C por defecto son SDA en GPIO 21 y SCL en GPIO 22; en las placas ESP32-S3 son SDA en GPIO 8 y SCL en GPIO 9. Conecta SDA y SCL del sensor a los pines correspondientes, más 3.3V y GND.

Detalle técnico: en la configuración del bus verás
.flags.enable_internal_pullup = false. El I2C necesita resistencias pull up en SDA y SCL, y la mayoría de los módulos BME280 ya las traen a bordo (típicamente de 4,7 kΩ). Por eso se desactivan las internas del ESP32. Si armas el circuito con un chip "pelado" sin pull ups, tendrás que ponerlas tú o activar las internas.
Crear el proyecto ESP IDF en VS Code
Este ejemplo asume que ya tienes instalada la extensión ESP IDF de Espressif en VS Code. Con eso listo, abre la extensión, despliega el menú Advanced y elige New Project Wizard. Selecciona la versión del framework (ESP IDF v6.x) y la plantilla ESP IDF Templates.

Completa el nombre del proyecto y la carpeta destino (evita carpetas sincronizadas tipo Google Drive o Dropbox: la compilación crea miles de archivos y se vuelve lentísima). Elige tu chip objetivo (ESP32 o ESP32-S3) y el puerto serial de tu placa, y crea el proyecto desde la plantilla.

El asistente genera muchos archivos y carpetas. Para esta guía solo tocaremos uno: main/main.c. Ábrelo desde el explorador de proyecto.
El código del escáner
Copia el siguiente código completo en main.c y guárdalo. Es un programa ESP IDF autónomo: configura el bus, recorre las 128 direcciones cada 10 segundos e imprime una grilla con los dispositivos encontrados.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
https://RandomNerdTutorials.com/esp-idf-esp32-i2c-scanner/
*/
#include <stdio.h>
#include "esp_log.h"
#include "driver/i2c_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define I2C_SDA_PIN 8 // Change to your SDA pin
#define I2C_SCL_PIN 9 // Change to your SCL pin
#define I2C_TIMEOUT_MS 50 // Timeout for probing each address (in milliseconds)
static const char *TAG = "I2C_SCANNER";
void i2c_scanner_task(void *pvParameters)
{
// Configure and initialize the I2C master bus
i2c_master_bus_config_t bus_cfg = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.sda_io_num = I2C_SDA_PIN,
.scl_io_num = I2C_SCL_PIN,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = false,
};
i2c_master_bus_handle_t bus_handle;
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_cfg, &bus_handle));
while (1) {
ESP_LOGI(TAG, "Starting I2C scan...");
uint8_t found_addresses[128] = {0}; // To store found devices
int devices_found = 0;
// Optional: Print classic grid header
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
for (int addr = 0x00; addr <= 0x7F; addr++) {
if (addr % 16 == 0) {
printf("%02x: ", addr);
}
// Skip general call (0x00) and reserved addresses
esp_err_t ret = i2c_master_probe(bus_handle, addr, I2C_TIMEOUT_MS);
if (ret == ESP_OK) {
printf("%02x ", addr);
if (addr >= 0x08 && addr <= 0x77) { // Find only count valid 7-bit addresses
found_addresses[devices_found++] = addr;
}
} else if (ret == ESP_ERR_NOT_FOUND) {
printf("-- ");
} else {
printf("UU "); // Timeout or other error
}
if ((addr + 1) % 16 == 0) {
printf("\n");
}
}
// Print summary
printf("\nScan complete: %d device(s) found.\n", devices_found);
for (int i = 0; i < devices_found; i++) {
printf("%d. Device 0x%02x address\n", i + 1, found_addresses[i]);
}
if (devices_found == 0) {
printf("\n"); // Extra newline for readability when none found
}
// Repeats scan every 10 seconds (optional)
vTaskDelay(pdMS_TO_TICKS(10000));
}
// Cleanup (never reached in this loop)
ESP_ERROR_CHECK(i2c_del_master_bus(bus_handle));
vTaskDelete(NULL);
}
void app_main(void)
{
ESP_LOGI(TAG, "I2C scanner starting on SDA=%d, SCL=%d", I2C_SDA_PIN, I2C_SCL_PIN);
xTaskCreate(i2c_scanner_task, "i2c_scanner", 4096, NULL, 5, NULL);
}
Cómo funciona, por partes
Se incluyen las librerías base: stdio.h para printf, esp_log.h para los mensajes de depuración, driver/i2c_master.h (el driver I2C de ESP IDF) y FreeRTOS.h + task.h para manejar la tarea. La configuración del bus (i2c_master_bus_config_t) fija los pines SDA/SCL y desactiva las pull up internas.
El núcleo es la función i2c_master_probe(): envía un sondeo a cada dirección y devuelve ESP_OK si algún dispositivo responde. El bucle recorre de 0x00 a 0x7F, imprime una grilla estilo i2cdetect de Linux y guarda solo las direcciones válidas (0x08 a 0x77). Al final lista cuántos dispositivos halló y en qué direcciones.
A diferencia de Arduino, en ESP IDF no existe setup() ni loop(). El punto de entrada es app_main(), que aquí crea una tarea de FreeRTOS (xTaskCreate) para correr el escáner. Ese es el patrón idiomático de ESP IDF.
Compilar y flashear
En la barra inferior de VS Code selecciona el método de flasheo (UART), el puerto COM de tu ESP32 y el chip objetivo. Luego compila con el ícono de la llave (Build Project). la primera vez tarda más. y, cuando aparezca Build Successfully, flashea con el ícono del rayo (Flash Device). Si tu placa lo pide, mantén presionado el botón BOOT para entrar en modo de programación.

Interpretar los resultados
Abre el monitor serial (Monitor Device, ícono de pantalla). En un par de segundos verás la grilla con las direcciones activas. Con el BME280 conectado deberías ver Device 0x76 address (algunos módulos usan 0x77). Esa es la dirección que después pondrás en la librería del sensor.
Tabla de referencia rápida de direcciones I2C comunes, útil para identificar qué encontraste:
| Dispositivo | Dirección típica |
|---|---|
| BME280 / BMP280 | 0x76 o 0x77 |
| OLED SSD1306 | 0x3C o 0x3D |
| MPU6050 (IMU) | 0x68 o 0x69 |
| RTC DS3231 | 0x68 |
| PCF8574 (expansor / LCD I2C) | 0x20 a 0x27 |
| ADS1115 (ADC) | 0x48 a 0x4B |
| BH1750 (luz) | 0x23 o 0x5C |
Si no aparece nada
- Revisa que SDA y SCL no estén cruzados.
- Confirma que el sensor recibe 3.3V y GND.
- Verifica que definiste los pines correctos para tu placa (21/22 en ESP32 clásico, 8/9 en ESP32-S3).
- Si el módulo no trae pull ups, agrégalas (4,7 kΩ a 3.3V en SDA y SCL).
Variantes y mejoras
Ideas para extender el escáner más allá del original:
- Autoidentificar el sensor, no solo su dirección. Mantén en el código un diccionario que mapee dirección → nombre probable (usando la tabla de arriba) e imprime algo como
0x76 -> probablemente BME280/BMP280. Convierte el escáner en un identificador. - Escanear dos buses a la vez. El ESP32 tiene dos periféricos I2C. Crea un segundo
i2c_master_bus_config_tcon otro par de pines y escanea ambos buses en el mismo programa, útil cuando tienes sensores con direcciones repetidas y los separas físicamente. - Sacar la salida por la red. En vez de imprimir por serial, publica las direcciones encontradas por MQTT o en un pequeño servidor web del propio ESP32, para diagnosticar montajes que ya no tienes conectados al PC.
Personalización para Chile
Todo lo necesario para replicar esta guía está en stock en MechatronicStore:
- ESP32 (ESP WROOM-32, USB-C) (SKU X2-10V2). $7.990 CLP
- Sensor BME280 I2C (SKU GR1-10). $8.690 CLP
- Protoboard 830 puntos (SKU C-320). $3.790 CLP
- Cables jumper macho macho 30cm (SKU C-417). $2.990 CLP
Costo total aproximado: $23.460 CLP. El escáner sirve igual con cualquier otro periférico I2C del catálogo (OLED, RTC, expansores), así que este mismo hardware te acompaña en muchos proyectos.
Recursos
- Tutorial original (inglés): ESP IDF: ESP32 I2C Scanner, Finding the Address of I2C Devices
- Framework: Documentación oficial de ESP IDF (driver I2C)
Versión chilena con componentes en stock local en MechatronicStore, basada en la guía de Rui y Sara Santos (Random Nerd Tutorials).




