Vai al contenuto

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

Stai visualizzando 9 post - dal 1 a 9 (di 9 totali)
  • Autore
    Post
  • #57875
    Carmine Cavaliere
    Partecipante

    Devo 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?

    #57878
    Sergio Bertana
    Amministratore del forum

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

    #57939
    Carmine Cavaliere
    Partecipante

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

    #57945
    Sergio Bertana
    Amministratore del forum

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

    #62115
    Rubox
    Partecipante

    Mi 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?

    #62122
    Sergio Bertana
    Amministratore del forum

    E’ 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]));
    #62123
    Rubox
    Partecipante

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

    #62362
    Rubox
    Partecipante

    Non 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?

    #62367
    Sergio Bertana
    Amministratore del forum

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

Stai visualizzando 9 post - dal 1 a 9 (di 9 totali)
  • Devi essere connesso per rispondere a questo topic.