# WINCC Real zurück in Rohdaten



## K-SYSTEM-D (21 Februar 2011)

Hallo Zusammen brauch mal wieder eure unterstütung,

versuch schon seit längerem eine Real Variable über Rohdaten in VBS zur S7 zu schicken.

Hab hier auch im Forum was gefunden nur wird hier zwischen 1und-1 nicht angenommen.

Habt ihr was auf lager wo ich in VBS ne Real für Rohdaten zerstückeln kann?

Ich wäre euch sehr dankbar.

MFG

Daniel


----------



## Larry Laffer (22 Februar 2011)

Hallo,
leider habe ich nicht verstanden, wo es hängt ... Erklär doch mal an einem Beispiel, was du hast und was daraus werden soll ...

Gruß
Larry


----------



## Thomas_v2.1 (23 Februar 2011)

In C könnte ich dir ein Beispiel geben, vielleicht kannst du das ja in VBS umschreiben.
Vom Prinzip her musst du nur die Bytereihenfolge der 4 Bytes in der WinCC float-Variable (oder wie der 4-Byte Typ in VBS dann heißt) einmal komplett umdrehen, und dieses 4 Bytes in deine Rohdatenvariable schreiben.


----------



## K-SYSTEM-D (24 Februar 2011)

*Beispiel*

Danke erstmal.

Hier ist der Code den ich hier gefunden habe (etwas abgeändert)

dieser Code läuft in einer Action mit FOR NEXT Schleife als Function.


wenn ich in zahlen zwischen -1.0 und 1.0 liege dann schickt er diese nicht.
da ich nicht der meister in VBS bin bitte ich um eure unterstützung.



```
Function Real2Bytes (Rohdata, Name, n, Wert )
  
    Dim arrSend, strSend
    Dim i, j, k, Anz, Prefix
    Dim sign :    sign = 0                ' Vorzeichen 
    Dim Exp :    Exp = 127                ' Offset für Single entspr. IEEE 754
    Dim dblFract :    dblFract = 1
    Dim arrResult :    arrResult = Array (0,0,0,0)
    Dim invar
    
    ' konstanten vorbesetzen
    Anz = n-2                    'Position von Variable
    Prefix = Name        'Prefix für die Variabelen aus denen gelesen wird
    strSend = Rohdata    'Name der Rohdatenvariable
    
    ' Bytearray via Rohdatenvariable synchron lesen
    arrSend = HMIRuntime.Tags(strSend).Read (1)
    
    ' Variabelen in Rohdaten kopieren
    'For k = 0 To (Anz - 1)
        
        ' Initialisierungswerte vorbelegen
        sign = 0
        Exp = 127
        dblFract = 1
        arrResult = Array (0,0,0,0)
        
        ' Variabele einlesen   
       invar = Wert'+0.0000001'HMIRuntime.Tags(prefix & k).Read (1)   '123.5
      '  invar = Wert'-0.0000001
        
        '==============================================================================
        ' IEEE 754 Single (Float32) in ein Byte-Array entspr. der internen
        ' PLC-Darstellung wandeln.
        ' BEACHTE! Denormalisierte Zahlen werden (noch) nicht unterstützt.
        '==============================================================================
    
        If invar <> 0 Then
        
            If invar < 0 Then    invar = invar * -1 :    sign = 1
        
            ' Normalisieren
            Do While invar >= 2 :    invar = invar / 2 :    Exp = Exp + 1 :    Loop
            Do While invar < 1 :    invar = invar * 2 :    Exp = Exp -1 :    Loop
        
            If (Exp And 1) = 0 Then invar = invar - 1
            arrResult(0) = sign * 128 + Exp \ 2
            
            For i=1 To 3
                For j=7 To 0 Step -1
                    If invar > dblFract Then
                        arrResult(i) = arrResult(i) + 2^j
                        invar = invar - dblFract
                    End If
                    dblFract = dblFract/2
                Next
            Next
        
      '  End If
            
        ' Temporäres Array an Rohdaten übergeben 
        For i = 0 To 3
            arrSend((Anz * 4) + i) = arrResult(i)
            'HMIRuntime.Trace "Wert_" & ((k * 4) + i) &" : " & arrResult(i) & vbCrLf
        Next
 '   Next
    ' Bytearray via Rohdatenvariable asynchron (direkt) schreiben
    HMIRuntime.Tags(strSend).Write arrSend

End Function
```


----------



## winnman (24 Februar 2011)

was willst du damit machen?

Warum VBS? . . .

Beschreib mal dein Problem ganauer, vielleicht lässt sich das viel einfacher lösen ohne VBS, . . .


----------



## Thomas_v2.1 (24 Februar 2011)

Ich kenne mich mit dem VBS nun nicht aus, kann mir aber eigentlich nicht vorstellen dass dein Codebeispiel von oben die einzige Möglichkeit ist sowas umzusetzen. Die Binärdarstellung einer 32-Bit Gleitkommazahl ist zum Glück auf PC und SPS (S7) Seite identisch, sodass man eigentlich nicht bis auf Bitebene heruntermuss.

In C könnte eine Funktion so aussehen

```
void FloatToRaw(float flt, unsigned char *d)
{
  union 
  {
    float val;
    unsigned char b[4];
  } f; 
  f.val = flt;

  d[0] = f.b[3];
  d[1] = f.b[2];
  d[2] = f.b[1];
  d[3] = f.b[0];
}
```

Aufrufen und in die SPS schreiben mit:

```
unsigned char data[4];
float val = 123.4;

FloatToRaw(val, &data[0]);

SetTagRaw("RAW_VARIABLE", &data[0] , 4);
```

Ein Äquivalent zur Union in C scheint nach erster Google-Suche in VBS nicht zu geben, Pointer auch nicht, hm.


----------



## Larry Laffer (25 Februar 2011)

da es ja anscheinend für den TE sehr schwer ist ... dennoch noch einmal





Larry Laffer schrieb:


> Erklär doch mal an einem Beispiel, was du hast und was daraus werden soll ...


----------



## Ralle (25 Februar 2011)

Larry Laffer schrieb:


> da es ja anscheinend für den TE sehr schwer ist ... dennoch noch einmal



Das kann ich dir sagen 

Er hat eine Real und will diese in ihre 4 Bytes zerlegen. Diese Bytes werden dann, zusammen mit einigen anderen, in eine Rohdatenvariable einsortiert. Damit kann man so einige Tags sparen. Wir haben das mal gemacht, aber  ein Kollege hat dafür extra in Delphi ein ActiveX für WinCC geschrieben, denn VBS ist nun mal nicht allzu mächtig, was solche Dinge angeht.

Den umgekehrten Weg bin ich schon gegangen, das hatte ich auch erst sehr kompliziert, bis Zottel mir mal einen Code mit dem Move-Befehl gepostet hat, des war dann sehr einfach. Aber diesen Move kann VBS wohl nicht.

http://www.sps-forum.de/showpost.php?p=19431&postcount=17

Hier auch noch eine Anregung, falls VBS ähnliches kann:


```
//TypeCast
type int_short_union=record
case integer of
  1:(I32:Integer);
  2:(I16:array[0..1] of word);
  3:(I8:array[0..3] of byte);
end;
 
Daten: int_short_union;
 
Daten.I8[0] := DBDat.SPSBuf[SPS, L+3];
Daten.I8[1] := DBDat.SPSBuf[SPS, L+2];
Daten.I8[2] := DBDat.SPSBuf[SPS, L+1];
Daten.I8[3] := DBDat.SPSBuf[SPS, L];
 
Daten_Real := S7_Float(Daten.I32);
```


----------



## Larry Laffer (25 Februar 2011)

Hi Ralle,
schön, dass du den Part des TE hier übernommen hast ... 

Etwas, dass dem AT von SCL entspricht gibt es m.W. in der VB-Syntax nicht. da wäre das Code-Beispiel des TE, dass quasi per ausprobieren die Variable ausdröselt schon der Weg - das ist dann aber für "viele" Variablen sicherlich ganz schön rechenintensiv.

Die Frage, die sich mir hier stellt, ist : Warum muss es denn ein Array_of_Byte sein, das als ein Tag übertragen wird ? Kann es nicht genauso ein Array_of_Real sein ? Ich kenne dafür allerdings von WinCC zu wenig ... 

Gruß
Larry


----------



## Ralle (25 Februar 2011)

Larry Laffer schrieb:


> Hi Ralle,
> schön, dass du den Part des TE hier übernommen hast ...



Dann mach ich mal weiter 




Larry Laffer schrieb:


> Die Frage, die sich mir hier stellt, ist : Warum muss es denn ein Array_of_Byte sein, das als ein Tag übertragen wird ? Kann es nicht genauso ein Array_of_Real sein ? Ich kenne dafür allerdings von WinCC zu wenig ...
> 
> Gruß
> Larry



Geht leider nicht, zumindest in WinCC6.2, welches ich ein klein wenig kenne.
Einzige Möglichkeit, wirklich Tags zu sparen sind die Rohdaten. Das haben wir mit unserem ActiveX kräftig gemacht. Wir haben die Variablen als Rohdaten aus einem DB gelesen und dann in einem VB-Script via ActiveX aufgedröselt. damit war das auch nicht allzu zeitkritisch. Den umgekehrten Weg sind wir dann auch gegangen. Getriggert wurde das Ganze über Wertänderungen der entsprechenden Variablen, wenn ich recht erinnere, ist schon wieder 3 Jahre her.


----------



## Thomas_v2.1 (25 Februar 2011)

Es gibt durchaus Anwendungen bei der das Handling durch die Verwendung von Rohdatenvariablen wesentlich einfacher wird.

Ich hatte mal eine Anwendung bei der ein Messwert in der SPS ca. alle 100ms mit Zeitstempel in einen DB geschrieben wurde. War die Messung fertig, hat die SPS dieses an WinCC gemeldet, und in eine Header eingetragen wie viele Einträge das Archiv hat. In WinCC habe ich dann 10 Rohdatenblöcke mit max. Größe angelegt. In einem getriggerten Skript hat dann WinCC die entsprechende Anzahl Rohdatenblöcke gelesen, die Bytes in Zeitstempel und Real-Wert aufgedröselt und das Ganze als CSV-Datei gespeichert.

Der Vorteil ist hier dass die große Datenmenge nur einmal bei Bedarf gelesen wird. Zeitstempel kann WinCC aber eh nicht verarbeiten, darum wäre es ganz ohne Skript nicht gegangen.
Zur Rechenzeit:
Bei meinem C-Skript wird garnicht gerechnet, sondern es wird ein Speicherbereich einfach anders interpretiert. Und gegenüber der Zeit die das Lesen des Rohdatenblockes benötigt ist diese Zeit vernachlässigbar.


----------



## Larry Laffer (25 Februar 2011)

@Thomas:
Ich meinte auch nicht dein Beispiel - ich habe da (auch als Nicht-C-Programmierer) schon gesehen, dass du da eine Art AT-Sicht erzeugt hast. Ich meinte das VB-Beispiel des TE ...

Gruß
Larry


----------



## K-SYSTEM-D (27 Februar 2011)

Hallo Leute,

tut mir leid das ich mich jetzt erst wieder melde aber hatte gerade viel um die ohren.

Also sinn und zweck ist es 10 Realwerte bei änderung zurück in die 
SPS zu schreiben.

1. Ich bereite die Rohdatenbytes auf und übergib diese der Internen Variable.
2. hat sich die Interne Variable im letzten zyklus geändert schreib ich diese   zurück in die SPS.

Bei Word/ DWord funktioniert das einwandfrei, nur eben beim Real geht das nicht.

Liegt das eventuell daran das ich in einer Aktion die Variablen aufbereite und falls sich was in der Internen variable geändert hat zurückschreibe?

Ich kann leider hier kein komplettes Script posten.( Firma und so )

Ich danke euch im voraus.


----------



## Larry Laffer (28 Februar 2011)

K-SYSTEM-D schrieb:


> Bei Word/ DWord funktioniert das einwandfrei, nur eben beim Real geht das nicht.
> 
> Liegt das eventuell daran das ich in einer Aktion die Variablen aufbereite und falls sich was in der Internen variable geändert hat zurückschreibe?


 
Deine Frage beantwortet sich, wenn du dir den Aufbau einer REAL einmal ansiehst (Bit-Plazierung und Wertung von Exponent und Mantisse). Vielleicht siehst du dir das einmal an.
Du kannst eine REAL nur byteweise auflösen wenn du dir eine "andere Sicht" darauf erstellst. Das wäre dann der Vorschlag von Thomas oder die von Ralle angedeutete Vorgehensweise ... oder du umgehst hier die Reals irgendwie - vielleicht kannst du ja auch das Gleiche mit einem DINT und einer festen Skalierung erreichen ...

Gruß
Larry


----------



## K-SYSTEM-D (28 Februar 2011)

Danke für deine Antwort.

also grundsätzlich könnte ich DINT schon hernehmen.

da aber meine ganzen Bausteine in Real geschrieben sind, wollte ich logischerweise auch Real benutzen.

egal, werd dann mal mit DINT probieren.

Ich danke euch für eure hilfe.

Eine Frage hätte ich noch und zwar passt das nicht in dieses Thema, aber egal.

Ich kann in der Runtime Benutzer anlegen, das funktioniert schon!
Aber kann mir jemand ein Beispiel posten wo ich auch Benutzer löschen kann!?


----------



## Thomas_v2.1 (28 Februar 2011)

K-SYSTEM-D schrieb:


> also grundsätzlich könnte ich DINT schon hernehmen.
> 
> da aber meine ganzen Bausteine in Real geschrieben sind, wollte ich logischerweise auch Real benutzen.
> 
> egal, werd dann mal mit DINT probieren.


Und du bist dir sicher dass die Bytereihenfolge eines DINT in der SPS und im PC identisch ist? Ich meine nämlich bei Rohdaten musst du die immer drehen.


----------



## K-SYSTEM-D (1 März 2011)

Hallo zusammen, also meine lage hat sich erheblih gebessert.

nun ein anderes problem aber ich finds trotzdem nicht.

ne Real von 8.125733 ist in der SPS

byte 0 = 65
byte 1 = 2
byte 2 = 3
byte 4 = 1

aber in diesem code kommt was anderes raus und zwar

byte 0 = 65
byte 1 = 2
byte 2 = 3
byte 4 = 0      //und hier liegt nun mein Problem 

hier der Code von der Function


```
Function Real2Bytes (Realwert) 
Dim arrSend, strSend
Dim i, j, k, Anz, Prefix
Dim sign :    sign = 0                ' Vorzeichen 
Dim Exp :    Exp = 127                ' Offset für Single entspr. IEEE 754
Dim dblFract :    dblFract = 1
Dim arrResult :    arrResult = Array (0,0,0,0)
Dim invar
Dim V
'==============================================================================
' IEEE 754 Single (Float32) in ein Byte-Array entspr. der internen
' PLC-Darstellung wandeln.
' BEACHTE! Denormalisierte Zahlen werden (noch) nicht unterstützt.
'==============================================================================
            
' Initialisierungswerte vorbelegen
sign = 0
Exp = 127
dblFract = 1
arrResult = Array (0,0,0,0)
        
invar = Realwert
        
If invar < 0 Then    invar = invar * -1 :    sign = 1
        
' Normalisieren
Do While invar >= 2 :    invar = invar / 2 :    Exp = Exp + 1 :    Loop
Do While invar < 1 :    invar = invar * 2 :    Exp = Exp -1 :    Loop
        
    If (Exp And 1) = 0 Then invar = invar - 1
    arrResult(0) = sign * 128 + Exp \ 2
            
            For i=1 To 3
                For j=7 To 0 Step -1
                    If invar > dblFract Then
                        arrResult(i) = arrResult(i) + 2^j
                        invar = invar - dblFract
                    End If
                    dblFract = dblFract/2
                Next
            Next
        
      '  End If
            
        ' Temporäres Array übergeben
        
 Real2Bytes = Array(arrResult(0), arrResult(1), arrResult(2), arrResult(3))
End Function
```
 
und hier die aktion mit der ichs probiert hab 


```
Function action
Dim TestReal
Dim Byte_wert
Dim bytes
Dim byte1
Dim byte2
Dim byte3
Dim byte4
Dim k
k = 0
TestReal = 8.125733
bytes = Real2Bytes(TestReal)
MsgBox bytes(0)
MsgBox bytes(1)
MsgBox bytes(2)
MsgBox bytes(3)
End Function
```
 
Ich wäre euch echt dankbar wenn ihr mir nochmal helfen könntet.

Ich danke euch im voraus


----------



## K-SYSTEM-D (1 März 2011)

also ich hab jetzt festgestellt hat im Byte(3)
entweder um 1 zu viel oder 1 zu wenig rin steht aber ich komme nicht drauf warum!

jemand eine Idee?


----------

