Cos'è l'I2C? SDA, SCL, resistenze pull-up e scanner Arduino
Cos'è l'I2C e come funziona: SDA e SCL, indirizzi a 7 bit, calcolo delle pull-up, sketch scanner I2C, conflitti di indirizzo e pin di Uno, ESP32 e Pico.
L'I2C (Inter-Integrated Circuit) è un protocollo di comunicazione seriale che permette a un microcontrollore di parlare con decine di sensori, display e moduli usando solo due fili di segnale (SDA e SCL). Si pronuncia «I-quadro-C» e in alcuni datasheet compare come IIC o TWI (Two Wire Interface). Il display LCD I2C, il display OLED, l'accelerometro MPU6050, il sensore di pressione BMP280 e il modulo orologio DS1307 che usi nei progetti Arduino funzionano tutti con questo protocollo; puoi collegarli in parallelo agli stessi due fili e raggiungere ciascuno con il proprio indirizzo.
In questa guida imparerai come funziona l'I2C a livello elettrico, cosa significano gli indirizzi, perché le resistenze pull-up sono indispensabili e come calcolarne il valore. Poi, passo dopo passo, vedrai una tabella dei pin per Arduino Uno, ESP32 e Raspberry Pi Pico, uno sketch scanner I2C che trova tutti i dispositivi sul bus, un esempio di lettura dei registri senza libreria e le soluzioni ai problemi più comuni come i conflitti di indirizzo.

Cos'è l'I2C e come funziona?
L'I2C è stato sviluppato nel 1982 da Philips (oggi NXP) per far comunicare con pochi fili i chip di una stessa scheda. Sul bus ci sono due ruoli: il controller (un tempo chiamato master), che avvia ogni trasferimento e genera il clock, e i target (un tempo slave), che gli rispondono. Nei progetti Arduino il controller è quasi sempre l'Arduino, l'ESP32 o il Pico, mentre sensori e display sono i target.
- SDA (Serial Data): La linea su cui viaggiano i dati in entrambe le direzioni. Il controller invia indirizzi e comandi, e il sensore restituisce le misure sulla stessa linea.
- SCL (Serial Clock): La linea di clock. A ogni impulso di clock viene letto un bit su SDA, e il clock lo genera il controller.
- GND (massa comune): Il riferimento dei segnali. Anche i moduli alimentati separatamente devono avere una massa comune.
Le linee sono di tipo open-drain: nessun dispositivo porta una linea a livello alto, può solo tirarla verso il basso. A tenere la linea a 1 sono le resistenze pull-up che collegano SDA e SCL alla tensione di alimentazione. Per questo non si crea un cortocircuito nemmeno se due dispositivi provano a parlare insieme; se uno qualsiasi porta la linea a 0, tutti vedono uno 0. Un messaggio I2C procede così:
- START: Mentre SCL è alto, il controller porta SDA da 1 a 0 e tutti i dispositivi sul bus iniziano ad ascoltare.
- Indirizzo e bit di direzione: Viene inviato l'indirizzo a 7 bit, seguito da un bit di lettura (1) o scrittura (0).
- ACK: Il dispositivo a cui appartiene l'indirizzo porta SDA a 0 durante il 9° impulso di clock per dire «ci sono». Se nessuno lo fa, si parla di NACK.
- Byte di dati: Ogni byte viene inviato come 8 bit e il ricevitore risponde a ciascuno con un ACK. Nella maggior parte dei sensori il primo byte è il numero del registro da leggere o scrivere.
- STOP: Mentre SCL è alto, SDA sale da 0 a 1 e il bus torna libero. Nelle letture si usa uno START ripetuto (repeated start) al posto dello STOP, così da cambiare direzione senza rilasciare il bus.
Confrontare l'I2C con gli altri due protocolli più diffusi nel mondo Arduino chiarisce quando sceglierlo:
| Caratteristica | I2C | SPI | UART (seriale) |
|---|---|---|---|
| Fili di segnale | 2 (SDA, SCL) | 3 condivisi (MOSI, MISO, SCK) + un CS per dispositivo | 2 (TX, RX) |
| Numero di dispositivi | Oltre 100 indirizzi su un bus | Tanti quanti i pin CS liberi | Di solito 2 dispositivi |
| Velocità tipica | 100 kHz, 400 kHz, 1 MHz | 10 MHz e oltre | 9600 – 115200 baud |
| Selezione del dispositivo | Tramite indirizzo | Tramite pin CS | Nessuna, punto a punto |
| Uso tipico | Sensori, orologi, piccoli display, EEPROM | Schede SD, display TFT, RFID | GPS, Bluetooth, collegamento al computer |
Velocità dell'I2C e limiti tecnici
| Modalità | Velocità massima | Tempo di salita massimo | Dove si usa? |
|---|---|---|---|
| Standard mode (Sm) | 100 kHz | 1000 ns | Predefinita, cavi lunghi |
| Fast mode (Fm) | 400 kHz | 300 ns | OLED, MPU6050, BMP280 |
| Fast mode plus (Fm+) | 1 MHz | 120 ns | Pico e alcuni sensori recenti |
| High-speed mode (Hs) | 3,4 MHz | 80 ns (400 pF), richiede driver speciali | Rara nei progetti hobbistici |
La libreria Wire di Arduino parte di default a 100 kHz; la maggior parte dei sensori supporta anche 400 kHz e puoi passare a questa velocità con Wire.setClock(400000). Una velocità più alta rende più fluido l'aggiornamento dei display, ma rende il bus più sensibile alla lunghezza dei cavi e al valore delle pull-up. Secondo lo standard, la capacità totale del bus (cavi più pin dei dispositivi) non deve superare 400 pF. I normali cavetti jumper e i cavi piatti aggiungono 50–100 pF per metro e ogni pin di un dispositivo fino a 10 pF; per questo l'I2C è stato pensato per funzionare sulla stessa scheda o con cavi di qualche decina di centimetri. Oltre 1 metro bisogna ridurre la velocità, usare pull-up più forti o aggiungere estensori di bus come il P82B715.
Indirizzi I2C: 7 bit, 8 bit e indirizzi riservati
Ogni dispositivo sul bus ha un indirizzo a 7 bit, che in teoria dà 128 indirizzi. Poiché gli intervalli 0x00–0x07 e 0x78–0x7F sono riservati a usi speciali, gli indirizzi utilizzabili sono i 112 che vanno da 0x08 a 0x77. Di solito l'indirizzo è fissato dal produttore del chip, ma su molti moduli puoi cambiarne gli ultimi bit con ponticelli a saldare o pin chiamati A0, A1, A2 o AD0.
Ecco il punto che confonde: alcuni datasheet e le serigrafie sul retro dei moduli riportano l'indirizzo a 8 bit, compreso il bit di direzione. Per esempio, sul retro di una scheda OLED c'è scritto «0x78», ma l'indirizzo nel codice è 0x3C; se un modulo LCD riporta 0x4E, nel codice l'indirizzo è 0x27. La regola è semplice: dividi il valore a 8 bit per 2 (spostalo a destra di un bit) e ottieni l'indirizzo a 7 bit. Le librerie per Arduino, ESP32 e MicroPython si aspettano tutte indirizzi a 7 bit.
| Modulo | Chip | Indirizzo predefinito | Si può cambiare? |
|---|---|---|---|
| Modulo LCD I2C (16x2, 20x4) | PCF8574 / PCF8574A | 0x27 / 0x3F | Con i ponticelli A0–A2: 0x20–0x27 o 0x38–0x3F |
| OLED da 0,96 pollici | SSD1306 | 0x3C | 0x3D tramite una resistenza sul retro |
| Accelerometro e giroscopio | MPU6050 | 0x68 | 0x69 se AD0 = 1 |
| Orologio in tempo reale | DS1307 / DS3231 | 0x68 | No |
| Pressione e temperatura | BMP280 / BME280 | 0x76 o 0x77 | In base al pin SDO |
| Intensità luminosa | BH1750 | 0x23 | 0x5C se ADDR = 1 |
| ADC a 16 bit | ADS1115 | 0x48 | 0x48–0x4B tramite il pin ADDR |
| Driver servo e PWM a 16 canali | PCA9685 | 0x40 | Decine di indirizzi da 0x40 con i ponticelli A0–A5 |
| Memoria EEPROM | AT24C32 / AT24C256 | 0x50 | 0x50–0x57 con A0–A2 |
| Multiplexer I2C | TCA9548A | 0x70 | 0x70–0x77 con A0–A2 |
Resistenze pull-up: perché servono e come sceglierne il valore
Dato che i dispositivi sul bus I2C possono solo tirare le linee verso il basso, il livello alto lo forniscono le resistenze pull-up. Se la resistenza è troppo grande, la capacità del bus rallenta il passaggio da 0 a 1, i fronti del segnale si arrotondano e ad alta velocità i bit vengono letti male. Se è troppo piccola, aumenta la corrente che un dispositivo deve assorbire quando porta la linea a 0; lo standard richiede solo che un dispositivo possa assorbire almeno 3 mA a 0,4 V, quindi la pull-up deve mantenere la corrente al di sotto di questo valore.
Queste formule danno i due limiti: la resistenza minima è R(min) = (VCC − 0,4 V) / 3 mA e quella massima R(max) = t(salita) / (0,8473 × C(bus)). Per 5 V si ottiene R(min) = 4,6 V / 0,003 A ≈ 1,53 kΩ, per 3,3 V ≈ 0,97 kΩ. Su un bus corto con 100 pF di capacità, R(max) ≈ 11,8 kΩ a 100 kHz e ≈ 3,5 kΩ a 400 kHz. Per questo, in pratica, i valori più usati sono 4,7 kΩ per 100 kHz e 2,2 kΩ per 400 kHz e per i bus affollati. Puoi usare lo strumento Codice colori resistenze per leggere le fasce di una resistenza e lo strumento Costante di tempo RC per vedere il ritardo creato da resistenza e capacità.
| Situazione | Pull-up consigliata | Nota |
|---|---|---|
| Un modulo, cavi corti, 100 kHz | 4,7 kΩ – 10 kΩ | La maggior parte dei moduli le ha già |
| Più moduli, 400 kHz | 2,2 kΩ – 4,7 kΩ | Le resistenze dei moduli finiscono in parallelo |
| Cavi più lunghi di 50 cm | 2,2 kΩ e 100 kHz | Non intrecciare SDA con SCL; intreccia ognuna con GND |
| Bus a 3,3 V (ESP32, Pico) | 2,2 kΩ – 4,7 kΩ | Collega le resistenze a 3,3 V, non a 5 V |
Sull'Arduino Uno, la chiamata a Wire.begin() attiva anche le resistenze pull-up interne da 20–50 kΩ dell'ATmega328P. Con un solo modulo e 10–20 cm di cavo spesso bastano, ma non sono affidabili; le resistenze esterne sono sempre la scelta migliore. Se usi una scheda sensore nuda senza pull-up, non dimenticare di aggiungere una resistenza da 4,7 kΩ tra SDA e VCC e un'altra tra SCL e VCC.
Pin I2C: Arduino Uno, Mega, ESP32, ESP8266 e Pico
| Scheda | SDA | SCL | Nota |
|---|---|---|---|
| Arduino Uno / Nano | A4 | A5 | Sull'Uno R3 i pin SDA e SCL vicino ad AREF sono lo stesso bus di A4/A5 |
| Arduino Mega 2560 | 20 | 21 | Sul Mega, A4 e A5 non sono I2C |
| Arduino Leonardo / Micro | D2 | D3 | Sono pin digitali |
| ESP32 (DevKit) | GPIO 21 | GPIO 22 | Con Wire.begin(SDA, SCL) si possono scegliere altri pin; il secondo bus è Wire1 |
| ESP8266 NodeMCU | D2 (GPIO 4) | D1 (GPIO 5) | I2C software, pin modificabili |
| Raspberry Pi Pico | GP4 (I2C0) | GP5 (I2C0) | I2C0 e I2C1 disponibili su molte coppie di pin |
Passo dopo passo: trovare gli indirizzi con lo scanner I2C
Quando ricevi un nuovo modulo, la prima cosa da fare è scoprire gli indirizzi dei dispositivi sul bus. Uno scanner I2C invia un messaggio vuoto a ogni indirizzo da 0x08 a 0x77 ed elenca quelli che rispondono con un ACK. Così verifichi allo stesso tempo che il modulo sia collegato correttamente e quale indirizzo devi scrivere nel codice.
- Collega il GND del modulo al GND di Arduino e il VCC al 5V (al 3.3V per i moduli che supportano solo 3,3 V).
- Collega SDA ad A4 e SCL ad A5. Se hai più moduli, unisci tutti i loro SDA e tutti i loro SCL sulla breadboard.
- Carica lo sketch qui sotto e apri il monitor seriale a 115200 baud.
- Annota gli indirizzi elencati. Se non compare nulla, controlla i collegamenti, la massa comune e le resistenze pull-up.
- Scollega e ricollega i moduli uno alla volta per capire quale indirizzo appartiene a quale dispositivo; lo scanner ripete la ricerca ogni 5 secondi.
1#include <Wire.h>
2
3void printHex(byte addr) {
4 Serial.print(F("0x"));
5 if (addr < 16) Serial.print('0'); // tek haneliye sıfır ekle / pad single digit
6 Serial.print(addr, HEX);
7}
8
9void setup() {
10 Serial.begin(115200);
11 Wire.begin(); // Uno: A4 = SDA, A5 = SCL
12#if defined(ARDUINO_ARCH_AVR)
13 Wire.setWireTimeout(3000, true); // AVR (Uno, Nano, Mega): hat kilitlenirse 3 ms sonra kurtar / recover a stuck bus after 3 ms
14#endif
15 Serial.println(F("I2C tarayici / I2C scanner"));
16}
17
18void loop() {
19 byte found = 0;
20 for (byte addr = 0x08; addr <= 0x77; addr++) { // geçerli 7 bit adresler / valid 7-bit addresses
21 Wire.beginTransmission(addr);
22 byte err = Wire.endTransmission(); // 0 = cihaz ACK verdi / device acknowledged
23 if (err == 0) {
24 Serial.print(F("Bulundu / found: "));
25 printHex(addr);
26 Serial.println();
27 found++;
28 } else if (err == 4 || err == 5) {
29 Serial.print(F("Hat hatasi / bus error at "));
30 printHex(addr);
31 Serial.println();
32 }
33 }
34 if (found == 0) {
35 Serial.println(F("Cihaz yok: kablolari ve pull-up'lari kontrol et / no devices: check wiring and pull-ups"));
36 } else {
37 Serial.print(found);
38 Serial.println(F(" cihaz bulundu / device(s) found"));
39 }
40 Serial.println();
41 delay(5000); // 5 sn sonra yeniden tara / rescan after 5 s
42}| Risultato di endTransmission() | Significato | Cosa fare |
|---|---|---|
| 0 | Il dispositivo ha riconosciuto il suo indirizzo (ACK) | Usa questo indirizzo nel codice |
| 1 | Dati troppo lunghi per il buffer | Non compare nello scanner; sull'Uno non scrivere più di 32 byte alla volta |
| 2 | NACK sull'indirizzo | Nessun dispositivo a quell'indirizzo, normale durante la scansione |
| 3 | NACK sui dati | Il dispositivo ha rifiutato il comando; controlla il numero di registro |
| 4 | Altro errore del bus | Cortocircuito, pull-up mancanti o disturbi |
| 5 | Timeout | Il bus è bloccato; controlla cavi e alimentazione |
La riga setWireTimeout dello sketch è importante: quando SDA o SCL sono in cortocircuito, oppure un dispositivo resta bloccato tenendo la linea bassa, la libreria Wire dell'Uno con le impostazioni predefinite può aspettare all'infinito e bloccare il programma. Con il timeout attivo, la libreria si arrende dopo 3 ms, reimposta l'hardware I2C e lo scanner segnala il problema con un codice di errore. La riga è racchiusa in un #if così viene compilata solo sulle schede AVR (Uno, Nano, Mega); le librerie Wire di ESP32 ed ESP8266 hanno già una propria protezione con timeout, quindi lo stesso sketch si compila e funziona senza modifiche su tutte e tre le piattaforme.
I2C senza libreria: leggere e scrivere i registri
Le librerie semplificano il lavoro, ma dietro le quinte fanno tutte la stessa cosa: inviano al dispositivo il numero del registro, poi leggono o scrivono byte in quel registro. Farlo da solo almeno una volta ti permette di leggere il datasheet di un nuovo sensore e usarlo anche senza libreria. L'esempio seguente risveglia il sensore MPU6050 dalla modalità sleep, legge il suo registro di identità (WHO_AM_I) e poi calcola temperatura e accelerazione sull'asse Z dai valori grezzi.

1#include <Wire.h>
2
3const byte MPU_ADDR = 0x68; // AD0 GND'de; AD0 = 3.3V ise 0x69 / AD0 low; 0x69 if AD0 high
4
5void writeReg(byte reg, byte value) {
6 Wire.beginTransmission(MPU_ADDR);
7 Wire.write(reg); // önce yazmaç adresi / register address first
8 Wire.write(value); // sonra veri / then the data
9 Wire.endTransmission(); // STOP gönder / send STOP
10}
11
12int16_t readWord(byte reg) {
13 Wire.beginTransmission(MPU_ADDR);
14 Wire.write(reg);
15 Wire.endTransmission(false); // STOP yok, tekrarlı START / no STOP, repeated START
16 Wire.requestFrom(MPU_ADDR, (byte)2); // 2 bayt iste / request 2 bytes
17 uint8_t hi = Wire.read();
18 uint8_t lo = Wire.read();
19 return (int16_t)(((uint16_t)hi << 8) | lo);
20}
21
22void setup() {
23 Serial.begin(115200);
24 Wire.begin();
25 Wire.setClock(400000); // hızlı mod 400 kHz / fast mode 400 kHz
26 writeReg(0x6B, 0x00); // PWR_MGMT_1: uykudan uyandır / wake up from sleep
27 Wire.beginTransmission(MPU_ADDR);
28 Wire.write(0x75); // WHO_AM_I yazmacı / WHO_AM_I register
29 Wire.endTransmission(false);
30 Wire.requestFrom(MPU_ADDR, (byte)1);
31 Serial.print(F("WHO_AM_I = 0x"));
32 Serial.println(Wire.read(), HEX); // 68 beklenir / expect 68
33}
34
35void loop() {
36 int16_t raw = readWord(0x41); // TEMP_OUT_H ve TEMP_OUT_L / TEMP_OUT_H and TEMP_OUT_L
37 float tempC = raw / 340.0 + 36.53; // veri sayfasındaki formül / datasheet formula
38 int16_t az = readWord(0x3F); // Z ekseni ivmesi / Z-axis acceleration
39 Serial.print(F("Sicaklik / temp: "));
40 Serial.print(tempC, 1);
41 Serial.print(F(" C AccZ: "));
42 Serial.println(az / 16384.0, 2); // +-2g aralığında 16384 = 1 g / 16384 = 1 g at +-2g
43 delay(500);
44}Fai attenzione alla riga endTransmission(false) nella funzione di lettura: cambia direzione con uno START ripetuto invece di uno STOP, così nessun altro dispositivo può inserirsi e il sensore non dimentica quale registro è stato richiesto. Se WHO_AM_I restituisce 0x68, la comunicazione è perfetta. Sui moduli clone economici il valore può essere 0x70 o un altro numero; significa che il chip è un modello compatibile ma diverso, come l'MPU6500, ed è il motivo per cui alcune librerie pronte segnalano «sensore non trovato». La formula della temperatura (valore grezzo / 340 + 36,53) viene direttamente dal datasheet dell'MPU6050; per l'accelerazione nell'intervallo ±2 g un valore grezzo di 16384 corrisponde a 1 g, quindi un sensore appoggiato piatto sul tavolo segna circa 1,00 sull'asse Z.
Più dispositivi sullo stesso bus e conflitti di indirizzo
Il grande vantaggio dell'I2C è che puoi collegare i dispositivi in parallelo agli stessi due fili, purché abbiano indirizzi diversi. Per esempio, un LCD (0x27), un OLED (0x3C), un BMP280 (0x76) e un orologio DS3231 (0x68) condividono senza problemi i pin A4 e A5; ogni libreria parla con il proprio indirizzo mentre gli altri dispositivi ascoltano in silenzio. I guai iniziano quando due dispositivi hanno lo stesso indirizzo: entrambi rispondono con ACK, i loro dati si sovrappongono e di solito nessuno dei due funziona. Ecco le soluzioni:
- Cambia il pin di indirizzo: Se colleghi il pin AD0 dell'MPU6050 a 3,3 V, il suo indirizzo diventa 0x69 e il conflitto con il DS3231 (0x68) sparisce.
- Usa i ponticelli a saldare: I ponticelli A0–A2 dei moduli LCD offrono 8 indirizzi e il pin ADDR dell'ADS1115 ne offre 4.
- Apri un secondo bus I2C: Sposta il dispositivo in conflitto su altri pin con Wire1 sull'ESP32 o con I2C1 sul Pico.
- Aggiungi un multiplexer I2C: Il TCA9548A apre otto sotto-bus separati partendo da un solo indirizzo (0x70); potresti collegare perfino otto OLED con lo stesso indirizzo.
- Dispositivi con indirizzo fisso: In alcuni chip, come il DS1307 o l'HTU21D, l'indirizzo non si può cambiare affatto; con loro funzionano solo un bus separato o un multiplexer.
I2C con l'ESP32: i pin che vuoi e due bus separati
Sull'ESP32 l'hardware I2C può essere assegnato ai pin in modo flessibile. I pin predefiniti sono GPIO 21 (SDA) e GPIO 22 (SCL), ma con Wire.begin(SDA, SCL) puoi scegliere quasi qualsiasi coppia di GPIO. L'ESP32 classico e l'ESP32-S3 hanno due controller I2C, quindi puoi far funzionare due sensori con lo stesso indirizzo su due bus separati; l'ESP32-C3 ha invece un solo controller. I GPIO 34–39 sono solo ingressi e non si possono usare per l'I2C. Per la mappa completa dei pin della scheda consulta lo strumento Pinout, e per un'introduzione generale l'articolo Cos'è l'ESP32?.
1#include <Wire.h>
2
3// Klasik ESP32'de iki I2C denetleyicisi vardır: Wire ve Wire1 / the classic ESP32 has two I2C controllers: Wire and Wire1
4
5void scan(TwoWire &bus, const char *name) {
6 Serial.printf("%s:\n", name);
7 for (uint8_t addr = 0x08; addr <= 0x77; addr++) {
8 bus.beginTransmission(addr);
9 if (bus.endTransmission() == 0) {
10 Serial.printf(" bulundu / found 0x%02X\n", addr);
11 }
12 }
13}
14
15void setup() {
16 Serial.begin(115200);
17 Wire.begin(21, 22); // SDA, SCL: varsayılan pinler / default pins
18 Wire1.begin(32, 33, 400000); // SDA, SCL, hız: başka iki GPIO / SDA, SCL, speed: any two other GPIOs
19 scan(Wire, "Wire (SDA 21, SCL 22)");
20 scan(Wire1, "Wire1 (SDA 32, SCL 33)");
21}
22
23void loop() {
24}I2C con il Raspberry Pi Pico (MicroPython)
Il chip RP2040 del Pico ha due controller chiamati I2C0 e I2C1, e ciascuno può essere assegnato a diverse coppie di pin. Per I2C0 puoi usare GP0/GP1, GP4/GP5, GP8/GP9, GP12/GP13, GP16/GP17 e GP20/GP21; per I2C1 GP2/GP3, GP6/GP7, GP10/GP11, GP14/GP15, GP18/GP19 e GP26/GP27. In ogni coppia il pin con numero pari è SDA e quello dispari è SCL. In MicroPython lo scanner è una sola riga: i2c.scan() restituisce l'elenco degli indirizzi che rispondono con ACK. Dato che il Pico lavora a 3,3 V, alimentare i moduli dal pin 3V3(OUT) è la soluzione più sicura; anche se l'RP2040 supporta pure il Fast mode plus da 1 MHz, restare a 400 kHz su una breadboard riserva meno sorprese. Per i primi passi con il Pico leggi Cos'è il Raspberry Pi Pico?.
1from machine import Pin, I2C
2
3i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000) # I2C0: GP4 = SDA, GP5 = SCL
4devices = i2c.scan() # ACK veren adresler / addresses that ACK
5
6if devices:
7 for addr in devices:
8 print("Bulundu / found:", hex(addr))
9else:
10 print("Cihaz yok / no devices")
11
12# MPU6050 varsa WHO_AM_I yazmacını oku / if an MPU6050 is present, read WHO_AM_I
13if 0x68 in devices:
14 i2c.writeto_mem(0x68, 0x6B, b"\x00") # uykudan uyandır / wake up
15 who = i2c.readfrom_mem(0x68, 0x75, 1)[0]
16 print("WHO_AM_I:", hex(who)) # 0x68 beklenir / expect 0x68Idee di progetti con l'I2C
- Mini stazione meteo: Misura pressione e temperatura con un BMP280 e mostrale su un display OLED; i due moduli condividono gli stessi due fili.
- Orologio digitale: Leggi l'ora da un modulo DS3231 e scrivila su un display LCD I2C.
- Indicatore di inclinazione: Calcola l'angolo con un MPU6050 e disegna il risultato sull'OLED come una livella a bolla.
- Nodo sensore Wi-Fi: Controlla dal telefono un sensore collegato ai pin D1 e D2 di un ESP8266 NodeMCU.
- Braccio robotico a 16 servo: Comanda 16 servo con soli due pin grazie al driver PCA9685.
- Data logger: Scrivi una misura al minuto in una EEPROM AT24C256, così i dati sopravvivono a un'interruzione di corrente.
Errori comuni e soluzioni
| Sintomo | Causa probabile | Soluzione |
|---|---|---|
| Lo scanner non trova nessun dispositivo | SDA e SCL invertiti, manca la massa comune o il modulo non è alimentato | Controlla i collegamenti; sull'Uno A4 = SDA e A5 = SCL |
| Lo scanner si blocca o dà errore a ogni indirizzo | Bus in cortocircuito o pull-up mancanti | Aggiungi setWireTimeout; misura la tensione di alimentazione su SDA e SCL a riposo |
| Lo sketch compila ma il display resta vuoto | Indirizzo sbagliato nel codice (0x27 invece di 0x3F) | Inserisci l'indirizzo trovato dallo scanner |
| Sul retro c'è scritto 0x78 e il codice non funziona | È stato usato l'indirizzo a 8 bit | Dividi per 2: 0x78 → 0x3C |
| Due sensori non funzionano insieme | Conflitto di indirizzo | Cambia il pin di indirizzo, usa un secondo bus o un TCA9548A |
| Blocchi casuali, errori quando parte un motore | Cavi lunghi, disturbi o alimentazione debole | Accorcia i cavi, scendi a 100 kHz, aggiungi condensatori da 100 nF ai moduli |
| Un pin dell'ESP32 o del Pico si è danneggiato | Pull-up collegate a 5 V su un pin a 3,3 V | Alimenta il modulo a 3,3 V o usa un convertitore di livello |
L'I2C è il modo più pratico per aggiungere display, orologi, sensori e memoria al tuo progetto con soli due fili; una volta capiti gli indirizzi, le resistenze pull-up e lo sketch scanner, risolverai la maggior parte dei problemi in pochi minuti. Nell'app BlueGrays trovi progetti che usano l'I2C, come il display LCD I2C, il gioco Pong su display OLED, un orologio digitale con DS1307 e un display meteo con ESP32, con schemi elettrici e codice passo dopo passo.
Domande frequenti
Qual è la differenza tra I2C e SPI?
L'I2C usa gli indirizzi per collegare più di cento dispositivi agli stessi due fili, ma di solito è limitato a 100–400 kHz. L'SPI richiede tre fili condivisi e un pin di selezione (CS) per ogni dispositivo; in cambio raggiunge 10 MHz e oltre. Per sensori e piccoli display si preferisce l'I2C, per schede SD e display TFT a colori l'SPI.
Quanti dispositivi si possono collegare a un bus I2C?
Con l'indirizzamento a 7 bit ci sono 112 indirizzi utilizzabili. In pratica il limite dipende meno dal numero di indirizzi e più dalla capacità del bus (al massimo 400 pF) e dalle resistenze pull-up in parallelo; su una breadboard 5–10 dispositivi funzionano senza problemi. Per averne di più usa un multiplexer TCA9548A o un secondo bus I2C.
Che valore devono avere le resistenze pull-up I2C?
I valori più comuni sono 4,7 kΩ per 100 kHz e cavi corti, e 2,2 kΩ per 400 kHz o per bus con molti dispositivi. Non scendere sotto 1,5 kΩ su un bus a 5 V né sotto 1 kΩ su un bus a 3,3 V. Ricorda anche che le resistenze presenti sui moduli finiscono in parallelo.
Quali sono i pin I2C di Arduino Uno?
Su Arduino Uno e Nano, SDA è il pin A4 e SCL il pin A5. L'Uno R3 ha altri due pin marcati SDA e SCL accanto ad AREF, ma sulla scheda sono collegati ad A4 e A5 e non formano un bus separato. Sul Mega i pin I2C sono il 20 (SDA) e il 21 (SCL).
Qual è la lunghezza massima di un cavo I2C?
L'I2C è stato progettato per brevi distanze sulla stessa scheda; a 100 kHz e con pull-up adeguate di solito funziona fino a circa 1 metro. Per distanze maggiori bisogna ridurre la velocità, usare cavi a coppie intrecciate o passare a driver di bus come il P82B715. Per diversi metri sono una scelta migliore l'RS-485 o un collegamento wireless.
Cosa fare se lo scanner I2C non trova il mio dispositivo?
Controlla prima che SDA e SCL siano sui pin giusti, che la massa comune sia collegata e che il modulo sia alimentato. Verifica poi le pull-up misurando la tensione di alimentazione su SDA e SCL a riposo. Se ancora non compare, prova il modulo da solo con cavi corti a 100 kHz e, sull'ESP32, assicurati di passare i pin corretti a Wire.begin.
Progetti da realizzare dopo questo articolo
Vedi tutti i progetti
Utilizzo dello schermo LCD con I2C
Grazie al modulo I2C, il progetto che stampa messaggi controllando lo schermo LCD con solo 2 cavi (SDA, SCL). Insegna come salvare i pin con il protocollo I2C.

Schermo LCD I2C per ESP32 (16x2)
In questo progetto visualizziamo del testo collegando un display LCD a 16x2 caratteri all'ESP32 tramite il protocollo I2C. Grazie all'I2C possiamo controllare il display utilizzando solo 2 pin di dati (SDA e SCL); si elimina così lo spreco dei 6+ pin tipici del collegamento parallelo classico. Il codice stampa un messaggio fisso sulla prima riga e un contatore che aumenta ogni secondo sulla seconda riga. Inoltre, all'inizio, eseguendo lo scanner I2C, stampiamo l'indirizzo del display sul Serial

Orologio digitale con ESP32 e RTC DS1307 (I2C + LCD)
In questo progetto, utilizziamo il modulo orologio in tempo reale (RTC) DS1307 per visualizzare l'ora e la data su un display LCD 16x2 I2C. Il DS1307 è un RTC con batteria di supporto che mantiene l'ora anche se l'ESP32 si spegne. Entrambi i moduli condividono la stessa linea I2C (SDA/SCL), permettendoci di imparare a controllare più dispositivi utilizzando solo due cavi di segnale. Cosi imparerai il protocollo I2C e il funzionamento dei moduli RTC nella pratica.

Calcolatrice Arduino I2C
Si tratta di un progetto di calcolatore basato su Arduino che esegue operazioni di addizione, sottrazione, moltiplicazione e divisione utilizzando una tastiera a membrana 4x4 e un display LCD I2C 16x2. Grazie all'I2C, il collegamento del display avviene con soli 2 cavi, riducendo così l'ingombro dei cavi e mantenendo un maggior numero di pin utilizzabili. Sono inoltre disponibili l'ingresso di numeri decimali e il supporto di numeri negativi.

Gioco Pong - SSD1306
Il classico gioco del Pong costruito con Arduino e display OLED SSD1306, dotato di un'intelligenza artificiale (CPU) autonoma che segue istantaneamente i movimenti della palla e reagisce in base alla

ESP32 HTTPClient + API meteo (con display OLED SSD1306)
In questo progetto, utilizzando l'ESP32, effettuiamo una chiamata REST all'API meteo (wttr.in) tramite Internet utilizzando `HTTPClient.h`. A differenza della precedente versione con LCD I2C, qui utilizziamo un display OLED SSD1306 (128×64), che consente di utilizzare caratteri di grandi dimensioni, icone vettoriali e una ricca presentazione visiva su un unico schermo. Per le condizioni meteorologiche, 7 diverse icone vettoriali (soleggiato, parzialmente nuvoloso, nuvoloso, piovoso, nevoso, temp

Orologio e calendario a matrice di punti (MAX7219, DS1307)
Si tratta di un progetto che visualizza informazioni sull'orologio e sul calendario in tempo reale su un display LED a matrice di punti MAX7219 8x32 con modulo RTC DS1307. Nel display dell'orologio, d

Data Logger di Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
Costruisci un data logger di temperatura con timestamp usando ESP32! Leggi temperatura/umidità dal DHT22 ogni 10 secondi, ottieni l'ora reale dal DS1307 RTC e registra su scheda microSD in formato CSV. L'OLED mostra dal vivo temperatura (font grande), percentuale di umidità, timestamp e contatore di log. Il file `/temp_log.csv` sulla scheda SD si apre in Excel, Google Sheets o Python pandas per l'analisi — perfetto per il monitoraggio di serre, tracciamento della temperatura domestica, raccolta
Altri articoli
Impara il protocollo I2C, che ti permette di collegare decine di sensori e display con soli due fili: indirizzi, resistenze pull-up, uno sketch scanner I2C e le soluzioni agli errori più comuni, con esempi pratici.

