Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Aus Gleitkommazahl einzelne Bytes erhalten
daywalker0086 - Mo 12.08.13 16:46
Titel: Aus Gleitkommazahl einzelne Bytes erhalten
Hallo Leute,
ich habe eine Gleitkommazahl z.Bsp. m:=116.0 (Wertebereich 4byte).
Diese soll über die serielle Schnittstelle übertragen werden. Dazu muss ich in diesem Fall den Wert 0x42e80000 übertragen wie hier auch durch umrechnen der Zahl 116.0 als Ergebnis
http://gregstoll.dyndns.org/~gregstoll/floattohex/.
Die frage ist nun wie ich an die Werte komme also ich gehe davon aus das im Speicher der Variable m genau di eZeichenfolge steht, nur wie komme ich daran?
Grüße Christian
IhopeonlyReader - Mo 12.08.13 16:52
ich speicher steht das sicher nicht :D
dort stehen die einzelnen Bits...
falls du bit für bit lesen willst, kannst du folgendes machen
(cardinal ist z.B. 4 Byte groß)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| var X: Cardinal; C: Byte; begin For C:=(8*4)-1 downto 0 do begin if Boolean( X and (1 shl C)) then else end; |
daywalker0086 - Mo 12.08.13 17:00
Ich will ja nicht unbedingt bit für bit haben.
Ich habe eine Gleitkommazahl vom typ real, und muss diese Zahl per serielle Schnittstelle übertragen. Der Senderoutine kann ich aber nur einzelne Bytes übergeben. Das heißt Wenn ich eine Real Zahl habe, welche 4 byte groß ist, wie kann ich dann die einzelnen 4 bytes an die serielle Schnittstelle übergeben?
jfheins - Mo 12.08.13 17:04
Aber sicher steht das im Speicher ;-)
Kann deine Senderoutine auch Pointer+Länge? Oder nur Bytearrays?
Besonders einfach ginge es, indem du ein ByteArray mit absolute auf den gleichen Speicher zeigen lässt, wie deine Single-Variable.
Real ist übrigens obsolet. Benutze double oder single stattdessen - in diesem Fall single, da du ja genau vier Bytes haben möchtest.
IhopeonlyReader - Mo 12.08.13 17:08
achso :D
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| var X: Cardinal; B: Array[1..4] of Byte; begin X := $FFFFFFF0; B[1] := X shr (8*3); B[2] := X shr (8*2); B[3] := X shr (8*1); B[4] := Byte(X and 255); end; |
B[1] enthält die ersten 8 Bit, B[2] die n ächsten 8...
jaenicke - Mo 12.08.13 17:13
daywalker0086 hat folgendes geschrieben : |
Die frage ist nun wie ich an die Werte komme also ich gehe davon aus das im Speicher der Variable m genau di eZeichenfolge steht, nur wie komme ich daran? |
Die Hexadezimaldarstellung interessiert den seriellen Port wenig. Dort musst du die Bytes hinschicken. Die Hexadezimaldarstellung bekommst du z.B. so:
Delphi-Quelltext
1: 2: 3: 4: 5:
| var a: Single; begin a := 116.0; ShowMessage(IntToHex(PInteger(@a)^, 8)); |
Je nachdem welche Komponente du für den Zugriff auf den seriellen Port benutzt, ist das etwas unterschiedlich, aber normalerweise gibt es dort eine Funktion Write oder so ähnlich zum Schreiben, der du einen Pointer und die Datengröße übergeben kannst. Den Pointer auf die Daten bekommst du mit dem @.
daywalker0086 - Mo 12.08.13 17:34
Also mal eine Rückmeldung
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| var X: Cardinal; C: Byte; begin For C:=(8*4)-1 downto 0 do begin if Boolean( X and (1 shl C)) then else end; |
funktioniert nicht da X hier cardinal ist, ich aber ein real Wert habe.
Delphi-Quelltext
1: 2: 3: 4: 5:
| var a: Single; begin a := 116.0; ShowMessage(IntToHex(PInteger(@a)^, 8)); |
Da steht bei mir im Dialog nur 00000000.
EDIT: Ok zeigt das richtige an, hatte a noch als real deklariert.
Also bis jetzt noch keine Lösung.
Hier mal meine Senderoutine damit ihr seht wie ich Daten über die serielle verschicke:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| daten[0]:=$06; daten[1]:=$10; daten[2]:=$06; daten[3]:=wr_anzahl; daten[4]:=(sw1); daten[5]:=maske_berechnen(1); for i:=0 to 5 do begin prog_finish := 0; sendstr:=sendstr+inttohex(daten[i],2); end; serialp1.SendString(hextostr(sendstr)); |
Die Komponente ist SerialNG von DomIS.
http://www.domis.de/cms/index.php?module=ContentExpress&func=display&bid=24&btitle=Content_Menu&mid=3&ceid=7
daywalker0086 - Mo 12.08.13 17:48
So hab es jetzt so gelöst:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure TForm1.Button5Click(Sender: TObject); var a: Single; wert:string; wert_byte: array[1..4] of string; begin a := 116.5; wert:= IntToHex(PInteger(@a)^, 2); wert_byte[1]:= copy(wert,0,2); showmessage(wert_byte[1]); wert_byte[2]:=copy(wert,3,2); showmessage(wert_byte[2]); wert_byte[3]:= copy(wert,5,2); showmessage(wert_byte[3]); wert_byte[4]:= copy(wert,7,2); showmessage(wert_byte[4]);
end; |
Jetzt hab ich im Array wert_byte jedes einzelne Byte drin und kann es so über die serielle Schnittstelle ausgeben.
Jetzt die Frage: gehts noch eleganter/einfacher?
MeierZwoo - Mo 12.08.13 18:10
Mich würde grade bei Gleitkommatypen als erstes interessieren, ob die Gegenseite mit den Bytes überhaupt etwas anfangen kann. Auf der Empfängerseite kann ja ein ganz anderes Programm, durch einen völlig anderen Compiler oder auch nur einer anderen Compiler-Version erstellt die Bytes lesen und sich wundern, was das soll.
Denn die Gegenseite muß ja den exakt selben Datentyp verwenden, um die Bytes dann wieder in der richtigen Form in den Speicher zu schreiben ... und zu interpretieren. Und da kann schon ein Versionswechsel, oder eine andere Plattform (32bit, 64bit) alles zunichte machen.
Deshalb ist bei DFÜ der Normalfall, die Werte in Strings umzuwandeln und so zu senden ... es sei denn, es handelt sich auf exakt aufeinander abgestimmte Hardware mit abgestimmter Firm- und Software, wie z.B. im Meß- und Regelwesen.
IhopeonlyReader - Mo 12.08.13 18:41
daywalker0086 hat folgendes geschrieben : |
Also mal eine Rückmeldung
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| var X: Cardinal; C: Byte; begin For C:=(8*4)-1 downto 0 do begin if Boolean( X and (1 shl C)) then else end; |
funktioniert nicht da X hier cardinal ist, ich aber ein real Wert habe.
|
dein ernst? dann mach halt
X als real und anstatt in der schleife 8*4 schreibste 8*8.. (real ist doch 8 Byte groß oder?)
IhopeonlyReader - Mo 12.08.13 18:46
mal alles auf real umgeschrieben
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| var X: Real; B: Array[1..8] of Byte; C: Byte; HilfX: Real; begin For C := 7 downto 0 do B[8-C] := X shr (8*C) end;
X := 0; For C:=7 downto 0 do begin HilfX := B[C]; HilfsX := HilfsX shl (8*C); X := X or HilfsX; end; |
Moderiert von
Martok: Code- durch Delphi-Tags ersetzt
jaenicke - Mo 12.08.13 20:43
Warum um alles in der Welt friemelst du da mit Strings herum, wenn du gar keinen String schicken willst? Die genannte Komponente hat den Befehl SendData...
Delphi-Quelltext
1: 2: 3: 4:
| var a: Single;
serialp1.SendData(@a, SizeOf(a)); |
Und um die Bytes alle zu schicken könntest du ein array of Byte benutzen.
mandras - Mo 12.08.13 21:31
jaenickes Methode ist die kürzeste,
verständlicher ist vielleicht folgendes wenn man doch auf einzelne Bytes zugreifen muß:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm1.Button1Click(Sender: TObject); var a:single; b:array[0..3] of byte absolute a; begin a:=116; end; |
jasocul - Di 13.08.13 08:18
Und wer noch weiß, was ein Record ist, kann es auch über einen varianten Record machen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| var a : record case Boolean of True : (s : Single); False : (b : Array[0..3] of Byte); end; ... a.s := 116.5; |
Dann steht in a.b Byte-Darstellung.
Aber ich würde auch die Variante von Jaenicke nehmen. :wink:
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!