Conversione da DWORD a REAL con lo standard IEEE-754
Home › Forum › Informazioni ambiente di sviluppo LogicLab › Conversione da DWORD a REAL con lo standard IEEE-754
Taggato: Convertitore da DWORD a REAL
- Questo topic ha 8 risposte, 3 partecipanti ed è stato aggiornato l'ultima volta 3 anni, 4 mesi fa da
Sergio Bertana.
-
AutorePost
-
Ottobre 9, 2020 alle 2:29 pm #57875
Carmine Cavaliere
PartecipanteDevo convertire una DWORD in REAL . Utilizzando la funzione TO_REAL viene fuori un numero che non è quello giusto. Il valore corretto lo ottengo invece con il convertitore trovato al seguente link https://www.h-schmidt.net/FloatConverter/IEEE754.html.
Come posso risolvere il problema?
Esiste un blocco funzione che fa lo stesso tipo di conversione del convertitore sopra citato?Ottobre 9, 2020 alle 2:30 pm #57878Sergio Bertana
Amministratore del forumLa dichiarazione TO_REAL è corretta, probabilmente stai prendendo un abbaglio in quello che vedi, eccco nello screenshot un esempio di conversione.
Come vedi ho caricato il valore 12345678 nella DWORD e lo stesso valore l’ho definito nel campo You entered della utility web. Come risultato della conversione avrò che la variabile REAL RVar ha valore 12345678.0 ma se utilizzando un puntatore di tipo DWORD ne visualizzo il valore esadecimale ottengo 16#4B3C614E che è lo stesso valore visualizzato nel campo Hexadecimal Representation.
Ho utilizzato il puntatore solo per poter vedere contemporaneamente sia il valore REAL che il suo valore esadecimale, ma tu puoi anche andare nella finestra watch e selezionare la variabile e con il tasto destro del mouse scegliere Format e formato Hexadecimal per vedere la stessa cosa.
Aggiungo che se ti serve maggior risoluzione dalla versione XUnified dei sistemi abbiamo introdotto i numeri a 64 bits sia interi che floating.
Ottobre 16, 2020 alle 8:07 am #57939Carmine Cavaliere
PartecipanteEsplicito meglio il problema: ho un trasmettitore di portata Hart che trasferisce il valore del totalizzatore a un convertitore Hart master – Modbus slave il quale, a sua volta, via RS485 trasferisce il dato al PLC Elsist. Come si vede dall’immagine la “variabile_1”, di tipo DWORD, mi viene passata da un convertitore Hart master-Modbus slave ed è originata da un misuratore di portata.
Il valore letto sul display del misuratore è 121240.5546, corrispondente al valore esadecimale 16#47ECCC47 ottenuto usando il convertitore che ti ho citato, come faccio a tirare fuori il valore REAL sul PLC?
Se uso la function Block TO_REAL per convertire la DW mi esce fuori un numero REAL che non è quello giusto.
Ottobre 16, 2020 alle 8:14 am #57945Sergio Bertana
Amministratore del forumIl valore letto dal FB ModbusMaster è già un valore REAL quindi non devi effettuare casting con l’operatore TO_REAL ma basta semplicemente che tu definisca la variabile variabile_1 di tipo REAL.
Siccome Modbus non specifica l’endiannes dei dati ritornati su più word, potrebbe essere che acquisendo variabili espresse su 2 word (UDINT, DWORD, REAL) ci si ritrovi con MSW e LSW invertiti (Ma non mi sembra questo il tuo caso). Nel caso fossero invertiti puoi usare la funzione VarSwap per sistemarli.
Gli operatori di casting TO_REAL, TO_INT, ecc non eseguono operazioni servono solamente per informare il compilatore che nel programma si stà facendo un trasferimento di un valore da una variabile di un tipo in una variabile di un’altro tipo.
Novembre 15, 2021 alle 4:25 pm #62115Rubox
PartecipanteMi sto scontrando con la mia ignoranza in materia di Modbus. Devo leggere da CPU dei valori in Modbus: un valore al numero di registro 6, lunghezza di 2 word, intero a 32 bit (è una temperatura, quindi intero 32 bit con segno).
Imposto l’Address del ModbusMaster a 6, Points a 2. Supponiamo che venga letto il valore di 380. Se come Buffer passo un array di Word, mi ritrovo buffer[0]=0000 e buffer[1]=017C.
Se come Buffer passo una DWORD mi trovo buffer=017C0000, ossia le due WORD scambiate. E’ corretto?
Per passare dalle due WORD dell’array del primo caso al valore intero è giusto moltiplicare buffer[0] per 16#FFFF e sommare buffer[1]? C’è un modo più veloce, qualche funzione che lo faccia in automatico?
Novembre 15, 2021 alle 4:43 pm #62122Sergio Bertana
Amministratore del forumE’ il problema dell’endianness cui facevo riferimento prima, nel Modbus non è indicato come gestire il passaggio di variabili più lunghe di 16 bits, quindi di solito dipende dall’endiannes del dispositivo.
Nel tuo caso il dispositivo da cui leggi ha un endiannes diverso dallo SlimLine.
Per il calcolo del valore corretto espresso su variabile DINT puoi fare come hai fatto tu, ma ti consiglio di utilizzare la funzione VarSwap, passando come sorgente l’indirizzo del buffer Modbus e destinazione l’indirizzo della variabile DINT. In questo modo è garantita anche la gestione dei valori negativi.
i:=VarSwap(DINT_TYPE, ADR(Temperature), ADR(buffer[0]));
Novembre 17, 2021 alle 12:03 pm #62123Rubox
PartecipanteGrazie per la risposta. Nel frattempo ho sperimentato un pò per le stringhe, i valori REAL e via dicendo.
Il costruttore del dispositivo ha scritto di tutto nel manuale, tranne l’endiannes: ho scritto al supporto sperando rispondano.Novembre 26, 2021 alle 4:42 pm #62362Rubox
PartecipanteNon riesco a capire una cosa banale: ho due array di WORD, rappresentazione di valori REAL a 32 bit, floating point.
Array1[0]:=51EB, Array1[1]:=417C
Quindi se acquisisco via Modbus da un sistema che utilizza il little endian (Come lo SlimLine) fornendo come buffer l’indirizzo di una variabile REAL ottengo il valore corretto.
Se invece acquisisco via Modbus da un sistema che utilizza il big endian devo utilizzare la funzione VarSwap, è corretto?
Novembre 26, 2021 alle 4:43 pm #62367Sergio Bertana
Amministratore del forumSi è corretto ecco un semplice esempio in LogicLab che ti illustra il problema.
VAR i : UDINT; (* Auxiliary variable *) DArray : ARRAY[0..1] OF WORD; RVar : REAL; (* REAL variable *) END_VAR // Esempio in little endian. DArray[0]:=16#51EB; DArray[1]:=16#417C; i:=Sysmemmove(ADR(RVar), ADR(DArray[0]), 4); // Esempio in big endian. DArray[0]:=16#417C; DArray[1]:=16#51EB; i:=VarSwap(WORD_TYPE, ADR(DArray[0]), ADR(RVar));
Come vedi nel caso di little endian ho solo copiato il valore ma potevo anche farlo scrivere direttemente da Modbus nella variabili RVar. Mentre nel caso del big endian ho dovuto utilizzare la funzione VarSwap.
-
AutorePost
- Devi essere connesso per rispondere a questo topic.