Umrechnen von Float16

Kurzschluß

Level-2
Beiträge
56
Reaktionspunkte
2
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich wende mich an Euch bezüglich eines Problems, das ich bei einem Projekt mit dem Modbus RTU habe. Dabei geht es um die Umrechnung von Float16-Werten. Ich konnte bereits Float32-Werte erfolgreich umrechnen, jedoch stoße ich bei den Float16-Werten auf Schwierigkeiten, insbesondere mit der Mantisse.

Unsere Konfiguration umfasst einen PFC200 mit e!Cockpit und FW22. Ich bin dankbar für jegliche Hilfe oder Anleitung, die Sie mir bezüglich dieser Umrechnung geben könnt.

Vielen Dank im Voraus für Eure Unterstützung.
 
Prionzipiell musst Du "nur" den Exponent und das Vorzeichen an die richtige Stelle schieben.
der Float_16 Wert wird über Modbus als WORD ankommen.

wFloat16 : WORD;

Das Vorzeichen wird maskiert und an die richtige Stelle geschoben:
SHL(TO_DWORD(wFloat16) AND 16#8000, 16)

Ich nehme einen Exponent von 5 Bit an.
SHL(TO_DWORD(wFloat16) AND 16#7C00, 12)

Die Mantisse kann direkt übernommen werden

Diese drei Teile müssen dann zusammengeführt werden:
SHL(TO_DWORD(wFloat16) AND 16#8000, 16) + SHL(TO_DWORD(wFloat16) AND 16#7C00, 12) + ( wFloat16 AND 16#03FF )

Um dieses DWORD in ein REAL zu überführen kann ein Pointer oder ein Union verwendet werden.
wFloat16 : WORD;
rMyFloat32 : REAL;
pDWort : POINTER TO DWORD;
----------
pDWort := ADR(rMyFloat32);
pDWort^ := SHL(TO_DWORD(wFloat16) AND 16#8000, 15) + SHL(TO_DWORD(wFloat16) AND 16#7C00, 12) + ( wFloat16 AND 16#03FF );
 
Ich fürchte, dass es nicht ganz so einfach ist. Zuimindest bei IEEE 754.

Der Exponent hat ein anderes "Bias", 15 stat 127, muss also umgerechnet werden.

Schließlich gibt es bei der Mantisse Sonderfälle, die nicht normalisiert sind und formal gesondert behandelt werden müssen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ob das Format so passt, kann man ja ausprobieren.
Da der zu erwartende Wert bekannt sein sollte, kann man diese zum Test einer REAL Variable zuweisen und Exponent und Mantisse mit dem Modbuswert vergleichen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Sorry natürlich nicht. Habe es selbst gelöst. Anbei mein Code, bin aber noch am testen darum war ich mir noch unsicher ihn online zu stellen.

ntegerValue := TRUNC(Eingang);

sign := SHR(Eingang, 15) AND 1;
exponent := SHR(Eingang, 10) AND 31;
mantissa := Eingang AND 1023;

IF exponent = 0 THEN
Float16_Real_MB := EXPT(-1, sign) * EXPT(2, -14) * (0 + (mantissa/1024));
ELSIF exponent =31 THEN
Float16_Real_MB := 0;
ELSE
Float16_Real_MB := EXPT(-1, sign) * EXPT(2, exponent - 15) * (1 + (mantissa/1024));
END_IF
 
Bist Du sicher das Du das so kompilieren kannst?

Also möchtest Du aus einer 32 Bit REAL Variable ein 16 Bit Float machen.
Ich bin von der anderen Richtung ausgegangen.

Eingang scheint ja deine REAL Variable zu sein.
Die REAL Variable kann aber nicht als Eingang einer Schiebeoperation (SHR) verwendet werden.
Das Vorzeichen sign wird nicht korrekt ausgewertet. sign ist immer Null egal ob der Real Wert Positiv oder Negativ ist.
 
Unabhängig von der Zulässigkeit nach IEC: Wenn SHR vorzeichen-richtig schiebt, dann bleibt das Vorzeichen erhalten.
(ich kenne die Wago und deren spezielle ST-Implementation nicht, und habe den Code nicht überprüft).

PS: Für mich sieht der Code so aus, als ob er aus einem FLOAT16 einen Standard-REAL32 macht.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Unabhängig von der Zulässigkeit nach IEC: Wenn SHR vorzeichen-richtig schiebt, dann bleibt das Vorzeichen erhalten.
(ich kenne die Wago und deren spezielle ST-Implementation nicht, und habe den Code nicht überprüft).
Übrigens kann man das Vorzeichenbit auch ganz ohne Schieben isolieren/ermitteln:
sign := (Eingang AND 16#8000) <> 0;
 
Zurück
Oben