← All projects
Basics Beginner

An I2C Scanner: Find Every Module's Address and Fix "Sensor Not Found"

The most useful sketch for any I2C project. We try all 127 addresses, label the devices we find, and go through five reasons a module does not answer: from swapped SDA/SCL to missing pull-ups and address conflicts.

Difficulty
Beginner
Time
20 min
Category
Basics
Updated

About the project

"Sensor not found" is the most common error in projects with I2C displays and sensors. Before blaming the library, find out whether the device answers on the bus at all, and at which address. That is what an I2C scanner is for: it addresses every possible address in turn and checks whether anyone answers.

What you need

  • ESP32 DevKit (or an Arduino)
  • Any I2C modules: this example uses an AHT20, a BMP280, an SSD1306 OLED and a PCF8574 expander

Wiring

All modules go in parallel on the same two wires:

Signal ESP32 Arduino Uno ESP32-C3 SuperMini
SDA GPIO21 A4 GPIO8
SCL GPIO22 A5 GPIO9
VCC 3V3 5V 3V3

How the scanner works

Every I2C transfer starts with an address. A device that recognises its address answers with an ACK bit. Wire.endTransmission() returns 0 if the ACK arrived and 2 if it did not. The scanner simply tries addresses 1 to 126.

Code

// I2C scanner: which addresses answer on the bus?
#include <Wire.h>

const char* guess(uint8_t a) {   // typical devices by address
  switch (a) {
    case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: return "PCF8574 / LCD 1602";
    case 0x38: return "AHT10 / AHT20";
    case 0x3C: case 0x3D: return "OLED SSD1306";
    case 0x40: return "INA219";
    case 0x48: return "ADS1115";
    case 0x5A: return "MLX90614";
    case 0x68: return "DS3231 / MPU6050";
    case 0x76: case 0x77: return "BME280 / BMP280";
    default: return "?";
  }
}

void scan() {
  Serial.println("Scanning I2C...");
  int found = 0;
  for (uint8_t addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.printf("  0x%02X  %s\n", addr, guess(addr));
      found++;
    }
  }
  Serial.printf("%d device(s) found\n\n", found);
}

void setup() {
  Serial.begin(115200);
  Wire.begin();   // ESP32: SDA 21, SCL 22
  scan();
}

void loop() {
  delay(5000);
  scan();   // disconnect a module and watch it disappear
}

In the simulator delete the SDA wire of one module, or change its address in the properties — the next scan shows it.

Five reasons a module is "not found"

  1. SDA and SCL swapped. The most common mistake. The scanner finds nothing — swap the wires.
  2. The wrong address. A BME280/BMP280 is 0x76 or 0x77, an OLED 0x3C or 0x3D, an LCD 1602 0x27 or 0x3F. Libraries have a default address, and it often does not match your module. Pass the one the scanner found: bme.begin(0x76).
  3. No pull-ups. The I2C lines need 4.7–10 kΩ resistors to VCC. Modules nearly always carry them; if a bare sensor is not found, add them.
  4. An address conflict. Two identical sensors on one bus have the same address. Move the address jumper on one of them (SDO, A0–A2), or use a second bus: the ESP32 has Wire1.
  5. Supply and levels. A 5 V module without a regulator does not work from 3.3 V, and 5 V pull-ups on a module stress the ESP32 inputs. Mixed systems need a level shifter (BSS138).

Good to know

  • Wire length. I2C is designed for a board, not a building: up to 30–50 cm at 100 kHz. For longer runs lower the clock with Wire.setClock(50000) or use a differential bus extender.
  • Addresses 0x00–0x07 and 0x78–0x7F are reserved, which is why the scanner skips them.