come convertire float in array (latitudine longitudine)

ragazzi potreste aiutarmi a risolvere questo dilemma dal momento che non mastico molto il linguaggio di programmazione

in pratica ho messo in comunicazione 2 arduino tramite libreria Wire.h ed invio byte di array da uno ad un altro in questo modo

ho il valore di latitudine e longitudine in formato decimale e vorrei inviarli con un array tipo

byte slave[2];
slave[0] = Lat;
slave[1] = Long;
Wire.write(slave,2);

ed inviarli al master che li riceve

while (Wire.available())
{
a = Wire.read();
b = Wire.read();
Lat = a;
Long = b;
delay(1);
}

ma è evidente che i valori che ricevo sono solo i numeri interi prima della virgola e non i decimali

come posso fare per inviare tutto il numero compreso i decimali?

grazie

E fare

Wire.write (&Lat, sizeof (Lat));

? In realtà non conosco la libreria, ma sono fiducioso che funzioni :).

Sempre il solito discorso trattato decine e decine di volte :stuck_out_tongue: la union è una soluzione molto comoda per queste operazioni

union {
  struct {
    float lat;
    float long;
  } str;
  byte arr[sizeof(float)*2];
} frame;

La union impone a tutti i suoi membri di condividere la stessa area di memoria, in questo modo la struct str occuperà gli stessi byte di memoria dell'array arr, se modifichi un valore nella struct anche nell'array questo cambierà, cosi facendo nella struct ti ritroverai i valori belli ordinati e formattati e nell'array i singoli byte che le compongono. Ti basterà implementare la struttura su entrambi i device, usando la str per operare sui dati e inviando tra di loro i byte contenuti in arr.

Grazie roberto,

scusami ma sono un po ignorante in questo campo e non vorrei fare tentativi a vuoto

ma se ho

Float Lat = 40.2211;
Float Long = 15.3321;

come se ho questo codice da lato slave

Float Lat = 40.2211;
Float Long = 15.3321;

void RequestEvent()
{
  byte slave[5];
  slave[0] = Th;
  slave[1] = RPM;
  slave[2] = Lat;
  slave[3] = Long;
  slave[4] = Speed;
  Wire.write(slave,5);
  
}

e questo codice da lato master

int Th;
int RPM;
float Lat;
float Long;
float Speed;
byte a, b, c, d, e;

void Request()
{
  Wire.requestFrom(6,5);
  while (Wire.available())
  {
   a = Wire.read();
   b = Wire.read();
   c = Wire.read();
   d = Wire.read();
   e = Wire.read();

   Th = a;
   RPM = b;
   Lat = c;
   Long = d;
   Speed =e;
   delay(1);
  }

come inserisco il codice che mi hai descritto nel mio sketch

grazie mille

Ad una union si accede esattamente come una struct, da entrambi le parti avrai la stessa union

union {
  struct {
    float lat;
    float long;
  } str;
  byte arr[sizeof(float)*2];
} frame;

I valori lat e long li leggerò e scriverò con frame.str.lat e frame.str.long, stesso discorso per l'array di byte frame.arr
Adesso lo slave legge i valori di longitudine e latitudine da un gps, li mette dentro la struttura frame.str e invia al master l'array di byte frame.arr, il master riceverà l'array di byte e lo posizionerà nel suo array frame.arr e leggera i valori formattati dalla struttura frame.str.
Ora è più chiaro?

quindi posso inserire nella union anche tutte le altre variabili teoricamente?

ed inviare al master solo la union e non

byte slave[5];
slave[0] = Th;
slave[1] = RPM;
slave[2] = Lat;
slave[3] = Long;
slave[4] = Speed;
Wire.write(slave,5);

Vedo che hai capito il concetto.

io non credo tanto

void RequestEvent()
{

  union {
  struct {
    
float Lat;
float Long;
float Speed;
float Alt;
float Amp;
float Volt;
float Watt;
float HR;
  } str;
  byte arr[sizeof(float)*8];
} frame;
Wire.write(frame,8);
}

alla fine ho scritto cosi ma ero sicuro che mi dava errore nell invio del frame
dove ho sbagliato?

Se ti viene più comodo puoi usare questa libreria. --> GitHub - madsci1016/Arduino-EasyTransfer: An Easy way to Transfer data between Arduinos
--> EasyTransfer Arduino Library « The Mind of Bill Porter

Perché hai detto alla funzione write di inviare una union, cosa che non è in grado di fare, devi passargli l'array della union

void RequestEvent()
{

  union {
    struct {
   
float Lat;
float Long;
float Speed;
float Alt;
float Amp;
float Volt;
float Watt;
float HR;
    } str;
    byte arr[sizeof(frame.str)];
  } frame;
  Wire.write(frame.arr, sizeof(frame.str));
}

Prestiamo attenzione alla dimensione dell'array, hai una struct che occupa tanti byte quanti quelli occupati dagli elementi che contiene, su Arduino i float sono da 2 byte, per sicurezza usiamo scrivere sizeof(float) questo permette la piena portabilità del codice su piattaforme diverse, in questo caso arr lo facciamo grande quanto str, quindi sizeof(frame.str) (in realtà potevamo anche farlo da un singolo elemento, a noi quello che interessa è il puntatore in se alla struct). Facciamo un piccolo calcolo per l'invio di byte, abbiamo sizeof(float per 8 elementi, abbiamo detto che sizeof(float) = 2 quindi inviamo frame di 16 byte alla volta, quindi scriveremo Wire.write(frame.arr, 16) o piu semplicemente sizeof(frame.str) la dimensione della struct.
Dall'altra parte attenderemo quindi 16byte, ci mettiamo in ascolto e all'arrivo del sedicesimo byte copiamo il tutto nel frame.arr.

certo che complicarsi la vita per niente....
perché usi un vettore di byte per inviare i dati e non invii direttamente i dati?

float long = leggi_satellite ();
wire.write(&long, sizeof long);

e per riceverlo

float long=0;
wire.readByte(&long, sizeof long);

Perché è il metodo piu inefficiente che esista, risposta breve. Cosi facendo per ogni variabile rinizi da capo la connessione. L'array di byte mediante union è forse il metodo piu usato in C per la serializzazione dei dati. La serializzazione dei dati e la de serializzazione è completamente affidata al compilatore che la esegue senza invocare mezza call.

Mi sfugge la differenza a livello di trasmissione tra la spedizione della versione byte o di quella struttura, mi sembra sia solo più semplice da capire per chi non ha dimestichezza con i puntatori.

PS: dubito che si possa chiamare una variabile long :slight_smile:

è semplice formalità, non sarebbe nemmeno errato usare come puntatore &Lat e come numero di byte 16. Con l'array eviti semplicemente il cast, ma come dici te è corretto ed equivalente.

RobertoBochet:
Perché hai detto alla funzione write di inviare una union, cosa che non è in grado di fare, devi passargli l'array della union

void RequestEvent()

{

union {
    struct {
 
float Lat;
float Long;
float Speed;
float Alt;
float Amp;
float Volt;
float Watt;
float HR;
    } str;
    byte arr[sizeof(frame.str)];
  } frame;
  Wire.write(frame.arr, sizeof(frame.str));
}



Prestiamo attenzione alla dimensione dell'array, hai una struct che occupa tanti byte quanti quelli occupati dagli elementi che contiene, su Arduino i float sono da 2 byte, per sicurezza usiamo scrivere sizeof(float) questo permette la piena portabilità del codice su piattaforme diverse, in questo caso arr lo facciamo grande quanto str, quindi sizeof(frame.str) (in realtà potevamo anche farlo da un singolo elemento, a noi quello che interessa è il puntatore in se alla struct). Facciamo un piccolo calcolo per l'invio di byte, abbiamo sizeof(float per 8 elementi, abbiamo detto che sizeof(float) = 2 quindi inviamo frame di 16 byte alla volta, quindi scriveremo Wire.write(frame.arr, 16) o piu semplicemente sizeof(frame.str) la dimensione della struct.
Dall'altra parte attenderemo quindi 16byte, ci mettiamo in ascolto e all'arrivo del sedicesimo byte copiamo il tutto nel frame.arr.

ricevo l errore

frame was not declared in the scope

come lo dichiaro?

Il problema è che la dichiarazione di frame non è completa al suo interno, per cui fai come detto prima, sostituendo la dichiarazione di arr con:

byte arr[sizeof(float)*8];

grazie succo

e dal lato master come proseguo questo?

  Wire.requestFrom(address,11);
  while (Wire.available())
  {

Premesso che ho sonno, devi essenzialmente richiedere tot byte, aspettare che arrivino ed accodarli in arr, alla fine potrai usare str per recuperare quel che hai trasmesso. Qualcosa del genere potrebbe funzionare:

#define ADDRESS 0x27  // Inventato a caso

void boh() {
  union {
    struct {

      float Lat;
      float Long;
      float Speed;
      float Alt;
      float Amp;
      float Volt;
      float Watt;
      float HR;
    } str;
    byte arr[sizeof(float) * 8];
  } frame;

  Wire.requestFrom(ADDRESS, sizeof (frame));
  for (byte b = 0; b < sizeof (frame); b++) {
    // Attende il prossimo byte
    while (!Wire.available())
      ;

    // Accoda in arr
    frame.arr[b] = Wire.read ();
  }

  // A questo punto la struttura è completa ed utilizzabile con frame.str
}

Immagino ci siano modi migliori di farlo, ma questo dovrebbe essere il più semplice da capire.

grazie mille, ci provo!!!

@RobertoBochet, parlare di efficienza su Arduino fa scappare dal ridere.
La union rimane una sciocchezza in codesto contesto, un'inutile ridondanza.
Se hai una struttura che contiene i tuoi dati la puoi tranquillamente inviare e ricevere senza impazzire con cose inutili:
Master:

struct ciao
{
      float Lat;
      float Long;
      float Speed;
      float Alt;
      float Amp;
      float Volt;
      float Watt;
      float HR;
};

struct ciao mondo;

void loop()
{
    mondo.Long = satellite();
    mondo.Watt = leggiWatt();
    //etc etc etc
    Wire.write(&mondo, sizeof mondo);
}

slave:

struct ciao
{
      float Lat;
      float Long;
      float Speed;
      float Alt;
      float Amp;
      float Volt;
      float Watt;
      float HR;
};

struct ciao mondo;

void loop()
{
    if ( Wire.available() >= sizeof mondo)
    {
        Wire.readByte(&mondo, sizeof mondo);
    }
}

Semplice, pulito, elegante.