Scl string_to_real

Matze001

Level-3
Beiträge
2.814
Reaktionspunkte
573
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Tag,

ich hab mal wieder ein Problem, und denke wohl etwas kompliziert... vielleicht geht es ja ganz einfach.

Von einer Maschine bekomme ich Werte übermittelt. Diese liegen in einem Array of CHAR.

Beispiel:

Code:
RCV_ARRAY[0] = VORZEICHEN
RCV_ARRAY[1] = 1
RCV_ARRAY[2] = 2
RCV_ARRAY[3] = 3
RCV_ARRAY[4] = 4
RCV_ARRAY[5] = 5
RCV_ARRAY[6] = 6
RCV_ARRAY[7] = .
RCV_ARRAY[8] = 1
RCV_ARRAY[9] = 2
RCV_ARRAY[10] = 3
RCV_ARRAY[11] = 4
RCV_ARRAY[12] = 5
RCV_ARRAY[12] = 6

Also handelt es sich vereinfacht um einen String '-123456.123456'

Mit der tollen Funktion FC39 STRNG_R (STRING_TO_REAL) hoffte ich mein Problem zu lösen, aber siehe da... Siemens kann halt nicht einfach.
Es muss folgendes Format eingehalten werden

Code:
-1.1234567E+00

Warum das so ist, weiß ich nicht. Wenn ich z.B. folgendes tippe geht es:

Code:
DUMMY:=STRING_TO_REAL('3.1415');

Wohingegen dieses nicht tut

Code:
VARIABLE:='3.1415';
DUMMY:=STRING_TO_REAL(VARIABLE);

Das sollte ja eigentlich KEINEN Unterschied machen (Außer Siemens hat es nicht so mit den ersten zwei Byte des String?)


Mein Ansatz ist nun folgender. Jedes Array Element mit einem Faktor versehen,und manuell zu einem Real zusammen zu basteln... aber das muss doch einfacher gehen?!

Also Dann so:

Code:
RCV_ARRAY[0] = VORZEICHEN
RCV_ARRAY[1] = 1
RCV_ARRAY[2] = 2
RCV_ARRAY[3] = 3
RCV_ARRAY[4] = 4
RCV_ARRAY[5] = 5
RCV_ARRAY[6] = 6
RCV_ARRAY[7] = .
RCV_ARRAY[8] = 1
RCV_ARRAY[9] = 2
RCV_ARRAY[10] = 3
RCV_ARRAY[11] = 4
RCV_ARRAY[12] = 5
RCV_ARRAY[12] = 6

REALVAR:= (RCV_ARRAY[1] * 100 000) + (RCV_ARRAY[2] * 10 000) + (RCV_ARRAY[3] * 1 000) + (RCV_ARRAY[4] * 100) + (RCV_ARRAY[5] * 10) + (RCV_ARRAY[6] * 1) + (RCV_ARRAY[8] * 0.1) + (RCV_ARRAY[9] * 0.01) ...

Das sieht aber meiner Meinung nach weder hübsch aus, noch ist es "sauber".

Wie geht ihr mit sowas um? Ich brauche auch die Genauigkeit, mit der die Daten übermittelt werden, also wäre STRING_R eh keine Option für mich.
Das ganze muss später auch rückwärts gehen. Also REAL_TO_STRING.

Freu mich auf eure Vorschläge!

Grüße

Marcel

P.S: Warum kann Siemens nicht einfach einfach sein?
 
Leg Dir eine Variable tmp an.

tmp := STRING[16]

tmp :='000000000000E+00'; // Initialisieren

FOR i := 1 to 12 DO // Werte eintragen
tmp := REPLACE(IN1:=tmp,IN2:=RCV_ARRAY,L:=1,P:=i);
END_FOR

Sollte so gehen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich brauche auch die Genauigkeit, mit der die Daten übermittelt werden, also wäre STRING_R eh keine Option für mich.

Danke für die Antwort! Aber leider hast du meinen Beitrag nicht komplett gelesen ;) Ich werde wohl auf zwei DINT statt nen REAL ausweichen müssen...
Denn ich denke nicht das ich mit einem REAL die Werte die ich bekomme so genau abbilden kann.

Grüße

Marcel
 
Danke für die Antwort! Aber leider hast du meinen Beitrag nicht komplett gelesen ;) Ich werde wohl auf zwei DINT statt nen REAL ausweichen müssen...
Denn ich denke nicht das ich mit einem REAL die Werte die ich bekomme so genau abbilden kann.

Grüße

Marcel

Das kannst du in der Tat nicht, denn die Real in der S7 kann nur 7 Ziffern enthalten, dazwischen noch ein Komma und dazu der zugehörige Exponent.
 
Zuletzt bearbeitet:
RCV_ARRAY[0] = VORZEICHEN
RCV_ARRAY[1] = 1
RCV_ARRAY[2] = 2
RCV_ARRAY[3] = 3
RCV_ARRAY[4] = 4
RCV_ARRAY[5] = 5
RCV_ARRAY[6] = 6
RCV_ARRAY[7] = .
RCV_ARRAY[8] = 1
RCV_ARRAY[9] = 2
RCV_ARRAY[10] = 3
RCV_ARRAY[11] = 4
RCV_ARRAY[12] = 5
RCV_ARRAY[12] = 6
Diese Real-Format ist sehr Speziell !
Wenn es um eine skalierte Signal handelt, kannst du eventuell den unskalierte Signal bekommen, und zwar als INT oder DINT, und dann selber den benötigte skalierung machen ?
Es wird einfacher, und du verlierst kein genauigkeit wegen rundungen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich hatte gehofft es in einen Real-Wert stopfen zu können. Geht aber nicht ;)

Meine VERMUTUNG ist, dass die Gegenseite sich zweier DINT bedient, und genau das werde ich wohl auch machen (müssen :( )

Grüße

Marcel
 
Hallo,
zu dem Thema hatte ich mir mal etwas in SCL gebaut (aus dem gleichen Grund).
Vielleicht hilft es ja :
Code:
FUNCTION FC437 : VOID                       // UP String nach REAL umwandeln
Title   = 'UP String nach REAL umwandeln'   // UP String nach REAL umwandeln
AUTHOR  : 'Larry Laffer'
VERSION : '1.0'   //  15.07.2011
//     Bausteinparameter
VAR_INPUT
   Real_String : string ;  // umzuwandelnder Eingangs-String
END_VAR

VAR_IN_OUT
END_VAR

VAR_OUTPUT
   Wert        : REAL ;    // umgewandelter Wert
END_VAR

VAR_TEMP
   i : INT ; 
    
   is_VZ_Basis : BOOL ;    // false = VZ positiv , true = VZ negativ
   is_VZ_Exp   : BOOL ;    // false = VZ positiv , true = VZ negativ
   is_Basis    : BOOL ;    // true = Bearbeitung der Basis , false = Bearbeitung vom Exponent
   is_Vorkomma : BOOL ;    // true = Bearbeitung der Vorkommastellen , false = Bearbeitung der Nachkommastellen
   is_Zahl     : BOOL ;    // true = akt. Zeichen ist eine Zahl
    
   Wert_Basis  : REAL ;
   Wert_Exp    : REAL ;
   Faktor_Nachkomma : REAL ;
   akt_Zahl    : REAL ;
   
   myString : STRING ;
   a_myString AT myString : STRUCT 
          Total  : BYTE ;
          Length : BYTE ;
          Chars  : ARRAY [1..254] OF BYTE ;
   END_STRUCT ;
   myStringLen : INT ;
   
END_VAR

//     Anweisungsteil
BEGIN
is_VZ_Basis := false ;    // false = VZ positiv , true = VZ negativ
is_VZ_Exp   := false ;    // false = VZ positiv , true = VZ negativ
is_Basis    := true ;     // true = Bearbeitung der Basis , false = Bearbeitung vom Exponent
is_Vorkomma := true ;     // true = Bearbeitung der Vorkommastellen , false = Bearbeitung der Nachkommastellen
     
Wert_Basis := 0.0 ;
Wert_Exp   := 0.0 ;
Faktor_Nachkomma := 0.1 ;
myString    := Real_String ;
myStringLen := BYTE_TO_INT(a_myString.Length) ;
FOR i := 1 TO myStringLen BY 1 DO
   IF (a_myString.Chars[i] = CHAR_TO_BYTE('.')) THEN is_Vorkomma := false ; END_IF ;
   IF (a_myString.Chars[i] = CHAR_TO_BYTE(',')) THEN is_Vorkomma := false ; END_IF ;
   IF (a_myString.Chars[i] = CHAR_TO_BYTE('e')) THEN is_Basis := false ; END_IF ;
   IF (a_myString.Chars[i] = CHAR_TO_BYTE('E')) THEN is_Basis := false ; END_IF ;
   
   IF (a_myString.Chars[i] = CHAR_TO_BYTE('-')) THEN
      IF is_Basis THEN is_VZ_Basis := true ; ELSE is_VZ_EXP := true ; END_IF ; 
   END_IF ;
   
   akt_Zahl := INT_TO_REAL(BYTE_TO_INT(a_myString.Chars[i])-48) ;
   is_Zahl := (akt_Zahl >= 0) AND (akt_Zahl <= 9) ;
   
   IF is_Zahl THEN
      IF is_Basis  THEN
         IF is_Vorkomma THEN
            Wert_Basis := (Wert_Basis * 10.0) + akt_Zahl ;
         ELSE
            Wert_Basis := (akt_Zahl * Faktor_Nachkomma) + Wert_Basis ;
            Faktor_Nachkomma := Faktor_Nachkomma * 0.1 ;
         END_IF ;      
      ELSE
         Wert_Exp := (Wert_Exp * 10.0) + akt_Zahl ;
      END_IF ;    
   END_IF ;  
END_FOR ;    
IF is_VZ_Basis THEN Wert_Basis := Wert_Basis * -1.0 ; END_IF ;
IF is_VZ_Exp THEN Wert_Exp := Wert_Exp * -1.0 ; END_IF ;
   
Wert := Wert_Basis * 10**Wert_Exp ;  
   
END_FUNCTION
... das lösst allerdings nicht das Problem mit dem Double ... :(

Gruß
Larry
 
Trotzdem ein guter Ansatz.

ich habe nun die Variable in zwei Teile zerlegt. Vor dem Komma ein DINT, und danach auch einer.
Das ist für meine Zwecke mehr als ausreichend, und funktioniert tadellos!

Grüße

Marcel
 
Zurück
Oben