Vai al contenuto
PLC Forum


Acquisizione dati in Modbus tipo Float con bit invertiti


Messaggi consigliati

Buongiorno,

ho inserito in quadro elettrico un misuratore di energia interfacciabile via Modbus RTU,

le variabili restituite sono tante ma a me ne servono solo tre o quattro,

 

il dispositivo funziona e da display i valori sono corretti ma via Modbus diventano per me incomprensibili,

ho scoperto che i dati restituiti si appoggiano su due word ma è in formato Real (Float) e con i bit invertiti (endianness),

non mi sono mai trovato in questa situazione ma che probabilmente è uno standard per questi dispositi,

grazie a chiunque mi dia qualche idea

Link al commento
Condividi su altri siti


Anche io ho avuto la stessa situazione e weintek ha la possibilità di convertire il dato in floating point girando byte o word....Penso che anche shneider non abbia problemi a farlo..

Link al commento
Condividi su altri siti

sicuramente c'è qualcosa di semplce che mi sfugge .. come al solito!

attualmente ho provato cosi:

- prendo i due registri Modbus in arrivo e li assemblo tramite il blocco WORD_AS_DWORD (Toolkit)

- inverto i bit tramite il blocco ROL (n=31)

- trasformo il dato in REAL

 

ma anche invertentendo gli ingressi del blocco WORD_AS_DWORD il risultato non è corretto,

sto provando a leggere semplicemente la tensione che è un dato certo: 230 o 400V

Link al commento
Condividi su altri siti

secondo me non devi invertire i bit, ma devi scambiare i byte a due a due e se necessario alla fine scambi anche le word ottenute

Link al commento
Condividi su altri siti

14 minuti fa, Water ha scritto:

- prendo i due registri Modbus in arrivo e li assemblo tramite il blocco WORD_AS_DWORD (Toolkit)

- inverto i bit tramite il blocco ROL (n=31)

- trasformo il dato in REAL

 

ma anche invertentendo gli ingressi del blocco WORD_AS_DWORD il risultato non è corretto,

Il tuo problema è probabilmente legato al fatto che hai da 'girare' anche l'ordine dei byte ...

Il modbus ragiona in registri a 16 bits (WORD) quindi a seconda del endianness puoi ricevere byte alto/byte basso oppure il contrario. Quando hai a che fare con variabili che sono composte da registri doppi (caso tipo il DINT oppure il REAL) puoi avere anche in questo caso l'inversione del registro altro con quello basso (oltre ovviamente all'inversione del byte alto con quello basso).

 

Link al commento
Condividi su altri siti

Può anche essere, come dice max, che non vadano invertiti i byte (se normalmente i registri a 16 bit li decodifichi correttamente), ma le word. Dunque i byte 1234 vanno interpretati 3412

Link al commento
Condividi su altri siti

grazie degli input!

come detto avevo già provato ad invertire le word e poi i bit della dword generata ma niente,

non ho provato però ad invertire prima i bit delle word per poi assemblarle in una dword "invertita",

mah .. proverò anche questa, se trovo la sopluzione la posto!

grazie

Link al commento
Condividi su altri siti

1 ora fa, Water ha scritto:

non ho provato però ad invertire prima i bit delle word ...

Non i bit (anche se tecnicamente lo sono) ma i bytes (quello basso con quello alto).

P.S. Ogni manuale che sia decentemente scritto oltre ad indicare il significato dei registri indica anche come questi vengono trasmessi (al peggio indicano se si tratta di CPU Motorola o Intel).

In generale, posto che i bytes di 2 registri (WORD) consecutivi che debbano essere interpretati come DINT o come REAL siano indicati come A,B,C,D puoi avere le seguenti combinazioni :

- A,B,C,D

- B,A,D,C

- C,D,A,B

- D,C,B,A

Esempio di Word (composta da A - Byte meno significativo, B - Byte più significativo, ricevuti come B,A) to Byte :

ByteH= Word AND 16#FF00  #Mascheratura del byte meno significativo

ByteH=RSH(ByteL,8)   #Shift di 8 bit a destra

ByteL = Word AND 16#00FF  #Mascheratura del byte più significato

Swap della Word :

NewWord = LSH(ByteL) OR ByteH  # Potrebbe/Dovrebbe essere necessario trasformare i Byte in WORD prima di ricostruire la Word

Forse esiste già una funzione che fa il mestiere di inversione dei bytes all'interno di una word (e se esistesse potrebbe chiamarsi SWAP_qualcosa) : verifica nell'. del PLC che stai usando ....

Link al commento
Condividi su altri siti

grazie Max della esauriente risposta!

hai ragiorne e lo avevi detto anche nel precedente post ma chissà perchè mi sono interstardito con i bit 😬

so di certo che il dato è in formato REAL usando due registri con endness invertito,

il manuale non lo dice o comunque non ne ho trovato traccia (Eastron SDM630MCT) ,

 

in Codesys non c'è il blocco SWAP  e puoi girare solo i bit con il blocco ROL, ma so che c'è qualcosa nelle librerie di OSCAT,

in ogni caso ti ringrazio e ci provo!

Link al commento
Condividi su altri siti

1 ora fa, Water ha scritto:

in Codesys non c'è il blocco SWAP  e puoi girare solo i bit con il blocco ROL, ma so che c'è qualcosa nelle librerie di OSCAT,

Scusa la 'tignoseria' ma continui ad insistere che devi girare i bit (e il pensare di utilizzare la funzione ROL lo dimostra) : tu devi girare i bytes (prendi spunto dallo 'pseudo codice' che ti ho scritto, che salvo errori di sintassi è quello che utilizzo su M340).

Link al commento
Condividi su altri siti

1 ora fa, Water ha scritto:

in Codesys non c'è il blocco SWAP  ...

Non uso codesys, qundi non posso confermare la validità del risultato, 

ma cercando 'codesys swap word' ottengo :

VAR
Test1:WORD;
Test2:Word;
END_VAR

Test2:=MEM.ReverseBYTEsInWORD(Test1);
Altra soluzione (credo utilizzando oscat) in questo caso per fare lo swap di 2 word all'interno di una dword :
FUNCTION SWAP_WORD : DWORD
VAR_INPUT
    IN : DWORD;
END_VAR

SWAP_WORD := ROL(IN, 16);

Probabilmente, in codesys (forse tramite oscat), lo swap dei bytes all'interno di una word si ottiene semplicemente con ROL(IN,8) ...

 

Ciao

Link al commento
Condividi su altri siti

4 ore fa, Water ha scritto:

(Eastron SDM630MCT

 

Proprio quel contatore. Devi convertire, come ha giustamente detto max.riservo, ABCD con CDAB. Se il tuo pannello non lo fa in automatico come lo fa Weintek, devi farti uno script per farglielo fare.

Link al commento
Condividi su altri siti

5 ore fa, max.riservo ha scritto:

... tu devi girare i bytes (prendi spunto dallo 'pseudo codice' che ti ho scritto, che salvo errori di sintassi è quello che utilizzo su M340).

Alla fine direi che posso evolvere anche io evitando quello che faccio da 35 anni ...

Per fare lo swap dei bytes di una word basta semplicemente un ROL(word,8) oppure un ROR(word,8).

Link al commento
Condividi su altri siti

6 ore fa, max.riservo ha scritto:

Scusa la 'tignoseria' ma continui ad insistere che devi girare i bit (e il pensare di utilizzare la funzione ROL lo dimostra) : tu devi girare i bytes (prendi spunto dallo 'pseudo codice' che ti ho scritto, che salvo errori di sintassi è quello che utilizzo su M340).

hai ragione ma mi ero espresso male .. perchè intendevo mi ero erroneamente interstardito con i bit! 😀

ma soprattutto grazie anche a quello che hai postato successivamente 👍👍👍

2 ore fa, Lucky67 ha scritto:

 

Proprio quel contatore. Devi convertire, come ha giustamente detto max.riservo, ABCD con CDAB. Se il tuo pannello non lo fa in automatico come lo fa Weintek, devi farti uno script per farglielo fare.

vedo che lo conosci .. grazie della conferma Lucky!!

Link al commento
Condividi su altri siti

2 minuti fa, Water ha scritto:

ma soprattutto grazie anche a quello che hai postato successivamente 👍👍👍

Di nulla.

Quindi hai risolto con un semplice ROL(word,8) ?

Link al commento
Condividi su altri siti

13 ore fa, max.riservo ha scritto:

Di nulla.

Quindi hai risolto con un semplice ROL(word,8) ?

no Max non ancora perchè devo testarla sul campo con i valori che vengono dal misuratore,

ma sicuramente ora ho la chiave per farlo e appena riesco posterò la soluzione,

interessante la tua semplificazione tramite ROL di traslare solo 8 bit della word, 👍

Link al commento
Condividi su altri siti

Il 24/2/2024 alle 17:23 , max.riservo ha scritto:

Alla fine direi che posso evolvere anche io evitando quello che faccio da 35 anni ...

Per fare lo swap dei bytes di una word basta semplicemente un ROL(word,8) oppure un ROR(word,8).

Essendo un numero in virgola mobile non sono così sicuro che shiftando i bit si abbia un dato congruo....così a naso è...

Link al commento
Condividi su altri siti

11 ore fa, Lucky67 ha scritto:

Essendo un numero in virgola mobile non sono così sicuro che shiftando i bit si abbia un dato congruo....così a naso è...

L'interpretazione dei 2 registri modbus come numero REAL è subordinata al corretto ordinamento dei byte che compongono i registri stessi ...

e in questo caso stiamo invertendo byte alto con byte basso (e magari anche word alta con word bassa) per ricostruire in arrivo lo stesso dato che c'è in partenza.

Link al commento
Condividi su altri siti

.. ho testato velocemente con più opzioni ma senza nessun risultato,

per il momento devo abbandonare la cosa x mancanza di tempo,

però la cosa mi innervosisce molto e sicuramente appena possibile ci riprovo, 🥵

grazie comunque a tutti per il supporto

Modificato: da Water
Link al commento
Condividi su altri siti

Se sei in zona Torino, puoi passare da me in ditta (magari con il contatore di energia) e vedi che sistemiamo il problema ...

Link al commento
Condividi su altri siti

2 ore fa, max.riservo ha scritto:

Se sei in zona Torino, puoi passare da me in ditta (magari con il contatore di energia) e vedi che sistemiamo il problema ...

grazie Max sei molto gentile e ci verrei molto volentieri ..almeno per pagarti una birra! 😁

purtroppo non siamo così vicini, sono della provincia di Milano e molto raramente sono a Torino 😥

comunque a breve ci riprovo .. è garantito! 😁

Link al commento
Condividi su altri siti

1 ora fa, NoNickName ha scritto:

Oppure posti qui i 4 byte grezzi e il valore che ti attendi. 

ciao, questo sono i valori dei primi 10 registri Modbus,

da dataSheet i primi tre registri partendo dall'uno danno la tensione Fase-Neutro delle tre fasi (circa 228/230V),

Clipboard Image.jpg

Link al commento
Condividi su altri siti

ti faccio il primo 17251 54936 = 0x4363 0xD698

 

La tua dword è 0x4363d698

 

4 3 6 3 D 6 9 8
0 1 0 0 0 0 1 1 0 1 1 0 0 0 1 1 1 1 0 1 0 1 1 0 1 0 0 1 1 0 0 0
0 10000110 11000111101011010011000

 

Il primo bit è il segno, quindi positivo.

i successivi otto bit sono l'esponente

Il resto è la mantissa

L'esponente è a complemento 127. 10000110 = 134 - 127 = 7

La mantissa è 1.11000111101011010011000 binario, cioè 1.7799863815307617 decimale

Il risultato è 2^7 * 1.7799863815307617 = 227,838 che è la tua tensione della fase 1

 

Analogamente per le altre.

IEEE 754 floating point standard.

 

La seconda è 0x43653e10 e la tensione è 229.242 

La terza è 0x4365c270 e la tensione è 229.76

Modificato: da NoNickName
Link al commento
Condividi su altri siti

Crea un account o accedi per commentare

Devi essere un utente per poter lasciare un commento

Crea un account

Registrati per un nuovo account nella nostra comunità. è facile!

Registra un nuovo account

Accedi

Hai già un account? Accedi qui.

Accedi ora
×
×
  • Crea nuovo/a...