La Comunicazione I2C arduino to arduino è un argomento che spesso mi è stato richiesto nei commenti e sul quale la documentazione che ho trovato in rete è tanta ma spesso confusionaria.
Da qualche giorno con un amico, Paolo, abbiamo deciso di fare dei test in merito alla possibilità di sfruttare l’I2C per trasmettere messaggi da un arduino ad un altro.
Paolo è un fisico ed è l’autore del conduttimetro, utilizzato nell’orto idroponico, per cui le prime trasmissioni abbiamo deciso di eseguirle con dei valori numerici interi in modo da poter utilizzare come test successivo il conduttimetro di Paolo.
Accenni di teoria
In una comunicazione I2C deve essere presente un Master ed uno, o più Slave, ossia un nodo principale ( Master I2C ) ed uno, o più nodi, secondario ( Slave I2C )
Il compito del Master è di gestire tutta la comunicazione I2C sia inviando i messaggi a tutti gli slave connessi, sia richiedendo a ciascun slave di inviargli un messaggio.
Per eseguire il test puoi usare, come abbiamo fatto noi, due arduino uno.
Schema per la Comunicazione I2C arduino to arduino
Per i test puoi usare due Arduino uno collegandoli come nello schema:
nei test che abbiamo eseguito l’alimentazione di ciascun arduino è avvenuta con il cavo USB e per rendere l’esperimento allo stesso tempo divertente e ricco di suspence ad alimentare l’arduino usato come Master c’era il Pc di Paolo e per l’alimentazione dell’arduino usato come slave ho usato il mio Mac, più variabili non potevamo introdurle; ecco perché nella foto che mostra i collegamenti non c’è il cavo positivo ( +5v ) ad unire i due arduino:
Lo sketch Master
lo sketch Master si preoccupa di inviare allo slave 3 messaggi distinti da un carattere prima di ciascun messaggio:
- $ per un messaggio da 12 byte
- W per un messaggio simile al 12 ma con funzionalità Slave differenti
- M per un messaggio da 13 byte e valori differenti dai precedenti
Lo scopo dell’esperimento è finalizzato alla realizzazione di un progetto più complesso di cui questo scketch rappresenta solo il primo passo relativo alla Comunicazione I2C arduino to arduino.
#include <Wire.h> int ECHO = 1; byte header=0; byte i = 0; word CSspec = 0; // Conducibilità corretta word Temp = 0; // Temperatura acqua word Vcc = 0; // alimentazione in mV byte vettore[12] = {0,0,0,0,0,0,0,0,0,0}; byte flag; word RS; word CS; void setup() { Serial.begin(9600); delay(1000); Wire.begin(); } void loop() { flag = '$'; header = 14; //ID nodo RS = 1230; // resistenza acqua ohm CS = 4589; // Conducibilità a 20° uS CSspec = 3250; // Conducibilità specifica uS/cm Temp = 2734; // Temperatura in 0,1 °K Vcc = 3300; // Alimentazione in mV vettore[0] = highByte(RS); vettore[1] = lowByte(RS); vettore[2] = highByte(CS); vettore[3] = lowByte(CS); vettore[4] = highByte(CSspec); vettore[5] = lowByte(CSspec); vettore[6] = highByte(Temp); vettore[7] = lowByte(Temp); vettore[8] = highByte(Vcc); vettore[9] = lowByte(Vcc); Wire.beginTransmission(8); // transmit to device #8 Wire.write(flag); Serial.print(flag,HEX); Serial.print(" "); Serial.print(header,HEX); Serial.print(" "); Wire.write(header); for(i=0; i < 10; i++){ Wire.write(vettore[i]); Serial.print(vettore[i],HEX);Serial.print(" "); } Wire.endTransmission(); // stop transmitting Serial.println(); flag = 'W'; Wire.beginTransmission(8); // transmit to device #8 Wire.write(flag); Serial.print(flag,HEX); Serial.print(" "); Serial.print(header,HEX); Serial.print(" "); Wire.write(header); for(i=0; i < 10; i++){ Wire.write(vettore[i]); Serial.print(vettore[i],HEX);Serial.print(" "); } Wire.endTransmission(); // stop transmitting Serial.println(); flag = 'M'; word M1 = 4760; // Conducibilità specifica uS/cm media nodo 1 word M2 = 3440; // Conducibilità specifica uS/cm media nodo 2 word M3 = 2160; // Conducibilità specifica uS/cm media nodo 3 word T1 = 2734; // Temperatura in 0,1 °K media nodo 1 word T2 = 2823; // Temperatura in 0,1 °K media nodo 21 word T3 = 2947; // Temperatura in 0,1 °K media nodo 3 vettore[0] = highByte(M1); vettore[1] = lowByte(M1); vettore[2] = highByte(M2); vettore[3] = lowByte(M2); vettore[4] = highByte(M3); vettore[5] = lowByte(M3); vettore[6] = highByte(T1); vettore[7] = lowByte(T1); vettore[8] = highByte(T2); vettore[9] = lowByte(T2); vettore[10] = highByte(T3); vettore[11] = lowByte(T3); Wire.beginTransmission(8); // transmit to device #8 Wire.write(flag); Serial.print(flag,HEX); Serial.print(" "); for(i=0; i < 12; i++){ Wire.write(vettore[i]); Serial.print(vettore[i],HEX);Serial.print(" "); } Wire.endTransmission(); // stop transmitting Serial.println(); delay(2000); }
leggendo lo sketch linea per linea noti che alla linea 01: includi la libreria Wire.h necessaria per la gestione della Comunicazione I2C arduino to arduino;
linee 03-12: definisci le variabili che ti serviranno nello sketch per memorizzare i dati da trasmettere;
linee 15-17: inizializza la comunicazione seriale a 9600 baud, attendi 1 secondo ( 1000 millisecondi ) ed inizializza la comunicazione I2C con il metodo begin() della libreria Wire;
linee 23-29: imposta i valori da inviare via I2C, osserva in particolare il valore della variabile flag e della variabile header che saranno identificativi in funzione dei quali lo Slave deciderà dove destinare il messaggio che riceve. Le restanti variabili contengono i dati che trasmetterai;
linee 31-40: definisci un array di tipo byte in cui ciascun elemento contiene un byte da trasferire allo slave I2C. Se osservi le linee 31 e 32 noti che il valore RS è scomposto in 2 byte, in quanto sappiamo che sono sufficienti 2 byte per rappresentare il dato numerico contenuto nella variabile RS, ed in particolare il byte più alto lo inseriamo nell’indice 0 del vettore mentre il byte più basso nell’indice 1. Nelle linee successive, fino alla 40, scomponi e inserisci i restanti valori negli altri elementi del vettore;
linea 42: con il metodo beginTransmission() inizi una trasmissione verso l’indirizzo contenuto tra parentesi, abbiamo deciso di utilizzare il valore 8 che troverai anche in altri numerosi esempi su internet.
linea 43: con il metodo write() invii allo Slave 8, l’altro arduino in questo esempio, il valore contenuto tra parentesi, in questa linea il valore flag;
linee 44-45: scrivi sul monitor seriale i valori relativi a flag e header;
linea 46: così come fatto alla linea 43, invia il valore di header;
linee 47-50: crea un ciclo for per tutta la lunghezza del vettore, in questo esempio da 0 a 9, e per ciascun valore di i invia il dato contenuto nell’elemento del vettore corrispondente, scrivendolo anche sul monitor seriale;
linee 51-52: indica la conclusione della trasmissione I2C con il metodo endTransmission() della libreria Wire;
linee 54-65: sono identiche alle linee 42-52 a parte la linea 54 che ridefinisce il valore di flag cambiandone il valore in “W”;
linea 67: ridefinisci nuovamente il valore per la variabile flag in modo che l’ultima sequenza inviata inizi con il valore “M”
linee 68-73: definisci 6 variabili di tipo word in ciascuna delle quali inserisci i nuovi valori da inviare;
linee 75-86: scomponi le variabili definite alle linee 68-73 in un vettore simile a quello creato alle linee 31-40 scomponendo ciascuno dei sei valori in due elementi;
linee 88-96: trasmetti il flag via I2C allo slave con indirizzo 8 e successivamente i 12 byte in sequenza;
linea 97: attendi 2 secondi prima di ripetere il loop() e quindi l’invio.
Nel prossimo articolo leggerai il codice che abbiamo usato per ricevere i dati sull’arduino slave I2C.
13 commenti
Vai al modulo dei commenti
Dove e’ la seconda parte ? lo sketch con indirizzo 08 ?
Autore
Ciao Armando,
fossi in te io proverei a cercare nel blog.
Ciao, ho provato a cercare sul blog ma non ho trovato l’articolo con lo sketch dello slave.
Sono interessato a questo articolo per un progetto che prevede Raspberry e Arduino per un dolly computerizzato ed estendibile.
Scusa il disturbo e buone vacanze
Autore
Ciao Francesco,
come esempio per comprendere la descrizione di uno sketch i2c slave con arduino puoi utilizzare quello descritto in questo articolo:
https://www.mauroalfieri.it/elettronica/attiny85-encoder-arduino-slave.html
ovviamente dovrai adattarlo alle tue esigenze, ti serve solo per comprendere come funziona il discorso master-slave i2c.
Tutto molto interessante. Suggerirei di ampliare la descrizione del codice, e di definire più precisamente i fattori.
Autore
Ciao Marco,
grazie per il suggerimento, mi descrivi meglio cosa intendi per “definire più precisamente i fattori” ?
Ciao,
devo fare una comunicazione I2C tra un Arduino UNO e un Arduino Mega.
Quali sono i collegamenti?
Grazie
Autore
Ciao Matteo,
sulla uno sono quelli che vedi nello schema di questo articolo, sulla Mega puoi consultare il datasheet pubblico sul sito arduino.cc
splendido articolo mi piacerebbe provarlo ma non trovo il link alla parte slave
Autore
Ciao Andrea,
hai ragione, forse me lo sono perso, per ovviare puoi adattare uno degli articoli simili al seguente ( https://www.mauroalfieri.it/elettronica/i2c-attiny85-slave-adc.html ) in cui al posto dell’arduino ho usato un Attiny85.
I concetti sono i medesimi e cambiano solo le librerie che per l’Attiny85 sono più leggere mentre per Arduino puoi usare la Wire come per il Master.
Ciao Mauro.
Intanto complimenti per il sito e per i tantissimi tutorial, chiari e semplici.
Non riesco però a trovare la seconda puntata de “Comunicazione I2C arduino to arduino” (quella dello slave)
Mi potresti dare il link diretto?
Grazie infinite e complimenti ancora
Luigi
Autore
Ciao Luigi,
non sei il primo che mi segnala la cosa, in realtà mi sono accorto di non averlo mai pubblicato e lo farò appena possibile.
Nell’attesa se vuoi puoi leggere gli articoli dedicati alla comunicazione I2C con Attiny85 ed adattare la parte slave di uno di quei progetti.
Ciao Mauro
Complimenti per il tuo sito e per i tuoi chiarissimi articoli.
Non riesco a trovare il link alla seconda parte (relativa allo slave) di questo articolo (Comunicazione I2C arduino to arduino).
Saresti così gentile da dirmelo?
Grazie
Luigi