e!COCKPIT ModbusTCP Floatwert zu Real konvertieren

RobbyJump

Level-1
Beiträge
30
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
[Gelöst] e!COCKPIT ModbusTCP Floatwert zu Real konvertieren

Hallo zusammen,
ich denke dass es hier recht gut reinpasst da e!Cockpit etwas spezieller ist als das blanke Codesys.

Mein Problem ist aktuell das einlesen von Floats über Modbus TCP.
Verwendet wird ein 750-8207 zusammen mit mehreren Janitza UMG801
Der Zugriff und die Konfig über den Modbuskonfigurator (Netzwerkansicht) verlief wie gewohnt unproblematisch, nun kommt allerdings der Knackpunkt beim einlesen der Werte, da diese nur als Float vorliegen.
Probiert habe ich unteranderem schon den Datenpunkt als Real,LReal,Int,DWord und Word einzulesen mit dem ergebniss dass es in keine sinnvolles Format konvertiert wird.
Die Frage ist nun ob man es mit einem Baustein hinbekommt oder es andere Möglichkeiten ohne viel Aufwand (da es viele Datenpunkte werden) gibt mit denen man das Problem erschlagen kann.

Ich stehe etwas auf dem Schlauch, jeder Hinweis kann mir weiterhelfen

Danke
Gruß Robin
 
Zuletzt bearbeitet:
Hallo Robin,

Janitza stellt die Werte als little Endian bereit. Somit müsstest Du die Bytereihenfolge tauschen.
Wago arbeitet z.B. mit der Reihenfolge 1234. Janitza mit 4321. Modbus definiert dass das High Byte zuerst gesendet werden muss. Also resultiert daraus 3412. Somit muss Du nur das High und Low Word tauschen.
Du könntest z.B eine Funktion schreiben. Mit einem Pointer to Array [0..1] of Word auf den Real Wert gelegt, kannst Du die Wörter tauschen.

Einige Janitza Geräte liefern die Werte auch im Big Endian an bestimmmten Modbus Adressen.

Grüße
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi Tobsucht,
das ist auf jeden fall ein guter Hinweis an dem ich mich mal probieren muss.
Wenn ich es also richtig verstehe müsste ich ein Dword mit der Bytereihenfolge 1234 generieren und dieses nur mit DWORD_TO_REAL wandeln?
Die Reihenfolge in Big-Endian ist aber 4321 und in Little 3412 so dass ich am besten die Little-Endian-Register (z.B. 19000+32768 ) als DWORD einlese um dann die Wortreihenfolge zu tauschen?

Byte sequence
The data in the modbus address list can be called up in the
• Big-Endian (high-Byte before low-Byte) and in the
• Little-Endian (low-byte before high-byte)
format.
The addresses described in this address list supply the data in the „Big-Endian“ format.
If you require the data in the „Little-Endian“ format, you must add the value 32768 to the address.

Hierbei ist gerade aufgefallen dass die Adressen ab 51768 nur den Wert 0 liefern (vom Janitzer Support bestätigt, ist ein Firmwarefehler).


Gibt es nicht eine schönere variante ohne alle Datenpunkte erst konvertieren zu müssen?
Sonnst muss ich für jeden Datenpunkt einen Wandlerbaustein (den man zum glück nur einmal bauen muss) nutzen und diesen manuell Verknüpfen (sind so Ca 250+ Datenpunkte)
Irgendwie nervig dass man nicht einfach Wert x100 als Int bekommen kann.

Danke schonmal

Gruß
 
Besten Dank für eure kompetente Unterstützung!

Wago hat mir durch ein Supportticket mitgeteit, dass REAL und FLOAT nach IEEE754 identisch sind und die PFC200 BigEndian (Motorolaformat) somit unterstützen.
In Zukunft wird es vermutlich auch möglich sein im Modbuskonfigurator (e!Cockpit) die Bytereihenfolge zu ändern.

Zudem habe ich aus anderen Gründe auch einmal mit Janitza gesprochen wobei mir bestätigt wurde das die 19000der Register des UMG801 in BigEndian vorliegen, die LittleEndian register hat das Gerät nicht (Fehler in der Anleitung).
Zukünftig wird es hier ggf. auch möglich sein die Register extra zu Konfigurieren.

Nach dem ich das Ganze dann noch einmal versucht habe, ist mir aufgefallen dass die Register um 1 verrutscht sind (Register 19000 in der Wago als 18999 implementieren)
...da hätte ich auch ehr drauf kommen können...

Auf jeden fall ist dieses Problem aus der Welt und doch alles recht einfach.
Anbei noch zwei Screenshoots aus meinem Testprogramm.


messwertejanitzatestkonfig.PNGmesswertejanitzatest.PNG
Danke euch nochmals
Gruß Robin
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Zusammen,

ich bin aktuell auch auf diese Problem gestoßen, als ich aus einem DEOS-Controller REAL-Werte lesen wollte (DEOS --> Slave, WAGO --> Master). DEOS verwendet offensichtlich das little endian Format. Nachdem sowohl WAGO als auch DEOS keine einstellbares Format anbieten, musste ich eine kleine Funktion zur Umwandlung schreiben, welche auch funktioniert. Leider bin ich nicht der Held, was das Programmieren anbetrifft und so hab ich es sicherlich viel zu umständlich fabriziert:

Code:
FUNCTION SWAP1 : REAL

VAR_INPUT
    rbig_endian:REAL;
END_VAR

VAR
    DW_R: DW_R_Union;
    R_DW: DW_R_Union;
END_VAR

R_DW.rUnion:=rbig_endian;

DW_R.dwUnion.16:=R_DW.dwUnion.0;
DW_R.dwUnion.17:=R_DW.dwUnion.1;
DW_R.dwUnion.18:=R_DW.dwUnion.2;
DW_R.dwUnion.19:=R_DW.dwUnion.3;
DW_R.dwUnion.20:=R_DW.dwUnion.4;
DW_R.dwUnion.21:=R_DW.dwUnion.5;
DW_R.dwUnion.22:=R_DW.dwUnion.6;
DW_R.dwUnion.23:=R_DW.dwUnion.7;

DW_R.dwUnion.24:=R_DW.dwUnion.8;
DW_R.dwUnion.25:=R_DW.dwUnion.9;
DW_R.dwUnion.26:=R_DW.dwUnion.10;
DW_R.dwUnion.27:=R_DW.dwUnion.11;
DW_R.dwUnion.28:=R_DW.dwUnion.12;
DW_R.dwUnion.29:=R_DW.dwUnion.13;
DW_R.dwUnion.30:=R_DW.dwUnion.14;
DW_R.dwUnion.31:=R_DW.dwUnion.15;

DW_R.dwUnion.0:=R_DW.dwUnion.16;
DW_R.dwUnion.1:=R_DW.dwUnion.17;
DW_R.dwUnion.2:=R_DW.dwUnion.18;
DW_R.dwUnion.3:=R_DW.dwUnion.19;
DW_R.dwUnion.4:=R_DW.dwUnion.20;
DW_R.dwUnion.5:=R_DW.dwUnion.21;
DW_R.dwUnion.6:=R_DW.dwUnion.22;
DW_R.dwUnion.7:=R_DW.dwUnion.23;

DW_R.dwUnion.8:=R_DW.dwUnion.24;
DW_R.dwUnion.9:=R_DW.dwUnion.25;
DW_R.dwUnion.10:=R_DW.dwUnion.26;
DW_R.dwUnion.11:=R_DW.dwUnion.27;
DW_R.dwUnion.12:=R_DW.dwUnion.28;
DW_R.dwUnion.13:=R_DW.dwUnion.29;
DW_R.dwUnion.14:=R_DW.dwUnion.30;
DW_R.dwUnion.15:=R_DW.dwUnion.31;


SWAP1:=DW_R.rUnion;

Ich hab dann mal versucht, das Ganze zu vereinfachen, in dem ich hier im Forum Codeschnipsel zu einem ähnlichen Problem geklaut habe. Leider tappe ich bei der Bitmaskierung immer völlig im Dunklen und hab das hier fabriziert ... erwartungsgemäß funktioniert es natürlich nicht:

Code:
FUNCTION SWAP2 : REAL

VAR_INPUT
    In:REAL;
END_VAR

VAR
    DW_R: DW_R_Union;
    R_DW: DW_R_Union;
    dw_in: DWORD;
END_VAR

R_DW.rUnion:=In;
dw_in:=R_DW.dwUnion;

    DW_R.dwUnion:=  SHR(dw_in AND 16#FF000000 ,24) OR 
                    SHR(dw_in AND 16#00FF0000 ,8 ) OR
                    SHL(dw_in AND 16#0000FF00 ,8 ) OR
                    SHL(dw_in AND 16#000000FF ,24) ;

SWAP2 := DW_R.rUnion;

Vielleicht hat jemand Lust, sich den Stuss mal anzusehen und hat eine Idee für mich, wie man's richtig machen kann.

Ach ja ... das ist das Union:

Code:
TYPE DW_R_Union :
UNION
    rUnion: REAL;
    dwUnion: DWORD;    
END_UNION
END_TYPE

Grüße Holger
 
Zuletzt bearbeitet:
Wenn deine Bit-Logik funktioniert, sollte das so gehen:

Code:
FUNCTION SWAP2 : REAL

VAR_INPUT
    In:REAL;
END_VAR

VAR
    DW_R: DW_R_Union;
    R_DW: DW_R_Union;
    dw_in: DWORD;
END_VAR

R_DW.rUnion:=In;
dw_in:=R_DW.dwUnion;

    DW_R.dwUnion:=  SHR(dw_in AND 16#FFFF0000 ,16) OR 
                    SHL(dw_in AND 16#0000FFFF ,16) ;

SWAP2 := DW_R.rUnion;

Alternativ geht's auch mit Pointer:

Code:
FUNCTION ByteSwap : REAL
VAR_INPUT
    In: REAL;
END_VAR
VAR
    dwOut: REAL;
    pbSource: POINTER TO INT;
    pbDest: POINTER TO INT;
END_VAR


Code:
pbSource := ADR(In);
pbDest := ADR(dwOut)+2;

pbDest^:=pbSource^;

pbSource := ADR(In)+2;
pbDest := ADR(dwOut);

pbDest^:=pbSource^;

ByteSwap := dwOut;
 
Hey Oberchefe,

Codebeispiel 1 funktioniert schon bestens. Danke für Deine Hilfe, auch wenn ih jetzt noch verwirtter bin. Ich muss ja bei der Umwandlung little in big endian die Bytereihenfolge von 1234 in 4321 wandeln. Mit meinem Tippel-Tappel Bit-Austauschen passiert ja genau das. Das mit dem Maskieren uns schieben hab ich offensichtlich aber echt nicht gerafft. Ich dachte mir das so:

SHR(dw_in AND 16#FF000000 ,24) OR // maskiert Byte 1 und schiebt es 24 Bit nach rechts, also an Stelle von Byte 4
SHR(dw_in AND 16#00FF0000 ,8 ) OR // maskiert Byte 2 und schiebt es 8 Bit nach rechts, also an Stelle von Byte 3
SHL(dw_in AND 16#0000FF00 ,8 ) OR // maskiert Byte 3 und schiebt es 8 Bit nach links, also an Stelle von Byte 2
SHL(dw_in AND 16#000000FF ,24) ; // maskiert Byte 4 und schiebt es 8 Bit nach links, also an Stelle von Byte 1

Bei Deinem Code werden für mich theoretisch die Bytes in den geschobenen Wortwerten nicht getauscht, da käme für mich jetzt
eine Bytereihenfolge von 3412 raus ?! Aber es funktioniert ja tadellos ... wo ist nur mein Denkfehler ???

Grüße Holger
 
Wenn schon mit UNION oder Pointer gearbeitet wird, warum dann noch so unverständliches umständliches Maskieren und Schieben? Dann kann man doch ganz übersichtlich alle 4 Bytes einzeln in beliebiger Folge an die richtigen Stellen kopieren:
Code:
TYPE R_B4_Union :
UNION
    rUnion: REAL;
    abUnion: ARRAY[0..3] OF BYTE;
END_UNION
END_TYPE

...

VAR
    uIn: R_B4_Union;
    uOut: R_B4_Union;
END_VAR

uIn.rUnion := In;
uOut.abUnion[1] := uIn.abUnion[3];
uOut.abUnion[0] := uIn.abUnion[2];
uOut.abUnion[3] := uIn.abUnion[1];
uOut.abUnion[2] := uIn.abUnion[0];

SWAP2 := uOut.rUnion;
Das läßt sich auch für andere Tauschereien easy weiternutzen/anpassen.

Harald
 
Deine Bitlogik sagt aber was anderes. Die macht aus AABBCCDD ein CCDDAABB

Stimmt ... Du hast recht, ich hatte an der Bitlogik so lange rumgebastelt, bis es gepasst hatte ... 1234 --> 4321 der erste Versuch, nach Literatur ... war's in meinem Falle aber nicht. Vielen Dank nochmal ... dass lag der Fehler gar nicht bei der Bitmaske.

Grüße Holger
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn schon mit UNION oder Pointer gearbeitet wird, warum dann noch so unverständliches umständliches Maskieren und Schieben? Dann kann man doch ganz übersichtlich alle 4 Bytes einzeln in beliebiger Folge an die richtigen Stellen kopieren:
Code:
TYPE R_B4_Union :
UNION
    rUnion: REAL;
    abUnion: ARRAY[0..3] OF BYTE;
END_UNION
END_TYPE

...

VAR
    uIn: R_B4_Union;
    uOut: R_B4_Union;
END_VAR

uIn.rUnion := In;
uOut.abUnion[1] := uIn.abUnion[3];
uOut.abUnion[0] := uIn.abUnion[2];
uOut.abUnion[3] := uIn.abUnion[1];
uOut.abUnion[2] := uIn.abUnion[0];

SWAP2 := uOut.rUnion;
Das läßt sich auch für andere Tauschereien easy weiternutzen/anpassen.

Harald


Genial ! Danke !!!
 
Hallo RobbyJump,

hast Du die Werte einfach als REAL Adresse minus 1 ausgelesen?

Stehe momentan vor dem gleichen Problem und bekomme keine plausiblem Werte raus bei einem Janitza UM6G04.

Besten Dank für eure kompetente Unterstützung!
Wago hat mir durch ein Supportticket mitgeteit, dass REAL und FLOAT nach IEEE754 identisch sind und die PFC200 BigEndian (Motorolaformat) somit unterstützen.
In Zukunft wird es vermutlich auch möglich sein im Modbuskonfigurator (e!Cockpit) die Bytereihenfolge zu ändern.

Zudem habe ich aus anderen Gründe auch einmal mit Janitza gesprochen wobei mir bestätigt wurde das die 19000der Register des UMG801 in BigEndian vorliegen, die LittleEndian register hat das Gerät nicht (Fehler in der Anleitung).
Zukünftig wird es hier ggf. auch möglich sein die Register extra zu Konfigurieren.

Nach dem ich das Ganze dann noch einmal versucht habe, ist mir aufgefallen dass die Register um 1 verrutscht sind (Register 19000 in der Wago als 18999 implementieren)
...da hätte ich auch ehr drauf kommen können...

Auf jeden fall ist dieses Problem aus der Welt und doch alles recht einfach.
Anbei noch zwei Screenshoots aus meinem Testprogramm.


Anhang anzeigen 48955Anhang anzeigen 48956
Danke euch nochmals
Gruß Robin
 
Hast Du auch 4 Bytes gelesen?
Hast Du die Bytes, die Du vom UMG604 erhältst, mit dem Janitza Modbus Diagnose Test Client verglichen? Hast Du mit dem Tool auch mal 2 Register (2 Word, 4 Byte) vorher und 2 Register nachher gelesen und mit Deinen Antwort-Bytes verglichen? Möglicherweise siehst Du da Deine Bytes und wie die getauscht werden müssen, damit ein plausibler Wert rauskommt.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Habe jetzt eine Lösung gefunden.
Ich schreibe den Modbus-Wert in ein REAL. Über eine Funktion konvertiere ich die Rohdaten in den passenden REAL-Wert.

Code:
FUNCTION fb_Janitza_FLOAT_TO_REAL : REAL
VAR_INPUT
Input_Real : REAL;
END_VAR
VAR
Word_0 : WORD;
Word_1 : WORD;
dwDummy : DWORD;
ptDummy : POINTER TO REAL;


wArr : ARRAY [0..1] OF WORD;
pReal : POINTER TO REAL;
END_VAR
QUOTE]

pReal := ADR(wArr); //Pointer auf Anfangsadresse des Word-Array setzen
pReal^:= Input_Real; //REAL-Wert in das Word-Array speichern
Word_0 := wArr[0]; // Array in WORD 1 schreiben
Word_1 := wArr[1]; //// Array in WORD 2 schreiben


dwDummy:= SHL(WORD_TO_DWORD(Word_0),16)+ WORD_1; // Beide Wörter in ein DWORD schreiben
ptDummy:= ADR(dwDummy); //Pointer auf das DWORD
fb_Janitza_FLOAT_TO_REAL:= ptDummy^; //Pointer an REAL aus Funktionsrückgabe geben

Hast Du auch 4 Bytes gelesen?
Hast Du die Bytes, die Du vom UMG604 erhältst, mit dem Janitza Modbus Diagnose Test Client verglichen? Hast Du mit dem Tool auch mal 2 Register (2 Word, 4 Byte) vorher und 2 Register nachher gelesen und mit Deinen Antwort-Bytes verglichen? Möglicherweise siehst Du da Deine Bytes und wie die getauscht werden müssen, damit ein plausibler Wert rauskommt.

Harald
 
Au, das schmerzt... das kann man im SPS-Fachforum so nicht stehenlassen ;)
Besser so:
Code:
[COLOR="#008000"](* 32 Bit Byteorder 3412 zu 1234 tauschen = H/L-Words tauschen *)[/COLOR]
FUNCTION fc_Janitza_FLOAT_TO_REAL : REAL
VAR_INPUT
  Input_Real : REAL;
END_VAR
VAR
  dwTemp : DWORD;
  pReal : POINTER TO REAL;
END_VAR

pReal := ADR(dwTemp);       [COLOR="#008000"]//Pointer auf das DWORD setzen[/COLOR]
pReal^:= Input_Real;        [COLOR="#008000"]//Input-Wert in das DWORD speichern[/COLOR]

dwTemp := ROL(dwTemp, 16);  [COLOR="#008000"]//die beiden Words des DWORD tauschen[/COLOR]

fc_Janitza_FLOAT_TO_REAL := pReal^;  [COLOR="#008000"]//das DWORD als REAL zurückgeben[/COLOR]

Harald
 
Zurück
Oben