DWORD aus 4 Bytes to signed INT

philipp75

Level-2
Beiträge
67
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi,

ich spreche einen Service meiner Wärmepumpe an, um damit ein paar Temperaturen auszulesen.

Die Wärmepumpe (Luxtronic) liefert Werte, die ich als BYTES -> DWORDs -> REAL auslese über die SysLibSockets (Wago Steuerung, Codesys 2.x)

Code:
V_tempAussen := DWORD_TO_REAL(DWORD_OF_BYTE(R_BUF.BUFFER[72],R_BUF.BUFFER[73],R_BUF.BUFFER[74],R_BUF.BUFFER[75]))/10;

DWORD_OF_BYTE habe ich aus der Oscat Lib:
Code:
FUNCTION DWORD_OF_BYTE : DWORD
VAR_INPUT
    B3 : BYTE;
    B2 : BYTE;
    B1 : BYTE;
    B0 : BYTE;
END_VAR
--
DWORD_OF_BYTE := SHL(SHL(SHL(BYTE_TO_DWORD(B3),8) OR BYTE_TO_DWORD(B2),8) OR BYTE_TO_DWORD(B1),8) OR BYTE_TO_DWORD(B0);

Sobald die Temperator < 0 wird klappt es mit dem Vorzeichen nicht mehr, > 0 °C sieht alles gut aus.
Nach einigen Versuchen komme ich nicht auf den Trichter, wie ich das zu einem Signed INT / 100 oder direkt in ein vorzeichenbehaftetes REAL konvertieren kann.

Vielen Dank für Eure Hilfe!
Philipp
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi Thomas-

Danke, ja dem ist so. Aber wie geht´s denn nun? ;)

damit habe ich es schon versucht:
Code:
FUNCTION BYTES_TO_REAL : REAL
VAR_INPUT
 IN : ARRAY[0..3] OF BYTE;
END_VAR
VAR
 PTREAL:POINTER TO REAL;
END_VAR

--

PTREAL:=ADR(IN);
BYTES_TO_REAL := PTREAL^;

Grüße,
Philipp
 
@TE:
Deine Umsetzung in Beitrag #6 wäre jetzt aber genau das gewesen was ich dir vorgeschlagen hätte.
Das sieht jetzt für dich vielleicht unelegant aus - entspricht aber genau dem was du vorhast - also dem Casten, wie es jede Programmiersprache erwarten würde ...

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
DINT_TO_REAL(DWORD_TO_DINT(DWORD_OF_BYTE( [byteArray] )))/100;
Perfekt! Fast jedenfalls. Kann man noch ein Bisschen umständlicher/korrekter schreiben, indem man 100.0 statt 100 schreibt.
Das erspart dem Compiler, eine "unsichtbare" TypAnpassung für die Konstante. ;)
 
na wenns so sein muss, ists halt elegant genug ;)
Danke für den Tipp mit 100.0.

Warum geht es dann direkt volley mit DWORD_TO_REAL nicht? ;)
 
Warum geht es dann direkt volley mit DWORD_TO_REAL nicht?
Wie Thomas_v2.1 schon in #2 schrieb: weil DWORD als vorzeichenloser 32-Bit-Wert (UDINT, 0 bis 4'294'967'295) interpretiert wird - der Wert kann nicht negativ werden. Daher muß man dem Codesys mit DWORD_TO_DINT erklären daß ein gegebenes 32-Bit-DWORD als vorzeichenbehafteter DINT (-2'147'483'648 bis +2'147'483'647) interpretiert werden soll, den man dann inklusive Vorzeichen in REAL konvertieren kann (DINT_TO_REAL).

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Der Ansatz in Post 3 war doch garn nicht schlecht. Einfach nur der Falsche Typ für den Pointer gewählt. Ich würde das so machen:
Code:
FUNCTION BYTES_TO_REAL : REAL
VAR_IN_OUT //Spart Laufzeit und Speicher (Daten werden nicht umkopiert
	IN : ARRAY[0..3] OF BYTE;
END_VAR
VAR
	_p : POINTER TO DINT;
END_VAR

_p := ADR(IN);
BYTES_TO_REAL:= DINT_TO_REAL(_p^) / REAL#100;

Noch lieber würde ich gleich den ganzen Empfangspuffer reinstecken dann sieht das so aus:
Code:
FUNCTION ExtractTemp : REAL
VAR_IN_OUT //Spart Laufzeit und Speicher (Daten werden nicht umkopiert
	IN : ARRAY
[*] OF BYTE; //Hier einfach den ganzen Empfangspuffer reinstecken 
END_VAR
VAR
	_aB: ARRAY [0..3] OF BYTE;
	_p : POINTER TO DINT:= ADR(_aB); 
END_VAR


//Wenn ich richtig verstanden habe kommen die Bytes falsch rum.
//Ich mag die Schieberrei aus der Oscat nicht und lasse lieber den Compiler entscheiden, wie das am besten geht, deshalb einfach 4 Zuweisungen
_aB[3]:= IN[72];
_aB[2]:= IN[73];
_aB[1]:= IN[74];
_aB[0]:= IN[75];
// Natürlich geht das auch in einer FOR Schleife spart bei 4 Byte aber nichts


ExtractTemp:= DINT_TO_REAL(_p^) / REAL#100;
 
Zurück
Oben