Forum: Mikrocontroller und Digitale Elektronik IEEE-754 Float erzeugen


von Fragestellender (Gast)


Lesenswert?

Ein Modbus Slave liefert eine 32-bit Fließpunktzahl die in zwei 16-bit 
Register aufgeteilt ist.

Beispiel:
Reg 30001: 0x43FA
Reg 30002: 0x9B9A

Diese beiden aneinandergereihten Zahlen sollen als 0x43FA9B9A in eine 
IEEE-754 Fließpunktzahl umgeandelt werden, sodaß dies wie in diesem Fall 
501.21 als float ergibt.
Git es für den gcc eine lib? Oder wie macht man das am einfachsten?

von Peter II (Gast)


Lesenswert?

Fragestellender schrieb:
> Oder wie macht man das am einfachsten?

wenn deinen CPU intern auch IEEE-754 verwendet kannst du es einfach 
verwenden.
1
unsigned char tmp[2];
2
tmp[0] = 0x43FA;
3
tmp[1] = 0x9B9A;
4
5
float f;
6
memcpy( &f, &tmp, sizeof( float ) );

eventuell die Reihenfolge tauschen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

In welchem Format speichert denn Dein gcc floats?

Was geschieht, wenn Du folgendes ausprobierst:

1
uint16_t eins = 0x43fa;
2
uint16_t zwei = 0x9b9a;
3
4
uint32_t beides;
5
float wert;
6
7
8
beides = eins << 16;
9
beides += zwei;
10
11
wert = *(float *) &beides;

Was steht jetzt in "wert"?

von Peter II (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> wert = *(float *) &beides;

hatten wir doch gerade:

Beitrag "uint32_t => float (32) ohne cast!"


das ist so nicht zulässig (auch wenn es oft funktioniert)

von Peter II (Gast)


Lesenswert?

korrektur:

[c]
uint16_t tmp[2];
tmp[0] = 0x43FA;
tmp[1] = 0x9B9A;

float f;
memcpy( &f, &tmp, sizeof( float ) );

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Peter II schrieb:
> das ist so nicht zulässig

Akademisch gesehen ja, hier aber ist es so ziemlich die einzige 
Möglichkeit.

Man könnte natürlich die Funktion, die das Modbus-Telegramm 
interpretiert, so umbasteln, daß es den ankommenden Bytestrom gleich 
passend in float verpackt, aber das ist effektiv genau das gleiche in 
grün.

von Peter II (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Akademisch gesehen ja, hier aber ist es so ziemlich die einzige
> Möglichkeit.

was gefällt dir an meiner Lösung nicht?

von Fragestellender (Gast)


Lesenswert?

Autor: Rufus Τ. Firefly (rufus) (Moderator) schrieb:
>Was steht jetzt in "wert"?
Hat funktioniert. Danke!


Das erste Beispiel von Peter II ging nicht, da kam nur 0.0000 raus.

von Peter II (Gast)


Lesenswert?

Fragestellender schrieb:
> Das erste Beispiel von Peter II ging nicht, da kam nur 0.0000 raus.

das kann nicht sein.

von Joe F. (easylife)


Lesenswert?

Wenn die Endianess des Systems passt, geht auch folgendes:
1
uint16_t reg0;
2
uint16_t reg1;
3
uint32_t u;
4
float    f;
5
6
reg0 = 0x43FA;
7
reg1 = 0x989A;
8
9
u = (reg0 << 16) | reg1;
10
f = *(float *)(&u);
11
12
printf("u: %08X  f: %.2f\n", u, f);

von Peter II (Gast)


Lesenswert?

Peter II schrieb:
> Fragestellender schrieb:
>> Das erste Beispiel von Peter II ging nicht, da kam nur 0.0000 raus.
>
> das kann nicht sein.

ok kann doch sein, wie oben geschrieben die Reihenfolge tauschen.
1
#include <stdio.h>
2
#include <stdint.h>
3
#include <string.h>
4
5
int main()
6
{
7
uint16_t tmp[2];
8
tmp[1] = 0x43FA;
9
tmp[0] = 0x9B9A;
10
11
float f;
12
memcpy( &f, tmp, sizeof( float ) );
13
14
printf("test=%f\n", f );
15
}

von Peter II (Gast)


Lesenswert?

Joe F. schrieb:
> Wenn die Endianess des Systems passt, geht auch folgendes:

auch hier ist der unzulässig cast vorhanden.

von Joe F. (easylife)


Lesenswert?

Peter II schrieb:
> auch hier ist der unzulässig cast vorhanden.

wieso unzulässig?

Nachtrag:
ah ok. habe mir den Thread 
Beitrag "uint32_t => float (32) ohne cast!" zu spät 
angesehen.

gcc auf OSX macht's zwar richtig, aber kann Zufall sein.
Nehme daher meinen Vorschlag zurück.

: Bearbeitet durch User
von Fragestellender (Gast)


Lesenswert?

Autor: Peter II (Gast) schrieb um 14:57:
1
#include <stdio.h>
2
#include <stdint.h>
3
#include <string.h>
4
5
int main()
6
{
7
uint16_t tmp[2];
8
tmp[1] = 0x43FA;
9
tmp[0] = 0x9B9A;
10
11
float f;
12
memcpy( &f, tmp, sizeof( float ) );
13
14
printf("test=%f\n", f );
15
}

Interessant ist, daß wenn man tmp[1] und tmp[0] vertauscht, -0.0000 
rauskommt... hihi... was nach IEEE-754 Notation durchaus richtig ist.

Es soll mal jemand bei der US-Marine als Geschwindigkeit -0.0 Knoten in 
den Rechner eines Zerstöres eingegeben haben, worauf der Zentralrechner 
abstürzte und das Schiff für zwei Stunden lahmlegte.

von Joe F. (easylife)


Lesenswert?

Fragestellender schrieb:
> -0.0 Knoten in
> den Rechner eines Zerstöres eingegeben haben, worauf der Zentralrechner
> abstürzte und das Schiff für zwei Stunden lahmlegte.

Das war bestimmt der gleiche Zerstörer, der einen spanischen Leuchtturm 
per Funk zum ausweichen zwingen wollte...

https://www.youtube.com/watch?v=_VHXRYXzEVU (Satire!)

: Bearbeitet durch User
von Detlev T. (detlevt)


Lesenswert?

Man sollte auf jeden Fall beachten, wie die Bytes angeordnet werden 
(Big- oder Little-Endian)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Peter II schrieb:
> was gefällt dir an meiner Lösung nicht?

Das ist das gleiche, nur anders verpackt. Zulässiger im akademischen 
Sinne ist es auch nicht.

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.