# Realzahl umwandeln



## maccap (30 Mai 2007)

Hallo,
programmiere eine Visulaisierung auf einem PDA mit VB .NET.
Benutze zur Kommunikation mit der SPS den IBHLINK samt IBHNET Type Library.
Nun brauche ich eine Umrechnung vom Double-Format von VB .NET ins IEEE-Realformat, was Siemens benutzt.
Von Siemens nach VB.NET habe ich schon:
Private Function ConvertS7(ByVal Daten As Long) As Double
Dim Exp, Mant, Count As Integer 'von S7 ausgelesene Daten -> 4Byte aufaddiert zu IntZahl
Dim MantReal, pruefen, Datenreal As Double 'Umgewandelte Daten
Count = 1
MantReal = 0
Exp = ((Daten << 1) >> 24) - 127
Mant = (Daten << 9) >> 9
Do While Count < 23
pruefen = Mant And (1 << (23 - Count))
If pruefen > 0 Then
MantReal = MantReal + 2 ^ (-Count)
End If
Count = Count + 1
Loop
If ((Exp = -127) And (Mant = 0)) Then
MantReal = 0
Else
MantReal = MantReal + 1
End If
Datenreal = MantReal * 2 ^ Exp
ConvertS7 = Datenreal
End Function

Wie kriege ich das andersrum hin? Habe ja zwei unbekannte, muss also eine vorgeben. Was ist da sinvoll?

Gruß maccap


----------



## Zottel (30 Mai 2007)

maccap schrieb:


> Hallo,
> programmiere eine Visulaisierung auf einem PDA mit VB .NET.
> Benutze zur Kommunikation mit der SPS den IBHLINK samt IBHNET Type Library.
> Nun brauche ich eine Umrechnung vom Double-Format von VB .NET ins IEEE-Realformat, was Siemens benutzt.
> ...


Ich glaube, du machst es dir unnötig kompliziert: 
1. Benutze ein 32-bit floating point format. Ich kenne VB nicht gut, aber auf http://www.vb-seminar.de/vb_26.htm
heißt der Datentyp single. Das ist schon dasselbe Format, wie es die S7 benutzt, nur sind die Bytes andersherum angeordnet.
2. Bau dir etwas, so daß eine 32-Bit-Integer-Variable, ein Array von 4 Bytes und eine Single-Variable denselben Speicher benutzen.
3. Lies das 32-Bit-Integer aus der S7 ein.
4. Vertausche dieBytes im Array:
x=ba[4]
ba[4]=ba[1]
ba[1]=x
x=ba[3]
ba[3]=ba[2]
ba[2]=x
5. Nun enthält die Single-Variable dein Ergebnis.


----------



## Zottel (30 Mai 2007)

Punkt 2 scheint in VB ein echtes Problem zu sein. Auf
http://www.developer.com/net/vb/article.php/3602621
findet sich aber eine Lösung.
Die Beispieldefinition für deinen Bedarf angepasst:

```
<StructLayout(LayoutKind.Explicit)> _
Public Structure Union
    <FieldOffset(0)> _
    Public i As Integer
    <FieldOffset(0)> _
    Public b As Array[1..4]of Byte
    <FieldOffset(0)> _
    Public s As Single
End Structure

Dim u As Union
Dim x As Byte
Dim ergebnis As Single
u.i = Ein32BitWortVonDerS7

x=u.ba[4]
u.ba[4]=u.ba[1]
u.ba[1]=x
x=u.ba[3]
u.ba[3]=u.ba[2]
u.ba[2]=x

Ergebnis=u.s
```


----------



## maccap (31 Mai 2007)

Hallo Zottel,

vielen Dank für Deine Tipps. Habe jetzt den ganzen morgen mit der Srcture und bits und bytes verschieben herum probiert. 
Komischerweise läuft auch diese Version, was ich allerdings nicht verstehe:

Imports System.Runtime.InteropServices
Class union
<StructLayout(LayoutKind.Explicit)> Public Structure Union
<FieldOffset(0)> Public i As Integer
<FieldOffset(0)> Public s As Single
End Structure
 
Function Main() As Integer
Dim u As Union
Dim t As Byte
Dim u2 As New Union
Dim x As Boolean
Dim ergebnis As Integer
u.s = 827.9654 'zuwandelnde Realzahl für S7
Return u.i
End Function
End Class

Gruß, maccap


----------



## Zottel (31 Mai 2007)

Mmmh, was meinst du mit "läuft"? Wenn ich es richtig sehe, gibt diese  Version das Bitmuster der Single-Variable als Integer wieder, OHNE Bytes zu tauschen. Wenn du das in die S7 schreibst und zurück liest, iost natürlich alles in Ordnung, aber wenn du mit Step7 die SPS-Variable beobachtest, was siehst du dann? 
Was bekommst du wenn du mit der Umkehrfunktion (S7-Real einlesen, in u.i packen, u.s lesen) eine "vernünftigen" Gleitkommawert liest?


----------



## Zottel (31 Mai 2007)

Sorry, hatte nicht gelesen, daß du für einen PDA programmierst. Was hat der für eine CPU? Die Byte-Anordnung der S7 heißt "big endian", die der Intel-PCs "little endian". Da MUSS getauscht werden. Aber deine PDA-CPU könnte ja big endian nutzen...


----------



## maccap (31 Mai 2007)

Läuft sowohl auf dem PDA als auch auf meinem Windows-Rechner als Applikation.
Die Werte werden natürlich richtig in die S7 geschrieben und auch aus Ihr gelesen. Habe jetzt meine alte nicht so performante Version, die ich gestern gepostet habe auch ersetzt:

Function ConvertS7Real(ByVal daten As Integer) As Single
Dim u As Union
u.i = daten
Return u.s
End Function


----------



## Papschtler (12 November 2007)

*Auch für C#*

Hallo,
hat von euch zufällig jemand sowas für C#? Ich frag erst mal bevor ich das Rad neu erfinde....
gruß
Stefan


----------



## david.ka (13 November 2007)

Hallo,
das sollte funktionieren:


```
private static float OPCStringToFloat(string value)
      {
                int i=Convert.ToInt32(value,2);
                IntPtr ptr=Marshal.AllocHGlobal(4);
                Marshal.StructureToPtr(i,ptr,true);
                float f=(float)Marshal.PtrToStructure(ptr,typeof(float));
                Marshal.FreeHGlobal(ptr);
                return f;
      
        }
```

mfg.David.


----------



## harrylask (13 November 2007)

Hallo Papschtler,
ungetestet


```
public static float Convert(int Value)
    {
      return BitConverter.ToSingle(BitConverter.GetBytes(Value), 0);
    }
```

Grüsse, harrylask


----------



## Papschtler (13 November 2007)

Alles klar. Danke. Ich werds ausprobieren.
mfg
Stefan


----------

