Il popolare protocollo I2C consente la comunicazione tra due o più schede Arduino. Scopri come collegarli e codificarli.

Mentre un singolo Arduino può svolgere molte attività, alcuni progetti potrebbero richiedere l'uso di più di una scheda per gestire funzionalità diverse. Quindi, per consentire il trasferimento dei dati tra i due microcontrollori, è necessario impostare un protocollo di comunicazione come CAN, SPI, I2C o UART.

In questa guida tratteremo le basi del funzionamento di I2C, le connessioni hardware e l'implementazione del software necessarie per configurare due schede Arduino come dispositivi I2C master e slave.

Cos'è l'I2C?

Inter-Integrated Circuit (I2C) è un protocollo di comunicazione ampiamente utilizzato nei sistemi embedded e nei microcontrollori per consentire il trasferimento di dati tra dispositivi elettronici. A differenza di SPI (Serial Peripheral Interface), I2C consente di collegare più di un dispositivo master a un bus con uno o più dispositivi slave. È stato utilizzato per la prima volta da Philips ed è noto anche come protocollo di comunicazione Two Wire Interface (TWI).

instagram viewer

Come funziona la comunicazione I2C?

I2C utilizza due linee bidirezionali: Serial Data (SDA) e Serial Clock (SCL) per trasferire i dati e sincronizzare la comunicazione tra i dispositivi. Ogni dispositivo connesso al bus I2C ha un indirizzo univoco che lo identifica durante la comunicazione. Il protocollo I2C consente a più dispositivi di condividere lo stesso bus e ogni dispositivo può fungere da master o da slave.

La comunicazione viene avviata dal dispositivo master e l'indirizzamento errato dei dispositivi slave può causare errori nel trasferimento. Consulta la nostra guida approfondita su come funzionano le comunicazioni seriali UART, SPI e I2C per darti un po' di contesto.

Uno dei principali vantaggi della comunicazione I2C degno di nota è la flessibilità che offre quando si tratta di gestione dell'alimentazione. I dispositivi che operano a diversi livelli di tensione possono comunque comunicare in modo efficace con l'aiuto di variatori di tensione. Ciò significa che i dispositivi che funzionano a 3,3 V necessitano di variatori di tensione per connettersi a un bus I2C a 5 V.

La biblioteca del filo

La libreria Wire è una libreria Arduino integrata che fornisce funzioni per comunicare su I2C. Utilizza due pin, SDA e SCL, sulla scheda Arduino per la comunicazione I2C.

Pin I2C su Arduino Uno:

Pin Arduino Nano I2C:

Per utilizzare la libreria, è necessario includere il file Filo.h file di intestazione all'inizio del tuo schizzo Arduino.

#includere

La libreria Wire fornisce funzioni per avviare la comunicazione con un dispositivo I2C, inviare dati e ricevere dati. Alcune funzioni importanti che dovresti conoscere includono:

  • Wire.begin(): utilizzato per unire il bus I2C e avviare la comunicazione.
  • Wire.beginTransmission(): utilizzato per specificare l'indirizzo dello slave e iniziare una trasmissione.
  • Wire.write(): utilizzato per inviare dati al dispositivo I2C.
  • Wire.endTransmission(): utilizzato per terminare la trasmissione e verificare la presenza di errori.
  • Wire.requestFrom(): utilizzato per richiedere dati al dispositivo I2C.
  • Wire.disponibile(): utilizzato per verificare se i dati sono disponibili per la lettura dal dispositivo I2C.
  • Wire.read(): utilizzato per leggere i dati dal dispositivo I2C.

Usa il Wire.beginTransmission() funzione per impostare l'indirizzo del sensore, che viene inserito come argomento. Ad esempio, se l'indirizzo del sensore è 0x68, useresti:

Filo.beginTransmission(0x68);

Configurazione dell'hardware Arduino I2C

Per connettere due schede Arduino utilizzando I2C, avrai bisogno dei seguenti componenti hardware:

  • Due schede Arduino (master e slave)
  • Tagliere
  • Fili di ponticello
  • Due resistori pull-up da 4,7kΩ

Collega il SDA E SCL pin di entrambe le schede Arduino su una breadboard. Collegare le resistenze di pull-up tra i SDA E SCL perni e il 5V power rail sulla breadboard. Infine, collega le due breadboard usando i ponticelli.

Circuito Arduino Uno

Circuito Nano Arduino

Credito immagine: Documentazione Arduino I2C

Configurazione delle schede Arduino come dispositivi master e slave I2C

Usa il Wire.requestFrom() funzione per specificare l'indirizzo del dispositivo slave con cui vogliamo comunicare. Quindi usa il Wire.read() funzione per ottenere dati dal dispositivo slave.

Codice dispositivo principale:

#includere
vuotoimpostare(){
Filo.inizio(); // unisciti al bus i2c
Seriale.inizio(9600); // avvia la seriale per l'output
}
vuotoricevereDati(){
int indirizzo = 8;
int bytesToRead = 6;
Filo.richiesta da(indirizzo, bytesToRead);
Mentre (Filo.disponibile()) {
char dati = Filo.Leggere();
Seriale.stampa(dati);
}
ritardo(500);
}
vuotociclo continuo(){
ricevereDati();
}

IL Wire.onReceive() La funzione viene utilizzata per specificare cosa fare quando lo slave riceve i dati dal dispositivo master. Nel codice sopra, il Wire.disponibile() la funzione controlla se i dati sono disponibili e il Wire.read() funzione legge i dati inviati dal dispositivo master.

Codice dispositivo slave:

#includere
vuotoimpostare(){
Filo.inizio(8); // unisciti al bus I2C con indirizzo 8
Filo.onRicevi(ricevereEvento); // chiama receiveEvent quando i dati vengono ricevuti
}
vuotociclo continuo(){
ritardo(100);
}
vuotoricevereEvent(int byte){
Filo.scrivere("Ciao "); // risponde con un messaggio di 6 byte come previsto dal master
}

Invio e ricezione di dati tramite I2C

In questo esempio leggiamo la temperatura da un sensore di temperatura DHT11 interfacciato con lo slave Arduino e stampiamola sul monitor seriale del master Arduino.

Modifichiamo il codice che abbiamo scritto in precedenza per includere la misurazione della temperatura che poi invieremo alla scheda master tramite il bus I2C. La scheda master può quindi leggere il valore che abbiamo inviato, quindi visualizzarlo sul monitor seriale.

Codice dispositivo principale:

#includere
vuotoimpostare(){
Filo.inizio();
Seriale.inizio(9600);
Seriale.println("Maestro inizializzato!");
}
vuotociclo continuo(){
Filo.richiesta da(8, 1); // Richiedi i dati di temperatura dallo slave
Se (Filo.disponibile()) {
byte temperatura = Filo.Leggere(); // Legge i dati di temperatura dallo slave
Seriale.stampa("Temperatura: ");
Seriale.stampa(temperatura);
Seriale.println("°C");
}
ritardo(2000); // Attendi 2 secondi prima di richiedere nuovamente la temperatura
}

Codice dispositivo slave:

#includere
#includere

#definire PIN DHTP 4 // Pin collegato al sensore DHT
#definire DHTTYPE DHT11 // Tipo di sensore DHT
DHT dht(DHTPIN, DHTTYPE);
byte temperatura;

vuotoimpostare(){
Filo.inizio(8); // L'indirizzo dello slave è 8
Filo.su richiesta(richiestaEvento);
dht.inizio();
}

vuotociclo continuo(){
ritardo(2000); // Attendi 2 secondi affinché il DHT si stabilizzi
temperatura = dht.leggiTemperatura(); // Legge la temperatura dal sensore DHT
}

vuotorequestEvent(){
Filo.scrivere(temperatura); // Invia i dati di temperatura al master
}

Puoi personalizzare questo codice per adattarlo a qualsiasi sensore tu possa avere nel tuo progetto, o persino visualizzare i valori del sensore su un modulo display per crea il tuo termometro e misuratore di umidità per la tua stanza.

Indirizzamento slave con I2C su Arduino

Per leggere i valori dai componenti aggiunti a un bus I2C in un tale progetto, è importante includere l'indirizzo slave corretto durante la codifica. Fortunatamente, Arduino offre una libreria scanner che semplifica il processo di identificazione dello slave indirizzi, eliminando la necessità di vagliare lunghe schede dati dei sensori e creare confusione online documentazione.

Utilizzare il seguente codice per identificare l'indirizzo di qualsiasi dispositivo slave presente sul bus I2C.

#includere // Include la libreria Wire per la comunicazione I2C

vuotoimpostare(){
Filo.inizio(); // Inizializza la comunicazione I2C
Seriale.inizio(9600); // Inizializza la comunicazione seriale con un baud rate di 9600
Mentre (!Seriale); // Attendi che venga stabilita la connessione seriale
Seriale.println("\nScanner I2C"); // Stampa un messaggio che indica l'inizio della scansione I2C
}

vuotociclo continuo(){
byte errore, indirizzo; // Dichiara le variabili per memorizzare gli errori e gli indirizzi dei dispositivi
int nDispositivi; // Dichiara una variabile per memorizzare il numero di dispositivi trovati

Seriale.println("Scansione..."); // Stampa un messaggio che indica l'inizio della scansione I2C

nDispositivi = 0; // Imposta il numero di dispositivi trovati su 0
per (indirizzo = 1; indirizzo < 127; indirizzo++) { // Itera su tutti i possibili indirizzi I2C
Filo.beginTransmission(indirizzo); // Avvia una trasmissione all'indirizzo corrente
errore = Filo.endTransmission(); // Termina la trasmissione e memorizza eventuali errori

Se (errore == 0) { // Se non sono stati trovati errori
Seriale.stampa("Dispositivo I2C trovato all'indirizzo 0x"); // Stampa un messaggio che indica che è stato trovato un dispositivo
Se (indirizzo < 16) Seriale.stampa("0"); // Se l'indirizzo è minore di 16, aggiungi uno 0 iniziale per motivi di formattazione
Seriale.stampa(indirizzo, HEX); // Stampa l'indirizzo in formato esadecimale
Seriale.println(" !"); // Stampa un messaggio che indica che è stato trovato un dispositivo

nDispositivi++; // Incrementa il numero di dispositivi trovati
}
altroSe (errore == 4) { // Se è stato trovato un errore
Seriale.stampa("Errore sconosciuto all'indirizzo 0x"); // Stampa un messaggio che indica che è stato trovato un errore
Se (indirizzo < 16) Seriale.stampa("0"); // Se l'indirizzo è minore di 16, aggiungi uno 0 iniziale per motivi di formattazione
Seriale.println(indirizzo, HEX); // Stampa l'indirizzo in formato esadecimale
}
}
Se (nDispositivi == 0) { // Se non sono stati trovati dispositivi
Seriale.println("Nessun dispositivo I2C trovato\n"); // Stampa un messaggio che indica che non sono stati trovati dispositivi
}
altro { // Se sono stati trovati dispositivi
Seriale.println("fatto\n"); // Stampa un messaggio che indica la fine della scansione I2C
}
ritardo(5000); // Ritardo di 5 secondi prima di iniziare la scansione successiva
}

Espandi il tuo progetto oggi

L'interfacciamento di due schede Arduino utilizzando il protocollo di comunicazione I2C offre un modo flessibile ed efficiente per eseguire attività complesse che non possono essere gestite da una singola scheda. Con l'aiuto della libreria Wire, la comunicazione tra le due schede tramite I2C è semplificata, consentendoti di aggiungere più componenti al tuo progetto.