To connect two Arduino boards via I2C, wire the SDA pins together (A4 on Uno/Nano, SDA on Mega/Leonardo), wire the SCL pins together (A5 on Uno/Nano, SCL on Mega/Leonardo), and connect their GND pins. You must use 4.7kΩ pull-up resistors to VCC (5V) on both SDA and SCL lines for reliable communication beyond a few inches. I2C is a multi-master, multi-node bus ideal for short-distance sensor and microcontroller networking, but it requires strict adherence to physical layer rules to avoid bus lockups.
The Physical Layer: Wiring and Bus Mechanics
Unlike point-to-point protocols, I2C (Inter-Integrated Circuit) is a shared bus. Every device connects to the same two wires: Serial Data (SDA) and Serial Clock (SCL). Because these lines are open-drain (devices can only pull the line low, not drive it high), they require pull-up resistors to return to a logic HIGH state.
The ATmega328P on an Arduino Uno has internal pull-ups of roughly 20kΩ to 50kΩ. This is far too weak for a bus with more than 100pF of capacitance (about two breadboards or 12 inches of wire). Always add external 4.7kΩ resistors for 100kHz Standard Mode, or 2.2kΩ resistors for 400kHz Fast Mode. Without them, your signal rise times will be too slow, causing data corruption.
| Parameter | Standard Mode | Fast Mode | Fast Mode Plus |
|---|---|---|---|
| Wires Required | 2 (SDA, SCL) + Common GND | ||
| Clock Speed | 100 kHz | 400 kHz | 1 MHz |
| Max Bus Capacitance | 400 pF (per NXP UM10204 Spec) | ||
| Addressing | 7-bit (127 usable) or 10-bit | ||
| Practical Distance | ~1 meter | ~30 cm | ~10 cm |
Protocol Fit: I2C vs UART vs SPI for Microcontrollers
Choosing the right protocol depends entirely on your distance, speed, and device count requirements. I2C wins when you need to daisy-chain many low-speed devices on the same two pins without using chip-select lines.
| Criteria | I2C | UART (Serial) | SPI |
|---|---|---|---|
| Topology | Multi-master, multi-node bus | Point-to-point | Single master, multi-node |
| Wires | 2 shared + GND | 2 dedicated (TX/RX) + GND | 3 shared + 1 CS per device |
| Speed | Low (100kHz - 1MHz) | Medium (up to ~1 Mbps) | High (10+ MHz) |
| Best Use Case | On-board sensors, EEPROMs, multi-Arduino sync | GPS modules, long-distance (RS-485), PC comms | SD cards, TFT displays, high-speed ADCs |
Minimal Working Exchange: Master and Node Code
Below is a minimal, copy-pasteable exchange using the native Arduino Wire library. The Master sends a string; the Node receives it via an interrupt callback and prints it to its local Serial monitor.
Wiring Reminder: Uno SDA (A4) to Uno SDA (A4). Uno SCL (A5) to Uno SCL (A5). GND to GND. Add 4.7kΩ pull-ups to 5V on both lines.
Master Code (Controller)
#include <Wire.h>
const int NODE_ADDRESS = 0x08;
void setup() {
Wire.begin(); // Join I2C bus as Master (no address needed)
Serial.begin(115200);
}
void loop() {
Wire.beginTransmission(NODE_ADDRESS);
Wire.write("Ping"); // Send 4 bytes
byte error = Wire.endTransmission();
if (error == 0) {
Serial.println("Message sent successfully.");
} else {
Serial.print("I2C Error code: ");
Serial.println(error);
}
delay(1000);
}
Node Code (Peripheral / Target)
#include <Wire.h>
const int NODE_ADDRESS = 0x08;
void setup() {
Wire.begin(NODE_ADDRESS); // Join I2C bus with specific address
Wire.onReceive(receiveEvent); // Register callback
Serial.begin(115200);
}
void loop() {
// Node can sleep or do other tasks here
delay(100);
}
// Callback function triggered when Master sends data
void receiveEvent(int numBytes) {
Serial.print("Received ");
Serial.print(numBytes);
Serial.print(" bytes: ");
while (Wire.available()) {
char c = Wire.read();
Serial.print(c);
}
Serial.println();
}
Debugging the Bus: Sniffing and Classic Failures
When I2C fails, it fails silently. The Wire library will often just return an error code or hang indefinitely. Here is how to diagnose the three classic I2C failures.
- Address Clash: If two devices on the bus share the same 7-bit address (e.g., two LCD backpacks both defaulted to 0x27), both will attempt to pull SDA low simultaneously, causing data corruption. Fix: Run an I2C Scanner sketch to map the bus. Change addresses via hardware jumpers or software configuration registers.
- Missing Pull-Up Resistors: Without pull-ups, the SDA and SCL lines float. The oscilloscope will show slow, rounded rise times instead of sharp square waves, and the microcontroller will read random noise as data. Fix: Solder 4.7kΩ resistors between VCC and both SDA/SCL.
- Baud Mismatch (Clock Speed Mismatch): Unlike UART, I2C doesn't have a "baud rate" in the traditional sense, but it does have clock speed. If your Master forces Fast Mode (400kHz) via
Wire.setClock(400000), but your Node is an older ATtiny85 or a sensor that only supports 100kHz Standard Mode and lacks clock-stretching hardware, the Node will miss bits. Fix: Force the Master to 100kHz usingWire.setClock(100000);in setup.
How to Sniff the Bus:
Do not rely solely on Serial prints. Connect a logic analyzer (like a $15 DSLogic clone or a Saleae Logic Pro) to SDA and SCL. Set the trigger to capture the I2C START condition (SDA transitions from HIGH to LOW while SCL is HIGH). Decode the hex payload in the analyzer software to verify if the Master is actually sending the correct address byte (remembering that the 7-bit address is shifted left by one, with the LSB acting as the Read/Write bit).
Arduino to Arduino I2C FAQ
Can I connect a 5V Arduino Uno to a 3.3V ESP32 via I2C?
Yes, but you must use a bidirectional logic level shifter (like the BSS138-based Adafruit 4-channel shifter or a Texas Instruments TXS0108E). Feeding 5V directly into the ESP32's SDA/SCL pins will exceed the absolute maximum ratings and permanently damage the GPIO matrix. Wire the 5V side to the Uno, the 3.3V side to the ESP32, and place your pull-up resistors on the respective voltage sides of the shifter.
Why does my I2C bus lock up randomly after a few hours?
This is almost always caused by electrical noise (like a relay switching nearby) inducing a voltage spike that corrupts the clock signal. If the Master stops clocking while the Node is outputting a '0' (holding SDA low), the bus deadlocks because the Master thinks the bus is busy. To fix this, ensure your I2C wires are kept away from AC mains and inductive loads, use twisted-pair wire for SDA/SCL, and implement a software watchdog or bus-recovery routine that toggles the SCL pin manually to free a stuck Node.
What is the maximum cable length for Arduino to Arduino I2C?
The I2C specification limits the bus to 400pF of total capacitance. Standard 22 AWG hookup wire has a capacitance of roughly 50pF per meter. Therefore, your absolute maximum practical length is about 1 meter at 100kHz. If you need to run I2C across a room (up to 20 meters), you must use an active I2C bus extender IC like the NXP P82B96 or the PCA82C250, which buffer the signal and allow longer, lower-impedance cabling.
How do I change the default I2C address on an Arduino?
You define the address in the Node's setup() function using Wire.begin(address). For example, Wire.begin(0x08);. Note that valid 7-bit I2C addresses range from 0x08 to 0x77. Addresses 0x00 through 0x07 are reserved for special bus functions (like the general call address), and addresses above 0x77 are reserved for 10-bit addressing modes.






