2 Byte float (KNX DPT9) zurück nach REAL

sbzt

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

aktuell beiße ich mir die Zähne an einer (vermeintlich) recht einfachen Umwandlung aus.

Ich möchte Helligkeitswerte von KNX-Bewegungsmeldern kommend in der Beckhoff SPS weiterverarbeiten. Diese werden auf den Bus als Data Point Type DPT9.004 / EIS 5 gesendet. Sprich ein Luxwert als Gleitkommazahl, welche via 2 Bytes übermittelt wird.
Angeblich ist hier laut KNX-Spec der Wertebereich -671088,64 … 670433,28, was mir für einen 2-Byte-Float-Wert schon seltsam vorkommt.

Ich habe das Ganze nicht über die KL6301 laufen, sondern lausche direkt mittels selbst entwickelter Funktionsblöcke auf den KNXnet/IP-Backbone.
Bis dahin funktioniert auch alles reibungslos, ich bekomme die 2 Byte Nutzdaten grundsätzlich korrekt übermittelt (stimmen mit den RAW-Werten im ETS Busmonitor überein).

Mein Problem ist, diese zwei Byte nun wieder zur korrekten Gleitkommazahl zusammenzufügen.

Bei Verwendung der Beckhoff KNX-Klemme gäbe es einen fertigen Block dafür: EIB_2OCTET_FLOAT_REC
Ich gehe schwer davon aus, dass der die richtigen Werte liefern würde, 100%ig gewiss ist auch das aber nicht, da ja DPT9 wieder mehrere Untertypen hat und somit die Darstellung in der ETS u.U wieder unterschiedlich ist. Ich habe leider hier im Projekt keine KL6301 zur Hand, um das mal zu testen, und leider ist die Bibliothek ja verschlüsselt, ich kann also nicht nachschauen wie Beckhoff das löst und das einfach stumpf nachbauen.

Spaßeshalber habe ich mal trendgemäß das Allheilmittel ChatGPT gefragt und auch da kam nichts wirklich erhellendes rum.

Der letzte Stand war:

Code:
VAR
    wRawValue : WORD := 16#2F78; // Beispielwert
    iMantisse : INT;
    iExponent : INT;
    fResult   : REAL;
END_VAR

// Exponent (oberste 5 Bits extrahieren)
iExponent := SHR(wRawValue, 11);

// Mantisse (untere 11 Bits extrahieren)
iMantisse := wRawValue AND 16#07FF;

// Endgültige Berechnung
fResult := REAL(iMantisse) * EXP(REAL(iExponent - 3) * LOG(2.0)) * 0.08;

Bis zum Skalierfaktor 0.08 ist es ja irgendwo noch logisch, dann wird es aber recht willkürlich. Letztlich will mir die "KI" jedes mal einen anderen Faktor andrehen, bis es halt passt (für dieses eine Wertepaar). ;) Also völliger Käse aus meiner Sicht. Zumindest habe ich keine nachvollziehbaren Ergebnisse bekommen. Verstehe aber auch die Funktion"REAL(...)" nicht - was soll das bewirken? Schmeißt auch einen Fehler im Compiler. Wenn, dann ja wohl INT_TO_REAL...
Aber wie gesagt, ich komme nicht auf die Ergebnisse, obwohl der virtuelle Rechenknecht das angeblich für meine Wertetabelle verifiziert hat.

Ich habe hier mal ein paar Beispielwerte aus der ETS:

Rohdaten: 2F 78
Gleitkommawert: 611,84 lux

Bytes: 2C 39
Gleitkommawert: 345,92 lux

Bytes: 2C 21
Gleitkommawert: 338,24 lux


Gibt es hier jemanden, der in Bitschubserei UND bei KNX-Datentypen sattelfest ist und im wahrsten Sinne des Wortes etwas Licht ins Dunkel bringen kann?💡
Wahrscheinlich liegt die Lösung vor meiner Nase und ich sehe den Wald vor lauter Bäumen nicht.
Vielen Dank für eure Antworten und Ideen!


Edit: Hier habe ich etwas gefunden, was schon mal in die richtige Richtung geht. Dann war der o.g. Code mit der 11 Bit Mantisse ja schon gar nicht sooo verkehrt. Aber so ganz sehe ich da noch nicht durch, der Mathematik-Leistungskurs ist einfach zu lange her. Mehr als Try & Error bleibt mir aktuell nicht und da ist momentan verdammt viel "Error" dabei...

Hier gibts auch noch etwas, da lese ich mich gerade ein.
 
Zuletzt bearbeitet:
Hallo,

schau mal hier auf Seite 39 für die Datentypen.

Mal kurz umgesetzt:
Code:
PROGRAM PLC_PRG
VAR
    wTest:WORD:= 16#8738;
    rTest:REAL;
    
    wMantisse:WORD;
    wExponent:WORD;
    
END_VAR

////////////////////////////////
wExponent := SHR(wTest AND 16#7800,11);

IF wTest > 16#7FFF THEN
    wMantisse := (wTest AND 16#07FF) OR 16#F800;
ELSE
    wMantisse := (wTest AND 16#07FF);

END_IF

rTest := INT_TO_REAL(WORD_TO_INT(wMantisse))*0.01* EXPT(2,wExponent);

Gruß
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Schau mal hier


 
Der code von Thruser in #2 funktioniert, denke ich. Ich habe ihn nur mal in ein SCL-taugliches Format gebracht.

ChatGPT hat auch mir nur mäßig Hilfe geleistet. Vielleicht war es auch nur schwierig, die Problematik richtig rüber zu bringen. Ich habe aber meinen Code gerade noch mal von ihr begutachten lassen. Sie wollte ein paar Datenformate ändern, was ich abgelehnt habe, und sie wollte das Zweierkomplement einfügen. Ganz schön verwirrend ist das. Das Zweierkomplement muss man hier aber nicht berücksichtigen, oder? Das sollte ja in dem vorgegebenen Eigangswert schon berücksichtigt sein?

Andererseits würde ohne das Zweierkomplement das selbe Bitmuster der Mantisse den selben Betrag liefern, und nur das Vorzeichenbit die Polarität, was ja wiederum auch nicht sein kann?

Zweierkomplement eingearbeitet und Anhänge noch mal ausgetauscht. V2 ist besser von #2 abgeguckt und etwas kompakter als V1. Funktionieren müssten jetzt aber beide.
 

Anhänge

Zuletzt bearbeitet:
Schau mal hier


da geht es allerdings anscheinend immer nur in der Gegenrichtung von REAL nach DPT9
 
Hallo,

doch das Zweierkomplement muß man beachten.

In dem verlinkten Dokument ist der Wert so dargestellt: MEEEEMMMMMMMMMMM

Das höchstwertige Bit ist nicht nur ein Vorzeichenbit sondern Teil der Mantisse, daher auch die Fallunterscheidung zu Anfang. Für negative Werte müssen für die einfache Umrechnung (interne Wandlung in 16 Int) die Bitpositionen des Exponents auf 1 gesetzt werden.

Gruß
 
Zurück
Oben