Wandeln Double/Float in S7- dword

the.insider

Level-1
Beiträge
5
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo!

Habe folgendes Problem:

Ich muß von KBR ein Multimess über Profibus an eine S7-315-2 PN/DP
einbinden! Ist auch weiter kein Problem nur die Ausgelesenen Daten liegen nur in Float und Double vor! Float müsste noch mit S7 real übereinstimmen indem ich die HW-Konfig bearbeite, doch was/wie mache ich mit double???

Hier die Info's von KBR:

float:
Format korrespondiert mit dem IEEE 754 Standard
Darstellung 4 Byte
Genauigkeit 24 Bit (􀂾 repräsentieren >7 Dezimalstellen)
Zusammensetzung 24 Bit-Mantisse; 8 Bit Exponent
Mantisse 23 Bit (M) + 1 Bit (S)
Das MSB der Mantisse beträgt immer 1 => wird nicht extra gespeichert!
S = Vorzeichen der Mantisse: S = 1 􀂾 negative Zahl; S = 0 􀂾 positive Zahl
Exponent 8 Bit (0-255); wird relativ zu 127 gespeichert, d.h. der aktuelle Wert destion der Zahl 127 vom
abgespeicherten Wert.
Akt. Exp. = gesp. Wert des Exp. – 127 => Zahlenbereich von 128 bis -127!
Darstellbarer Zahlenbereich:
1.18E-38 bis 3.40E+38
Exponenten ergibt sich aus der Subtrak



double:
Format korrespondiert mit dem IEEE 754 Standard
Darstellung 8 Byte
Genauigkeit 52 Bit (􀂾 repräsentieren >15 Dezimalstellen)
Zusammensetzung 52 Bit-Mantisse; 11 Bit Exponent
Mantisse 52 Bit (M) + 1 Bit (S)
Das MSB der Mantisse beträgt immer 1 => wird nicht extra gespeichert!
S = Vorzeichen der Mantisse: S = 1 􀂾 negative Zahl; S = 0 􀂾 positive Zahl
Exponent 11 Bit (0-2047);
wird relativ zu 1023 gespeichert, d.h. der aktuelle Wert des Exponenten
ergibt sich aus der Subtraktion der Zahl 1023 vom abgespeicherten Wert.
Darstellbarer Zahlenbereich:
2.23E-308 bis 1.80E+308}


Kann mir dabei jemand helfen?
Kann leider noch nichts testen da die Anlage erst kurz vor Inbetriebnahme kommt! :confused: und dann muß ich mit der Programmierung schon fertig sein!
 
Ich hab das ja noch nie machen müssen.
Zuerst sei dies hier empfohlen: http://de.wikipedia.org/wiki/IEEE_754
Die S7 (300-er) kann ja nicht mit Double rechnen. Also würde ich versuchen, die nötigen Kennziffern

Die Darstellung einer Gleitkommazahl

besteht aus:
Vorzeichen s (fast ausnahmslos 1 Bit)
Basis b (bei normalisierten Gleitkommazahlen nach IEEE 754 ist b = 2)
Exponent e (r Bits), nicht zu verwechseln mit dem „biased exponent“ bzw. der Charakteristik
Mantisse m (p Bits), manchmal als Signifikant bezeichnet

zu extrahieren, dann entsprechend zu runden und ins Float-Format umzurechnen. Wenn denn die Double in die Float von der Größe her hineinpaßt. Denke aber, hauptsächlich wegen der höheren Genaugkeit wurde die Double verwendet.
 
Zuletzt bearbeitet:
Ist das denn wirklich nötig ? Hier ging es schon mal um die Anbindung von KBR an S7, insbesondere der Beitrag #20 dürfte interessant sein (Danke an msb dafür).
Wenn ich die GSD-Datei richtig deute, dann gibt es zu jedem double-modul ein korrespondierendes float-modul.

Grüße von HaDi
 
Habt vielen Dank!

Hab ich völlig übersehen, dass es den benötigten Wert auch noch als float gibt und das reicht mir natürlich!!!:TOOL:
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe mal eine Konvertierungsfunktion für IEEE 754 64-Bit double nach 32-Bit Real geschrieben.
Es werden allerdings nur normalisierte Werte (Normalfall) konvertiert. Kommt beim Double ein denormalisierter Wert rein wird Null ausgegeben.

Wenn die Sonderfälle nicht beachtet werden müssten könnte man den Baustein wesentlich verkürzen.

Hier mal der SCL-Code:
Code:
(* DOUBLE_TO_REAL
 * Konvertiert eine IEEE754 64-Bit Gleitpunktzahl in eine IEEE 32-Bit Gleitpunktzahl
 * Liegt der Double-Wert außerhalb des Wertebereiches der 32-Bit Zahl, so
 * wird der entsprechende Max/Min-Wert sowie ein Wert != 0 an Error ausgegeben.
 * 
 * Denormalisierte Werte werden nicht! umgerechnet, sondern es wird 0.0 ausgegeben!
 *
 * Darstellung 64-Bit IEEE754:
 * -------------------------------------------------------------------------------------------
 * S |         Exponent               |            Mantisse
 * -------------------------------------------------------------------------------------------
 * 63|62 61 60 59 58 57 56^55 54 53 52|51 50 49 48^47 46 45 44 43 42 41
 *         BYTE7          ^         BYTE6         ^
 *) 

TYPE DOUBLE :
STRUCT
    byte0 : BYTE;
    byte1 : BYTE;
    byte2 : BYTE;
    byte3 : BYTE;
    byte4 : BYTE;
    byte5 : BYTE;
    byte6 : BYTE;
    byte7 : BYTE;
END_STRUCT
END_TYPE
 
FUNCTION DOUBLE_TO_REAL : REAL
TITLE = 'DOUBLE_TO_REAL'

VERSION : '0.1'
AUTHOR  : TWI
NAME    : DBL_REAL
FAMILY  : CONVERT

CONST 
    FLT_MAX := REAL#3.402823e+38;
    FLT_MIN := REAL#1.175495e-38;     
    S_INF := 16#1;
    S_NAN := 16#2;
    S_MAX := 16#3;
    S_MIN := 16#4;
    S_DEN := 16#5;
END_CONST

VAR_INPUT
    dbl         : DOUBLE;   // (* Byte-Array mit 64-Bit IEEE754 Zahl *)
END_VAR

VAR_OUTPUT             
    wStatus     : WORD;     // (* Statusausgabe *)
END_VAR

VAR_TEMP
    xMant_Null  : BOOL;         (* Mantisse des Double-Wertes ist Null *)
    iExponent   : INT;          (* Exponent Double *)
    bFlt_exp    : BYTE;         (* Exponent Real *)
    rFlt_val    : REAL;         (* Real-Wert *)
    dw_AT_rFlt_val AT rFlt_val: DWORD; (* Hilfssicht auf Real-Wert *) 
END_VAR
(******************************************************************************)
    wStatus := 16#0; 
    (* Exponent bestimmen (11 Bit) Bits 52-63; Vorzeichenbit ausmaskieren und Mantissenbits rausschieben*)
    iExponent := WORD_TO_INT(SHL(IN := BYTE_TO_WORD(dbl.byte7 AND 16#7F), N := 4) OR 
                             SHR(IN := BYTE_TO_WORD(dbl.byte6), N := 4));
    
    (* Für Sonderfälle: Prüfen ob Mantisse Null ist *)    
    xMant_Null := ((dbl.byte6 AND 16#0F) OR dbl.byte5 OR dbl.byte4 OR dbl.byte3 OR dbl.byte2 OR dbl.byte1 OR dbl.byte0) = 0;    
    
    (* Sonderfälle abfragen *)
    IF (iExponent = 0) THEN       
        IF (xMant_Null = TRUE) THEN        (* Null *)
            DOUBLE_TO_REAL := 0.0;
            RETURN;
        ELSE                                (* denormalisierter Wert, wird hier nicht ausgewertet sondern 0 ausgegeben! *)
            wStatus := S_DEN;
            bFlt_exp := 0;
            DOUBLE_TO_REAL := 0.0;
            RETURN;
        END_IF;
    ELSIF (iExponent = 2047) THEN 
        IF (xMant_Null = TRUE) THEN         (* Infinity *)
            wStatus := S_INF;
            bFlt_exp := 16#FF;
        ELSE                                (* NaN, Not a Number *)
            wStatus := S_NAN;
            bFlt_exp := 16#FF;
        END_IF;    
    ELSE    
        iExponent := iExponent - 1023;       (* Bias des Exponenten wieder abziehen *)                                                                                                           
        IF (iExponent < -126) THEN           (* Bereich unterschritten *)
            wStatus := S_MIN;
            DOUBLE_TO_REAL := FLT_MIN;
            RETURN;
        ELSIF (iExponent > 127) THEN         (* Bereich überschritten *)
            wStatus := S_MAX;
            DOUBLE_TO_REAL := FLT_MAX;
            RETURN;       
        END_IF;
        
        (* Neuen Exponenten mit Bias bestimmen *)
        bFlt_exp := INT_TO_BYTE(iExponent + 127);
    END_IF;   
    
    (* Vorzeichenbit *)
    dw_AT_rFlt_val := SHL(IN := BYTE_TO_DWORD(dbl.byte7 AND 16#80), N := 24);
    (* Exponent 8 Bit *)
    dw_AT_rFlt_val := dw_AT_rFlt_val OR SHL(IN := BYTE_TO_DWORD(bFlt_exp), N := 23);
    (* Mantisse 23 Bit *)
    dw_AT_rFlt_val := dw_AT_rFlt_val OR SHL(IN := BYTE_TO_DWORD(dbl.byte6 AND 16#0F), N := 19)
                                     OR SHL(IN := BYTE_TO_DWORD(dbl.byte5), N := 11)
                                     OR SHL(IN := BYTE_TO_DWORD(dbl.byte4), N := 3)
                                     OR SHR(IN := BYTE_TO_DWORD(dbl.byte3), N := 5);
    
    DOUBLE_TO_REAL := rFlt_val;   
END_FUNCTION
Ich finde ja dass das Bitgeschubse in SCL etwas unkomfortabel ist, in AWL wäre das wesentlich einfacher.
Oder kennt jemand eine Möglichkeit das einfacher zu schreiben? Evtl. mit einer zusätzlichen AT-Sicht?

Mich stören vor allem die ganzen x_TO_y, aber sonst meckert der Compiler...
 
Hallo zusammen,
ich hole den alten Thread mal wieder vor.

Ich möchte den Baustein von Thomas_v2.1 benutzen, bekomme aber den UDT nicht vernünftig als Parameter übergeben. Es gibt immer einen Fehler.

Meine bisherige Vorgehensweise:
Quelle erzeugt.
Baustein (FC100) aus Quelle erzeugt.
UDT100 erzeugt (Symbol: "DOUBLE").
DB100 erzeugt, in dem der UDT100 benutzt wird (Byte 0-7).

Wie genau bekomme ich den UDT im DB jetzt als Parameter an den Baustein übergeben? Gibt es da einen Trick?

Ich habe es so probiert: P#DB100.DBX0.0 Byte 8
oder so: DB100.DOUBLE

Funktioniert beides nicht.

Vielleicht kann mir ja jemand helfen.

Vielen Dank.
 
Hallo,
wenn dein Datenbaustein einen symbolischen Namen hat dann könnte es z.B. so aussehen :
Code:
dbl := "mein_symbolischer_DB_Name".mein_sysmbolischer_UDT_Name
Gruß
Larry
 
Zurück
Oben