I²C Inter Integrated Circuit
Arduino Master e Slave
5 Marzo 2014
Continua la sperimentazione sull'uso della libreria Wire.
Realizziamo il collegamento come sopra.
Io ho usato due Arduino UNO r3.
Potete seguire anche altro schema e / o collegare schede Arduino diverse, in questo caso consultate il sito arduino oppure il post precedente perchè nelle varie schede di Arduino i pin SDA e SCL possono essere diversi.
Negli esempi della libreria Wire lo schema di collegamento è senza le due resistenze ( 2,2k) io le ho lasciate.
Ho preso uno degli esempi per l'uso della libreria ed ho apportato semplici modifiche.
Quello che ho vuluto provare con questa esperienza è il trasferimento da una scheda Master ad una scheda Slave, di numeri composti da più byte ( interi, long, float).
Sul forum arduino ho trovato la soluzione che ho utilizzato in questo sketch.
Gli sketch in realtà sono due uno per il master ed uno per lo slave.
Vogliamo trasmettere un intero ( due byte),
Sarà quindi il master che inzia la trasmissione con
Wire.beginTransmission(4); indicando l'idirizzo dello slave in questo caso 4.
Quindi trasmette i due byte
Wire.write(a1); // invia un byte
Wire.write(a2); // invia il secondo byte
Wire.write(a2); // invia il secondo byte
Infine chiude la trasmissione.
Wire.endTransmission(); // stop transmitting
Prima di questa operazione bisogna scomporre l'intero in due byte, io ho fatto così:
a1 = byte(mioInt); // si scompone l'intero in 2 byte
a2 = byte( mioInt >> 8);
Cosi da poter trasmettere allo slave i due singoli byte contenuti in a1 e a2.
Lo slave una volta ricevuti ricomporrà i due byte e formerà l'intero così:
masterInt = ((f1 << 8) | f0); // si ricompone l'intero
In f0 ci srà il contenuto di a1, ed in f1 ci sarà il contenuto di a2.
------------------------------------------------------------
Per quanto riguarda il numero float ho utilizzato ( come indicato sul forum di Arduino),
Questa funzione:
union Scomp_float // si utilizza union x float
{
float temp;
char byte_s[4];
}S_float;
La union è una struttura del linguaggio "C" dove una particolare variabile può contenere oggetti di tipo e dimensioni differenti.
Questa funzione:
union Scomp_float // si utilizza union x float
{
float temp;
char byte_s[4];
}S_float;
La union è una struttura del linguaggio "C" dove una particolare variabile può contenere oggetti di tipo e dimensioni differenti.
Nel nostro caso la S_float contiene un float (float temp) e un (char byte).
Questa funzione deve essere in testa allo sketch.
Questa funzione va dichiarata nel master e nello slave ( identica ).
Successivamente il master prima scompone il numero che vogliamo trasmettere:
S_float.temp = mioFlo; // si scompone in 4 byte
f0 = S_float.byte_s[0];
f1 = S_float.byte_s[1];
f2 = S_float.byte_s[2];
f3 = S_float.byte_s[3];
Quindi come nel caso precedente esegue la trasmissione dei 4 byte allo slave.
Infine nello sketch dello slave una volta ricevuti i 4 byte si provvederà a ricomporli, eseguendo l'operazione inversa effettuata sul master.
S_float.byte_s[0] = f0; // si ricompone il float
S_float.byte_s[1] = f1;
S_float.byte_s[2] = f2;
S_float.byte_s[3] = f3;
masterFloat = S_float.temp;
Nei due sketch qui sotto troverete tutte le note per i passaggi effettuati.
Si trasmettono 3 numeri dal master allo slave un intero, un float, ed un int long, il master trasmette e lo slave li mostra sul monitor.
lo sketch non è ottimizzato ed è migliorabile ma credo che così si legga bene lo svolgersi del programma.
Questo programma è solo dimostrativo.
Si può vedere come si possano passare dati utilizzando I²C, magari la cosa potrà servire in altro lavoro.
continua ......
Questa funzione deve essere in testa allo sketch.
Questa funzione va dichiarata nel master e nello slave ( identica ).
Successivamente il master prima scompone il numero che vogliamo trasmettere:
S_float.temp = mioFlo; // si scompone in 4 byte
f0 = S_float.byte_s[0];
f1 = S_float.byte_s[1];
f2 = S_float.byte_s[2];
f3 = S_float.byte_s[3];
Quindi come nel caso precedente esegue la trasmissione dei 4 byte allo slave.
Infine nello sketch dello slave una volta ricevuti i 4 byte si provvederà a ricomporli, eseguendo l'operazione inversa effettuata sul master.
S_float.byte_s[0] = f0; // si ricompone il float
S_float.byte_s[1] = f1;
S_float.byte_s[2] = f2;
S_float.byte_s[3] = f3;
masterFloat = S_float.temp;
Nei due sketch qui sotto troverete tutte le note per i passaggi effettuati.
Si trasmettono 3 numeri dal master allo slave un intero, un float, ed un int long, il master trasmette e lo slave li mostra sul monitor.
lo sketch non è ottimizzato ed è migliorabile ma credo che così si legga bene lo svolgersi del programma.
Questo programma è solo dimostrativo.
Si può vedere come si possano passare dati utilizzando I²C, magari la cosa potrà servire in altro lavoro.
Sketch del master.
---
/* *************************************** ***** Sergio & Adriano Prenleloup ***** ***** ***** ***** I2C libreria Wire ***** ***** MASTER V.3.01 ***** *************************************** ***** 01/03/2014 ***** *************************************** Con questo sketch si prova il funzionamento della libreria Wire per gestire la comunicazione seriale I2C. Lo sketch si compone di due parti il MASTER ( questo) e lo SLAVE. Si sono collegati al bus I2C due Arduino UNO r3. La prova consiste nel trasmettere dal MASTER allo SLAVE dati composti da più byte. Il master trasmette interi, interi lunghi, e float. Lo slave li riceve e li mostra sul monitor. Modifiche effettuate sullo sketch di esempio nella libreria Ho lasciato uguali alcune righe. */ #include (Wire.h) // si include la libreria //--------------------------------------------------------- union Scomp_float // si utilizza union x float { float temp; char byte_s[4]; }S_float; //--------------------------------------------------------- union Scomp_long // si utilizza union x long { long int mioL; char byte_sL[4]; }S_long; //---------------------------------------------------------- //---------------------------------------------------------- // questi sono i dati che si vogliono trasmettere int mioInt = 32499; long int mioLong = 1234567801; float mioFlo = 123456.29; //---------------------------------------------------------- byte a1 = 0; // conterrà i primo byte dell'int byte a2 = 0; // conterrà il secondo byte dell'int byte f0 = 0; // contengono i byte del float e del long byte f1 = 0; byte f2 = 0; byte f3 = 0; void setup() { Wire.begin(); // join i2c bus (address optional for master) } void loop() { //----------------------------------------------------- // trasmissione di un intero ( 2 byte) //----------------------------------------------------- a1 = byte(mioInt); // si scompone l'intero in 2 byte a2 = byte( mioInt >> 8); Wire.beginTransmission(4); // inzia trasmissione allo slave Wire.write(a1); // invia un byte Wire.write(a2); // invia il secondo byte Wire.endTransmission(); // stop transmitting //------------------------------------------------------ delay (2000); //------------------------------------------------------ // trasmissione intero lungo 4 byte //------------------------------------------------------ S_long.mioL = mioLong; // si scompone in 4 byte f0 = S_long.byte_sL[0]; f1 = S_long.byte_sL[1]; f2 = S_long.byte_sL[2]; f3 = S_long.byte_sL[3]; a1 = 1; // si trasmette questo byte solo per segnalare allo slave // che stiamo trasmettendo un long // una volta scomposto si trasmettono i 4 byte Wire.beginTransmission(4); // trasmette allo slave Wire.write(f0); // invia un byte Wire.write(f1); // Wire.write(f2); // Wire.write(f3); // invia un byte Wire.write(a1); Wire.endTransmission(); // fine trasmissione //------------------------------------------------------- delay (2000); //------------------------------------------------------ // trasmissione di un float 4 byte //------------------------------------------------------ S_float.temp = mioFlo; // si scompone in 4 byte f0 = S_float.byte_s[0]; f1 = S_float.byte_s[1]; f2 = S_float.byte_s[2]; f3 = S_float.byte_s[3]; // una volta scomposto si trasmettono i 4 byte Wire.beginTransmission(4); // trasmette allo slave Wire.write(f0); // invia un byte Wire.write(f1); // Wire.write(f2); // Wire.write(f3); // invia un byte Wire.endTransmission(); // fine trasmissione //------------------------------------------------------- delay (3000); } //------ end master ----------------------------------
---
Sketch dello slave
----
/* *************************************** ***** Sergio & Adriano Prenleloup ***** ***** ***** ***** I2C libreria Wire ***** ***** SLAVE V.3.01 ***** *************************************** ***** 01/03/2014 ***** *************************************** Con questo sketch si prova il funzionamento della libreria Wire per gestire la comunicazione seriale I2C. Lo sketch si compone di due parti lo SLAVE (questo) ed il Maaster. Si sono collegati al bus I2C due Arduino UNO r3. La prova consiste nel trasmettere dal MASTER allo SLAVE dati composti da più byte. Il master trasmette interi, interi lunghi, e float. Lo slave li riceve e li mostra sul monitor. Modifiche effettuate sullo sketch di esempio nella libreria Ho lasciato uguali alcune righe. */ #include (Wire.h) // include la libreria //------------------------------------------------------------ // si ripete la union esattamente come nel master union Scomp_float // si utilizza union x float { float temp; char byte_s[4]; }S_float; //------------------------------------------------------------ // si ripete la union esattamente come nel master union Scomp_long // si utilizza union x long { long int mioL; char byte_sL[4]; }S_long; //------------------------------------------------------------ //------------- byte temporanei byte f0 = 0; // contengono i byte ricevuti byte f1 = 0; byte f2 = 0; byte f3 = 0; byte a1 = 0; //------------------------------------------------------------- // qui si introdurranno i dati ricomposti dopo la trasmissione long int masterLong = 0; float masterFloat = 0; int masterInt = 0; //-------------------------------------------------------------- void setup() { Wire.begin(4); // join i2c bus with address #4 Wire.onReceive(receiveEvent); // register event Serial.begin(9600); // start serial for output } void loop() { //------------------------------------------------------------ // si stampano i dati ricevuti e ricomposti //------------------------------------------------------------ Serial.println(masterInt); Serial.println(masterLong); Serial.println(masterFloat); delay (3000); } // function that executes whenever data is received from master // this function is registered as an event, see setup() void receiveEvent(int howMany) { if (howMany == 2) // se in arrivo due dati { f0 = Wire.read(); // si leggono i byte f1 = Wire.read(); masterInt = ((f1 << 8) | f0); // si ricompone l'intero } if (howMany == 4) // se in arrivo 4 dati è un float { f0 = Wire.read(); // si leggono i byte f1 = Wire.read(); f2 = Wire.read(); f3 = Wire.read(); S_float.byte_s[0] = f0; // si ricompone il float S_float.byte_s[1] = f1; S_float.byte_s[2] = f2; S_float.byte_s[3] = f3; masterFloat = S_float.temp; } if (howMany == 5) // se in arrivo 5 dati è un long { f0 = Wire.read(); // si leggono i byte f1 = Wire.read(); f2 = Wire.read(); f3 = Wire.read(); a1 = Wire.read(); S_long.byte_sL[0] = f0; // si ricompone il long S_long.byte_sL[1] = f1; S_long.byte_sL[2] = f2; S_long.byte_sL[3] = f3; masterLong = S_long.mioL; } }
Qui una schermata del monitor seriale inviata dallo slave.
cliccando sul'immagine si leggono chiaramente i numeri trasmessi dal master e mostrati dallo slave.
qui sotto una foto della prova.
Nel prossimo post sarà il master che mostrerà dati che gli invia lo slave.
continua ......
Sto cercando di scambiare stringhe via I2Cbus tra due Arduino piuttosto che un carattere alla volta. Il tuo esempio non centra prprio il mio problema ma può essere fonte di ispirazione. Grazie
RispondiEliminaOk! Grazie per il commento.
EliminaPer trasferire stringhe vedi il post precedente con il quale si comunica "Acceso" o "Spento", del resto la seriale passa un carattere per volta, ma ricostruisce la stringa.
Questo con lo standard della libreria. Fammi comunque sapere se trovi soluzione e se la vuoi condividere con la comunità.
Questo mio blog ha superato le 21000 visite e ho notato che molti ci tornano per rivedere i post.
Cordiali saluti
Sergio
Salve, complimenti per il post è proprio quello che andavo cercando! o in parte; ho letto a fine post che hai scritto: "Nel prossimo post sarà il master che mostrerà dati che gli invia lo slave. continua ......" ho provato a cercarlo ma non l'ho trovato, sai darmi qualche dritta per leggere diversi byte dallo SLAVE? ho fatto qualche prova ma dallo slave riesco a leggere solo l'ultimo byte.Grazie in anticipo
RispondiEliminaSi purtroppo non ho completato quanto previsto.
EliminaPer leggere più byte vedi anche il primo post su I2C , lo slave comunica al master Acceso o Spento ( stato del led).
Se vedi bene lo sketch vedrai che in ogni caso anche la read legge un byte per volta ed infatti nello sketch utilizzo delle variabili di appoggio, per l'intero 2, per il float 4, per il long 5 ( a1 serve solo per segnalare che si sta trasmettendo un long )
Non credo che in tempi brevi possa aggiungere la parte mancante ma sicuramente l'argomento è interessante e vale la pena di approfondire.
Cordiali saluti.
Sergio
mmm si ho visto anche quel post ma in quel caso si invia al master 6 byte come caratteri e con un solo wire.write. io invece vorrei inviare al master 6 valori e per farlo ho scritto un wire.write per ogni valore da inviare es.:
EliminaWire.write(a1);
Wire.write(a2);
Wire.write(a3);
Wire.write(a4);
Wire.write(a5);
Wire.write(a6);
però non funziona! magari c'è qualche altra funzione che non conosco...
Ok! Infatti in quel modo si inviano al master 6 byte come caratteri.
EliminaProva a copiare lo sketch nel commento e vedo se posso aiutarti, se è troppo lungo inserisci un indirizzo email nel commento ( io non pubblicherò la tua mail).
Non posso prometterti tempi veloci perché sono impegnato su altre attività.
Cordiali saluti
Sergio
Mi fa piacere sapere che hai risolto il problema!
EliminaSaluti
Sergio.
Complimenti per l'utilissimo articolo.
RispondiEliminaL'aver reso "accessibile" questa tematica, trattata troppo spesso nel forum di Arduino in maniera troppo ermetica, è realmente da apprezzare...solo così si aiuta la comunità a crescere!
Grazie!
Grazie per il commento.
EliminaCerco di pubblicare i lavori e le prove che faccio, anche io mi avvalgo di pubblicazioni sul web.
In particolare per questi post sulla I2C ho letto il tutorial :
http://www.logicaprogrammabile.it/ di Marco Lai
Saluti
Sergio
grazie.
RispondiEliminaHo trovato quello che cercavo. Spesso si trovano soluzioni parziali, questa tua soluzione è abbastanza completa.
Buon 2017!!
EliminaPrimo commento del nuovo anno!!
Grazie per il commento, e giro i ringraziamenti a Marco Lai.
Saluti ed Auguri a tutti i lettori del Blog.
Sergio
La tua soluzione mi ha permesso l'uso dei motori con encoder incrementale non era indispensabile trasmettere i dati da un arduino all'altro per leggere i dati numerici dell'encoder pero cosi ho molte possibilita applicative in piu ho usato il master come lettore dell'encoder e lo slave riceve la lettura e la visualizza su lcd ...
RispondiEliminaCommento di Valerio Todeschini
Grazie del commento ho ricevuto i tuoi dati.
EliminaSaluti
Sergio
Funziona anche per la seriale?
RispondiEliminaCiao! Grazie per il commento.
EliminaNo il protocollo I2C è un protocollo di tipo seriale in quanto i dati vengono inviati in sequenza.
Ma la seriale usa un protocollo completamente diverso.
Saluti
Sergio