I2C Wiring and Protocol Guide for Arduino, ESP32, and Raspberry Pi
I2C (Inter-Integrated Circuit) is how most modern sensors communicate with microcontrollers. One pair of wires — SDA and SCL — can connect up to 127 devices on the same bus, each with a unique address. Here's how to wire and use it across the main maker platforms.
How I2C Works
I2C uses two signals:
- SDA (Serial Data): carries the data
- SCL (Serial Clock): synchronizes the transfer
The controller (Arduino, Pi, etc.) generates the clock and initiates all transfers. Devices on the bus are either controllers or peripherals. Each peripheral has a 7-bit address (0x00–0x7F), letting up to 127 devices share one bus.
Pull-up resistors on both SDA and SCL are required — typically 4.7 kΩ for standard speed, 2.2 kΩ for fast mode. Most breakout boards include these onboard.
Standard I2C Pins
| Platform | SDA | SCL |
|---|---|---|
| Arduino Uno R3 | A4 | A5 |
| Arduino Nano | A4 | A5 |
| Arduino Mega | 20 | 21 |
| ESP32 DevKit | GPIO 21 | GPIO 22 |
| ESP8266 NodeMCU | D2 (GPIO4) | D1 (GPIO5) |
| Raspberry Pi 40-pin | GPIO 2 (Pin 3) | GPIO 3 (Pin 5) |
| Raspberry Pi Pico | GP4 (default) | GP5 (default) |
See the full pinout references for each board on this site for exact physical pin locations.
Wiring Diagram
Sensor VCC → 3.3V or 5V (check sensor datasheet)
Sensor GND → GND
Sensor SDA → SDA pin
Sensor SCL → SCL pin
Logic level warning: The Raspberry Pi and ESP32 are 3.3V devices. Connect only 3.3V I2C sensors directly. For 5V Arduino + 3.3V sensor, use a bidirectional level shifter (BSS138-based modules are cheap and work well).
Scanning for Device Addresses
Always run an I2C scan first to confirm wiring is correct and find device addresses.
Arduino:
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(115200);
for (byte addr = 8; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
Serial.print("Found device at 0x");
Serial.println(addr, HEX);
}
}
}
void loop() {}
Raspberry Pi:
sudo i2cdetect -y 1
ESP32:
#include <Wire.h>
void setup() {
Wire.begin(21, 22); // SDA, SCL
Serial.begin(115200);
for (byte addr = 8; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0)
Serial.printf("Found: 0x%02X
", addr);
}
}
Common I2C Sensor Addresses
| Device | Default Address |
|---|---|
| BME280 (temp/humidity/pressure) | 0x76 or 0x77 |
| BMP180 (pressure) | 0x77 |
| MPU6050 (accelerometer/gyro) | 0x68 or 0x69 |
| SSD1306 OLED (128×64) | 0x3C or 0x3D |
| ADS1115 (16-bit ADC) | 0x48–0x4B |
| PCF8574 (GPIO expander) | 0x20–0x27 |
| DS3231 RTC | 0x68 |
| VL53L0X (ToF distance) | 0x29 |
Multiple Devices on the Same Bus
Just wire SDA and SCL in parallel across all devices. Each device responds only to its address. For two identical sensors (same address), most have an address select pin (AD0, ADDR) that lets you set a different address — check the datasheet.
Troubleshooting
Nothing found in scan: Check wiring, check power, confirm pull-ups are present, try slower bus speed.
Intermittent errors: Bus speed too high for cable length, or missing/wrong pull-up resistors.
Wrong readings: Confirm sensor address matches library call, check voltage compatibility.
Multiple devices causing problems: One faulty device can pull the bus low and block all others — disconnect devices one by one to find the culprit.