Forum: Mikrocontroller und Digitale Elektronik Float über RS232 ausgeben


von Martin (Gast)


Lesenswert?

Ich besitze einen neuen XMEGA128A3.

Nun habe ich eine Sinustabelle auf dem µC berechnet. Diese möchte ich 
zur Kontrolle einfach mal über RS232 an den PC senden. Der Zahlentype 
float ist ja ein 32Bit Wert. Nun habe ich gedacht das ich einfach 4x 8 
Bit nacheinander an den PC sende und diese 32 Bit am PC wieder zu einem 
float zusammensetze. Jedoch fangen da die Probleme an.

Ich benutze den Codeviosion Compiler für µC. Diese zeigt mir einen Error 
an wenn ich den Operrand >> bei float Zahlen benutzen möchte.
1
float test = 2,4536;
2
3
putchar(test);
4
putchar((test >> 8));
5
putchar((test >> 16));
6
putchar((test >> 24));

: Verschoben durch Moderator
von Klaus W. (mfgkw)


Lesenswert?

Martin schrieb:
> float test = 2,4536;

Wahrscheinlich willst du da einen Punkt haben statt des Kommas?

von Klaus W. (mfgkw)


Lesenswert?

Das was du vorhast, geht etwa so:
1
  float test = 2.4536;
2
3
  putchar( (*(uint32_t*)&test) );
4
  putchar( (*(uint32_t*)&test) >> 8 );
5
  putchar( (*(uint32_t*)&test) >> 16 );
6
  putchar( (*(uint32_t*)&test) >> 24 );

Geschickter (u.a., weil es wesentlich schnelleren Code erzeugt)
wäre:
1
  float test = 2.4536;
2
3
  putchar( ((uint8_t*)&test)[0] );
4
  putchar( ((uint8_t*)&test)[1] );
5
  putchar( ((uint8_t*)&test)[2] );
6
  putchar( ((uint8_t*)&test)[3] );

Portabel ist beides nicht.

von Klaus W. (mfgkw)


Lesenswert?

Was willst du eigentlich auf der PC-Seite damit anfangen?
So wie oben müsstest du aus den einzelnen Byte dort wieder
eine float in der richtigen Reihenfolge zusammensetzen.

Vielleicht wäre es für Log-Zwecke geschickter, aus den
Zahlen einen String zu machen und den zu senden.

Dann kann man bspw. auf der PC-Seite einfach mit einem
Terminalprogramm verfolgen, was passiert, und muß nicht
extra ein Programm dafür bauen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ich würde das auch über den ASCII-String machen. Dann kann die 
Übertragung auch problemlos mit jedem terminal mitprotokolliert werden.

Aber trotzdem: Falsches Forum, bitte verschieben...

[erledigt -- Jörg]

von Martin (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Das was du vorhast, geht etwa so:  float test = 2.4536;
>
>   putchar( (*(uint32_t*)&test) );
>   putchar( (*(uint32_t*)&test) >> 8 );
>   putchar( (*(uint32_t*)&test) >> 16 );
>   putchar( (*(uint32_t*)&test) >> 24 );
>
> Geschickter (u.a., weil es wesentlich schnelleren Code erzeugt)
> wäre:  float test = 2.4536;
>
>   putchar( ((uint8_t*)&test)[0] );
>   putchar( ((uint8_t*)&test)[1] );
>   putchar( ((uint8_t*)&test)[2] );
>   putchar( ((uint8_t*)&test)[3] );
>
> Portabel ist beides nicht.

Ich gestehen das ich bei diesem Code noch nicht so ganz durchblicke. Ich 
habe eine 32Bit float variable mit dem Namen test. Die Funktion putchar 
erwartet eine 8Bit Wert als Parameter.

Kann vielleicht jemand versuchen mir diese Quellcodezeile in 2 Sätzden 
zu erklären. putchar( ((uint8_t*)&test)[0] );

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Martin schrieb:
> float test = 2.4536;
>
>   putchar( ((uint8_t*)&test)[0] );
Das bedeutet:
Betrachte den Speicherbereich an der Adresse test (wo ja die 4 Bytes des 
floatwertes abgelegt sind) als char-Array und übergebe das erste Byte an 
dieser Stelle an die Funktion putchar().

Dazu muß man wissen, dass ein float 4 Bytes lang ist.
Was bei dieser Betrachtung allerdings aussen vor gelassen wird, ist die 
Tatsache, dass du dir damit eine Problematik bei der Datenübergabe 
zwischen mit Little- und Big-Endian Sytemen einhandelst. Dann ist der 
float im Empfänger einfach in der falschen Reihenfolge, und damit stimmt 
der Wert nicht mehr.

von Klaus W. (mfgkw)


Lesenswert?

An putchar() kann man auch eine ganze Zahl übergeben, die
größer als ein Byte ist. Dann wird nur das unterste Byte
genommen, der Rest ignoriert.

Wenn du jetzt aber eine float an putchar() übergibst,
würde der Compiler zuviel denken und die float in eine
ganze Zahl wandeln. Also z.B. aus 3.1415 würde eine 3, und
das Byte mit dem Wert 3 (in ASCII ist das ETX, wenn ich
mich recht entsinne) übergeben.

Mit &test nimmt man von der float die Adresse.
Dadurch ist &test ein Zeiger auf float.
Der Zeiger &test zeigt also auf das unterste der vier Byte
von test.

Mit (uint8_t*) davor macht man daraus einen Zeiger auf
Byte (Zeiger auf uint8_t). Es sind natürlich immer noch die
float-Bytes, auf die gezeigt wird, aber der Compiler
behandelt den Zeiger jetzt auf Zeiger auf die einzelnen Bytes.

Das könnte der Zeiger auf ein uint8_t sein, oder auf den Anfang
eines ganzen Feldes davon. Das ist in C erstmal beides gleich.

Mit den [0], [1], [2] und [3] wird nun auf die einzelnen
Bytes des vermeintlichen Feldes zugegriffen, also auf die
einzelnen Bytes der float.

von Martin (Gast)


Lesenswert?

Ich habe schon verstanden was Du damit erzeugen willst, jedoch war mir 
die Schreibweise zu kompakt.

Man erzuegt sich einen Pointer der auf einen vorzeichenlosen 8 Bit Wert 
zeigt. Dann weist man die Adresse vom 0 Element (also Bit 0 bis Bit 7) 
der Float Zahl dem Pointer zu.

Anschließend gibt man die Inhalt der Adresse auf die der Pointer zeigt 
aus und erhöht die Adresse des Zeigers um 1.

Dies habe ich leider nicht aus dem kompakten Code herauslesen können. 
Ich hätte es in mehreren Schritten gemacht (da ich noch nicht so geübt 
bin).

Trotzdem TAUSEND DANK für die Info,

von Klaus W. (mfgkw)


Lesenswert?

Martin schrieb:
> Dann weist man die Adresse vom 0 Element (also Bit 0 bis Bit 7)
> der Float Zahl dem Pointer zu.

Es wird hier keinem Pointer etwas zugewiesen, ...

Martin schrieb:
> erhöht die Adresse des Zeigers um 1

... und es wird nicht die ADRESSE des Zeigers erhöht, sondern
zu seinem WERT (der ein Zeiger ist) wird etwas addiert.

(Compiler sind übrigens ebenso pingelig, das ist also
keine Schikane meinerseits.)

von Martin (Gast)


Lesenswert?

Es wird etwas übertargen jetzt muss ich den Wert noch in einen float 
zurückwandeln

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Martin schrieb:
> Es wird etwas übertargen jetzt muss ich den Wert noch in einen float
> zurückwandeln
Du mußt jetzt genau das selbe rückwärts machen:
Nimm die einzelnen Bytes, schrieb sie über einen char-Pointer in den 
Speicherplatz des floats. Fertig (abgesehen von der Little- und 
Big-Endian-Problematik).

Und dann lass das in einer ruhigen Minute mal auf dich wirken und 
überleg, was du da gemacht hat...

von Stefan H. (stefanhennig)


Lesenswert?

Lothar Miller schrieb:
> Du mußt jetzt genau das selbe rückwärts machen:
>
> Nimm die einzelnen Bytes, schrieb sie über einen char-Pointer in den
>
> Speicherplatz des floats. Fertig (abgesehen von der Little- und
>
> Big-Endian-Problematik).
>
>
>
> Und dann lass das in einer ruhigen Minute mal auf dich wirken und
>
> überleg, was du da gemacht hat...

Also, das ist doch gemein dem armen Martin gegenüber. Korrigier mich mal 
jemand, der Bescheid weiß, aber solange nicht die Compiler auf AVR- und 
PC-Seite beide nach IEEE754 arbeiten, ist doch diese Vorgehensweise zum 
Scheitern verurteilt, oder?
Haben die Intel Prozessoren nicht ein 80-Bit Fließkommaformat?

Damit hier irgendwas funktioniert, müssen so viele Nebenbedingungen 
gegeben sein, dass ich bezweifle, dass wir Martin hier irgendwie 
geholfen haben.

Grüße,
  Stefan

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Stefan Hennig schrieb:
> Haben die Intel Prozessoren nicht ein 80-Bit Fließkommaformat?
1
   float flt;
2
   printf("sizeof(float)=%d\n", sizeof(flt));
3
   double dbl;
4
   printf("sizeof(double)=%d\n", sizeof(dbl));
Ergibt:
sizeof(float)=4
sizeof(double)=8

Was anderes hätte mich (mit Defaulteinstellungen am Compiler) auch sehr 
überrascht...

von Klaus W. (mfgkw)


Lesenswert?

Stefan Hennig schrieb:
> Haben die Intel Prozessoren nicht ein 80-Bit Fließkommaformat?

Wenn er eine float auf dem PC vereinbart, hat die ebenfalls 4 Byte.
Und zufällig die gleiche Auslegung...

Es gibt natürlich Unterschiede, z.B. würde ich nicht unbesehen
behaupten, daß NAN, +/-INF etc. gleich (oder überhaupt) auf
dem AVR behandelt wird.
Aber für "normale" Zahlen wird es klappen.

LE ist auch zufällig gleich.

von Klaus F. (kfalser)


Lesenswert?

Stefan Hennig schrieb:
> Haben die Intel Prozessoren nicht ein 80-Bit Fließkommaformat?

Wenn ich mich richtig erinnere, dann arbeitet oder arbeitete die FPU 
intern mit 80 Bit um Rundungsfehler zu vermindern.
Im Speicher abgelegte double oder floats haben aber 8 Byte/4 Byte

von Klaus W. (mfgkw)


Lesenswert?

Der Vollständigkeit halber: long double hat dann im Speicher
auch die internen 80 Bit auf Intel-PCs.

von Martin (Gast)


Lesenswert?

Vielen Dank für Eure Antwort. Ich arbeite mit der Software Labview. Ich 
habe es hinbekommen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.