mercoledì 5 marzo 2014

I²C - num. 2

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

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.
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.

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 ......


15 commenti:

  1. 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

    RispondiElimina
    Risposte
    1. Ok! Grazie per il commento.
      Per 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

      Elimina
  2. 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

    RispondiElimina
    Risposte
    1. Si purtroppo non ho completato quanto previsto.
      Per 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

      Elimina
    2. 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.:
      Wire.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...

      Elimina
    3. Ok! Infatti in quel modo si inviano al master 6 byte come caratteri.
      Prova 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

      Elimina
    4. Mi fa piacere sapere che hai risolto il problema!
      Saluti
      Sergio.

      Elimina
  3. Complimenti per l'utilissimo articolo.
    L'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!

    RispondiElimina
    Risposte
    1. Grazie per il commento.
      Cerco 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

      Elimina
  4. grazie.
    Ho trovato quello che cercavo. Spesso si trovano soluzioni parziali, questa tua soluzione è abbastanza completa.

    RispondiElimina
    Risposte
    1. Buon 2017!!
      Primo 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

      Elimina
  5. 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 ...

    Commento di Valerio Todeschini

    RispondiElimina
    Risposte
    1. Grazie del commento ho ricevuto i tuoi dati.
      Saluti
      Sergio

      Elimina
  6. Risposte
    1. Ciao! Grazie per il commento.

      No 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

      Elimina

Vi ringrazio per la lettura e vi invito al prossimo post.
Se il post vi è stato utile, vi è piaciuto oppure no, scrivete un commento.

Un saluto a tutti.
Sergio

Copyright - Condizioni d’uso - Disclaimer
http://avventurarduino.blogspot.it/2012/10/inizia-lavventura-arduino-12-settembre.html