Protocollo Modbus e problemi conversione valori

Forse questo non è il posto giusto ma ci provo lo stesso:

dovrei salvare in una variabile il valore ricavato da un analizzatore di rete elettrica che comunica in protocollo RS 485 Modbus RTU.

Questo protocollo consiste in richieste al dispositivo tramite frame e risposte dallo stesso con altro frame dove si possono trovare i valori richiesti.
Questo è il punto:
i dati utilizzati come risposta sono in formato floating point 32bit IEEE
Per capire un po' questo formato ho trovato un software che crea le stringhe e le invia registrandone le risposte dallo slave.

Allego le schermate dell'applicazione per comprendere:


Facendo un'interrogazione dei registri interessati (2, sempre adiacenti) la stringa di risposta è quella evidenziata in nero nella prossima schermata


I valori utili per il dato da estrapolare sono questi [43] [61] [B3] [33]


Il formato selezionato nella immagine mi restituisce il valore corretto della lettura (in questo caso in volt)

Alla fine di questa pappardella vi chiedo: esiste qualche modo/metodo/libreria che mi converta questi 4 numeri esadecimali in un valore rispondente al valore da ottenere?

Mi scuso per l'esposizione forse non estremamente tecnica ma l'argomento è parecchio complicato...
Grazie

Dai un occhio a questo:

Si, già ampiamente letto ma non appreso ... speravo in qualcuno che avesse già affrontato sul campo il problema

Forse in C/Arduino puoi usare la union:

union mix_t {
  float f;
  struct 
  { byte b1;
    byte b2;
    byte b3;
    byte b4;
  } s;
} mix;

void setup()
{ Serial.begin(9600);
  mix.s.b4=0x43;
  mix.s.b3=0x61;
  mix.s.b2=0xB3;
  mix.s.b1=0x33;
  Serial.println(mix.f);
  mix.f=225.70;
  Serial.println(mix.s.b1,HEX);
  Serial.println(mix.s.b2,HEX);
  Serial.println(mix.s.b3,HEX);
  Serial.println(mix.s.b4,HEX);
}
void loop()
{}

Mi stampa 225,70

Arabo.... scusa ma non ho capito nulla. Qualche indizio? :slight_smile:

La variabile mix occupa 4 byte, ma a questi 4 byte puoi accedere come un unico valore float oppure 4 byte nominati b1->b4

Scrivendo i 4 byte è come se scrivessi i 4 byte che compongono il float. Ma è tutto da provare.

Questi [43] [61] [B3] [33] a quale valore floating corrispondono ?

225 virgola....

Allora è corretto, con Arduino Uno e

  mix.s.b4=0x43;
  mix.s.b3=0x61;
  mix.s.b2=0xB3;
  mix.s.b1=0x33;
  Serial.println(mix.f);

Ottengo 225.70
Occhio che il 0x43 va in b4

FANTASTICO.... però però ora devi spiegarmi passo passo (abbi pazienza ma fare le cose a copiaincolla senza capire non mi piace) le varie righe di codice... sono poche

Grazie ancora

mix_t è il nuovo tipo di dato, una union (invece di una struct)
mix è la variabile di tipo mix_t
Puoi anche dare nomi tuoi e spezzare la cosa:

union MB_float {
  float f;
  struct 
  { byte b1;
    byte b2;
    byte b3;
    byte b4;
  } s;
};

MB_float num1,num2;

Una union è come una struct, una struttura che contiene altre "parti" o variabili.
Nel nostro caso dentro la MB_float ci sono 5 parti, f e poi s.b1, s.b2, s.b3, s.b4
Essendo una union f e le quattro parti di s (ovvero b1-b4) si "sovrappongono".
Scrivendo nell'ordine giusto le 4 parti (byte) che compongono il float, leggendo la parte f hai il numero con virgole.

Qui io ho scritto i valori (come esadecimali) che tu hai letto con il programma:

  mix.s.b4=0x43;  // ovvero 67 decimale
  mix.s.b3=0x61;
  mix.s.b2=0xB3;
  mix.s.b1=0x33;
  Serial.println(mix.f);

E poi stampo la parte f della variabile per avere il numero con virgole.
Logicamente tu dovrai leggere i 4 byte dal Bus e poi scriverli dentro a mix.s.b1 fino a mix.s.b4 e NELL'ORDINE giusto.

Partendo da questo codice che avevi postato e che funziona, avrei alcune domande :

union mix_t {
  float f;
  struct 
  { byte b1;
    byte b2;
    byte b3;
    byte b4;
  } s;
} mix;

void setup()
{ Serial.begin(9600);
  mix.s.b4=0x43;
  mix.s.b3=0x61;
  mix.s.b2=0xB3;
  mix.s.b1=0x33;
  Serial.println(mix.f);
  mix.f=225.70;
  Serial.println(mix.s.b1,HEX);
  Serial.println(mix.s.b2,HEX);
  Serial.println(mix.s.b3,HEX);
  Serial.println(mix.s.b4,HEX);
}

Nella union mix_t non capisco il concetto di "unire" la variabile float f con struct (che mi pare di aver capito essere un raggruppamento di dati che possono essere anche di diverso tipo)
Ho letto inoltre che volendo su può omettere nella struct l'identificatore s

Questa parte di codice

mix.f=225.70;
  Serial.println(mix.s.b1,HEX);
  Serial.println(mix.s.b2,HEX);
  Serial.println(mix.s.b3,HEX);
  Serial.println(mix.s.b4,HEX);

L' hai aggiunta tu ma non serve vero, per il calcolo?

Ho provato ad invertire in Serial.println(mix.f) mix con f per curiosità ma mi viene reso un errore in fase di compilazione: la sequenza corretta fa parte del costrutto di Serial.print() o cosa?

è la stessa cosa che fare

float f = b4 | ( b3 << 8) | (b2 << 16) | (b1 << 24);

bisognerebbe vedere tutto il protocollo e come comunichi.

Senza offera @franchelli, ma una struct o union è spiegata bene in un manuale di C.
Ti ho postato un link ad un sito che da una spiegazione di struct e union, con esempi.
In un forum mi viene difficile darti tutte le spiegazioni della struct, cerca su quel link o su internet in generale.

Come detto da @vbextreme, quella union facilita quello che puoi fare con il calcolo da lui indicato.
La seconda parte del codice da me postato non serve, è solo la riprova che un float=225,70 spezzato in 4 byte da i valori che avevi postato

Il nome "s" della struct lo puoi cambiare ma non evitare. Le parti della union che coincidono in memoria sono f ed s ovvero 4 byte in memoria.

f | .  .  .  .|    4 byte
s |b1|b2|b3|b4|    4 byte che sono le 4 parti del float

In una struct o union alle varie parti (campi) si accede con variabile.campo nel nostro caso mix.f oppure mix.s.b3
Non puoi invertire quell'ordine.

nid69ita:
Senza offera @franchelli, ma una struct o union è spiegata bene in un manuale di C.
Ti ho postato un link ad un sito che da una spiegazione di struct e union, con esempi.
In un forum mi viene difficile darti tutte le spiegazioni della struct, cerca su quel link o su internet in generale.
CUT

Hai assolutamente ragione e sei stato fin troppo disponibile... Il sito indicato ed anche qualche altro, li ho letti e riletti ma i concetti alle volte sono non proprio elementari.
Mi hai comunque chiarito molti aspetti oscuri, grazie.