Realzahl umwandeln

maccap

Level-1
Beiträge
96
Reaktionspunkte
2
Zuviel Werbung?
-> Hier kostenlos registrieren
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
 
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
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.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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:
Code:
<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
 
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
 
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?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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...
 
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


 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
das sollte funktionieren:

Code:
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.
 
Hallo Papschtler,
ungetestet

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

Grüsse, harrylask
 
Zurück
Oben