Forum: Mikrocontroller und Digitale Elektronik float nach unsigned int


von Sebastian (Gast)


Lesenswert?

Hallo,
ich programmiere gerade einen Regelalgorithmus welcher mit 32 Bit Floats 
rechnet (--> soll so sein!).
Der Algorithmus gibt eine Float Zahl zurück. Für die Ansteuerung der PWM 
benötige ich allerdings eine 16 Bit Unsigned Int.
Ich steh gerade echt auf dem Schlauch was die Typkonvertierung anbelangt 
kann mir jemand weiterhelfen?
(Achja ich benutze den C30 Compiler von Micrchip falls das von Bedeutung 
ist).

Viele Grüße,
Sebastian

von John_der_Seemann (Gast)


Lesenswert?

Hey!
Das, was du vermutlich suchst, nennt sich "casten".
Hierbei kann man einfache Typumwandlungen nach folgendem Beispiel 
durchführen:

float a;
unsigned int b;

b = (unsigned int) a;

Oder siehe auch:

http://home.fhtw-berlin.de/~junghans/cref/CONCEPT/cast.html


Beste Grüße

Seemann

von Karl H. (kbuchegg)


Lesenswert?

Sebastian schrieb:

> Ich steh gerade echt auf dem Schlauch was die Typkonvertierung anbelangt
> kann mir jemand weiterhelfen?

Einfach den float benutzen? Wenn der Empfänger einen unsigned int 
benötigt, dann fügt der Compiler schon eine entsprechende Konvertierung 
ein.


Ein bischen Komfort kann man von einem Compiler schon erwarten. Sonst 
hätte man ja Hochsprachen nicht erfinden müssen, wenn man sich dann 
sowieso um jeden Kleinscheiss erst recht wieder selber kümmern muss.

von Peter II (Gast)


Lesenswert?

John_der_Seemann schrieb:
> Das, was du vermutlich suchst, nennt sich "casten".

nein, casten ist hier überhaupt nicht notwendig. Einfach zuweisen und 
gut ist.
1
int main() {
2
   float a = 1.2;
3
   unsigned int i = a;
4
}

von John_der_Seemann (Gast)


Lesenswert?

@Peter II:

"Schneidet" der Compiler bei deiner Methode ebenfalls die 
Nachkommastellen einfach weg?

von Sebastian (Gast)


Lesenswert?

Das dachte ich auch zuerst allerdings funktioniert weder der cast noch 
die direkte Zuweisung (andersherum allerdings schon). Kann es sein, dass 
das Problem an der Konvertierung 32 Bit --> 16 Bit liegt?

von Peter II (Gast)


Lesenswert?

John_der_Seemann schrieb:
> "Schneidet" der Compiler bei deiner Methode ebenfalls die
> Nachkommastellen einfach weg?

was soll der denn sonst machen?

von Peter II (Gast)


Lesenswert?

Sebastian schrieb:
> Das dachte ich auch zuerst allerdings funktioniert weder der cast noch
> die direkte Zuweisung (andersherum allerdings schon). Kann es sein, dass
> das Problem an der Konvertierung 32 Bit --> 16 Bit liegt?

das kommt auf die werte an. In einem float können auch zahlen > 
MAX_INT32 sein und dann steht unsinn drin.

von John_der_Seemann (Gast)


Lesenswert?

True story! :)
Danke!

von lowlevel (Gast)


Lesenswert?

Natürlich wird der Nachkommateil des Floats abgeschnitten. Ein 
Interger-Typ beinhaltet nunmal nur Ganzzahlen.

Sebastian schrieb:
> Das dachte ich auch zuerst allerdings funktioniert weder der cast noch
> die direkte Zuweisung (andersherum allerdings schon).

Ohne konkrete Fehlermeldung des Compilers bzw. einer Beschreibung des 
Fehlverhaltens können wir nicht ermitteln wo das Problem liegt.

Gruß lowlevel

von Sebastian (Gast)


Lesenswert?

Der Compiler gibt keine Fehlermeldung oder Warning raus.
Folgender Code soll das Problem verdeutlichen:

float regelStellWert; //32 Bit float!

unsigned int pwm; //16 Bit unsigned int!


pwm = regelStellWert; //Es steht nur Käse in PWM

pwm = (unsigned int) regelStellWert; //Auch so steht nur Käse in PWM

Gibts da vielleicht irgend ne spezielle Funktion etc.?

von Karl H. (kbuchegg)


Lesenswert?

Sebastian schrieb:

> float regelStellWert; //32 Bit float!
>
> unsigned int pwm; //16 Bit unsigned int!
>
>
> pwm = regelStellWert; //Es steht nur Käse in PWM

Dann schau dir doch mal den originalen Wert in regelStellWert an.

Wie schon gesagt: ein unsigned int hat nach oben eine Grenze. Mehr geht 
nun mal mit den verfügbaren Bits nicht. Ist dein regelStellWert größer 
als diese Grenze, dann geht das nicht.

> Gibts da vielleicht irgend ne spezielle Funktion etc.?
Dein Problem liegt höchst wahrscheinlich in den Wertebereichen. Also 
musst du dir erst mal einen Überblick verschaffen über welche 
Wertebereich (hier: beim float) überhaupt geredet wird.

von Peter II (Gast)


Lesenswert?

Sebastian schrieb:
> pwm = regelStellWert; //Es steht nur Käse in PWM

bitte ein genaues beispiel:

Was steht und regelStellWert drin und was steht dann in pwm drin?

von Coder (Gast)


Lesenswert?

Wie Karl Heinz andeutete, prüfe mal was bei deinen Berechnung so 
herausgekommt, denn bevor Du eine typecast durchführst solltest Du 
sicher sein, dass der Wert in die zu "castenden" Variable passt. Casts 
sind erlaubt wenn nötig, aber verpönnt:-)

von Sebastian (Gast)


Lesenswert?

Habs gerade mal im Debugger nachgeschaut (beide Zahlen in hex)

regelStellWert = 0x4293 6E24

pwm = 0x6E24


Es wird also letzlich nur die hinteren 16 Bit übernommen, was natürlich 
Quatsch ist.
Gibt es da irgend ne Konvertierungsfunktion um eine float korrekt in 
eine unsigned int zu wandeln?

von Peter D. (peda)


Lesenswert?

Sebastian schrieb:
> regelStellWert = 0x4293 6E24
>
> pwm = 0x6E24

Also beim AVR-GCC kommt korrekt 73 (0x0049) raus:
1
#include <stdint.h>
2
3
uint16_t test()
4
{
5
  union{
6
    float f;
7
    uint32_t u;
8
  }x;
9
10
  x.u = 0x42936E24;
11
12
  return x.f;
13
}
14
  80:   89 e4           ldi     r24, 0x49       ; 73
15
  82:   90 e0           ldi     r25, 0x00       ; 0
16
  84:   08 95           ret


Peter

von Bronco (Gast)


Lesenswert?

Sebastian schrieb:
> regelStellWert = 0x4293 6E24
>
> pwm = 0x6E24

Das wundert mich jetzt aber doch.

Probier mal float nach sint16_t, geht das besser?

von Sebastian (Gast)


Lesenswert?

Ne das bringt leider keine Veränderung!
Bin am Ende mit meinem Latein!

von Coder (Gast)


Lesenswert?

Vielleicht kann Dir jemand im MicroChip-Forum helfen, oder Du wendest 
dich dort direkt an den Support.

von Bronco (Gast)


Lesenswert?

Kannst Du mal den Assembler-Code von der Stelle posten?
Es müßte ja irgendeine impliziete FloatToInt-Convertierungs-Funktion 
aufgerufen werden...

von pic (Gast)


Lesenswert?

Kann es sein, daß du nicth mit float/double sondern mit fixed point
rechnest. Sieht nach Q16 aus, auch wenn PID usw in Q15 gerechnet wird.

Zur Info: Q15=16bit fixed point im 1.15 Format und Q16=16.16 Format.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

John_der_Seemann schrieb:
> @Peter II:
>
> "Schneidet" der Compiler bei deiner Methode ebenfalls die
> Nachkommastellen einfach weg?

Das ist "Implementation Defined" laut Standard.

Es gibt folgende Möglichkeiten, wie die Implementierung das erlegigt; je 
nach Compiler auch einstellbar per Kommandozeile:

• Round to Zero
• Round to Nearest
• Round down (towards -oo)
• Round up (towards +oo)

von pic (Gast)


Lesenswert?

C30 ist GCC. Wenn wie hier Beschrieben:
Sebastian schrieb:
> regelStellWert = 0x4293 6E24
>
> pwm = 0x6E24

dann heisst das, regelStellWert ist irgendein Int, deutet stark auf
fixed point float hin und hat nichts mit float zu tun.
Um diese Zahlen umzuwandeln zu konvertieren gibt es entsprechende
Funktionen. viele DSP Libs von Microchip verwenden fixed point float,
jedoch wird generell Q15 genommen, vielleicht wurde auch das gemischt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Johann L. schrieb:

> • Round to Zero
> • Round to Nearest
> • Round down (towards -oo)
> • Round up (towards +oo)

Mit der Gaußklammer [·] schreiben sich diese Möglichkeiten als:

  

von Karl H. (kbuchegg)


Lesenswert?

Sebastian schrieb:
> Habs gerade mal im Debugger nachgeschaut (beide Zahlen in hex)
>
> regelStellWert = 0x4293 6E24
>
> pwm = 0x6E24
>
>
> Es wird also letzlich nur die hinteren 16 Bit übernommen, was natürlich
> Quatsch ist.
> Gibt es da irgend ne Konvertierungsfunktion um eine float korrekt in
> eine unsigned int zu wandeln?

Zeig doch mal deinen Code.

die Variable regelStellWert ist vom Datentyp 'float'? Das steht da 
explizit so im Code?
die Variale pwm ist vom Datentyp unsigned int (oder int)? Auch das steht 
da so explizit im Code?

Deine Zuweisung sieht so und nicht anders aus?
     pwm = regelStellWert;

Da sind nirgends Pointer involviert?

von Sebastian (Gast)


Lesenswert?

Hier die Originalstelle im Code:
1
float stellWert = 0;
2
unsigned int pwmui = 0;
3
4
PidDataType pidReglerDaten;
5
PidInit(1,0,0,100.0,-100.0, & pidReglerDaten);
6
  
7
PWMInit(70);
8
PWMStart();
9
10
        while(1)
11
  {
12
            sollWert = 100;
13
            vTaskDelayUntil (& lastWakeTime, period);
14
            adValue = GetADVal(I2CADDRESS, I2CCONFBYTESTART);
15
            messWert = GetTemperature(adValue);
16
            stellWert =  PidController(sollWert, messWert, pidReglerDaten);
17
            pwmui = stellWert;
18
            PWMChangeDuty(pwmui);
19
            
20
  }

Sobald stellWert an pwmui "übergeben" wird, passiert das obere Problem. 
Werden die Werte Dezimal betrachtet ist der Wert von stellWert richtig 
der Wert von pwmui ist Quatsch.

von Sebastian (Gast)


Angehängte Dateien:

Lesenswert?

Hier noch die Werte aus dem Debugger wie oben beschrieben

von pic (Gast)


Lesenswert?

Das sind doch alles Q15 Werte, !!!
Mal das Handbuch zur Lib lesen, ist sehr gut beschrieben.

Ansonsten für Dummys:
float varfloat;

   varfloat = Fract2Float(pidReglerDaten.measuredOutput);
   varfloat = Fract2Float(pidReglerDaten.controlReference);
   varfloat = Fract2Float(pidReglerDaten.controlOutput);

von Karl H. (kbuchegg)


Lesenswert?

Sebastian schrieb:
> Hier noch die Werte aus dem Debugger wie oben beschrieben

Was mir viel mehr Sorgen macht, ist die 0x0 in der zweiten Spalte.
Ist das die Adresse der Variablen?

Wenn du im Debugger dir die Werte ansiehst, steht dann die 
Programmausführung in der Funktion?

: Wiederhergestellt durch User
von Sebastian (Gast)


Lesenswert?

Die Programmausführung steht dann bei der Funktion PWMChangeDuty.

Kann mich mal jemand aufklären was Q15 Werte sind - hab das noch nie 
gehört und denke doch einiges an Erfahrung zu haben?

von Karl H. (kbuchegg)


Lesenswert?

Sebastian schrieb:
> Die Programmausführung steht dann bei der Funktion PWMChangeDuty.
>
> Kann mich mal jemand aufklären was Q15 Werte sind - hab das noch nie
> gehört und denke doch einiges an Erfahrung zu haben?

Ist doch ganz einfach.
Was sagt die Doku zur Funktion PidController?

Da stehts drinnen.
Du musst dir angewöhnen, die Doku zu benutzen und weniger zu raten.
Dafür gibt es Doku. Wenn du keine hast, dann musst du dir eben eine Doku 
online suchen.

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


Lesenswert?

pic schrieb:
> Das sind doch alles Q15 Werte, !!!
Sebastian schrieb:
> Kann mich mal jemand aufklären was Q15 Werte sind
Google nach q15 und pic...
1
The I/Q Fixed Point Math Library provides a set of speed optimized functions 
2
for the most common digital signal processing applications. This library 
3
provides significant performance savings over equivalent functions coded in 
4
C and allows developers to dramatically shorten their development time. The 
5
I/Q math library provides mathematical functions useful in a variety of 
6
applications ranging from motor control, digital power control, digital 
7
signal processing and general purpose real-time control using fractional 
8
data types. The function formats provided in the library are in Q15 (1.15) 
9
and Q16 (15.16) representations.
Kurz: du verwendest die falsche Lib.

von Sebastian (Gast)


Lesenswert?

@Karl Heinz Buchegger:
Die Funktion PidController habe ich selber geschrieben. Dazu gibts 
(noch) keine Doku.

von Karl H. (kbuchegg)


Lesenswert?

Sebastian schrieb:
> @Karl Heinz Buchegger:
> Die Funktion PidController habe ich selber geschrieben. Dazu gibts
> (noch) keine Doku.

Zeigen

von Sebastian (Gast)


Lesenswert?

1
float     PidController (float sollwert, float messwert, PidDataType *pid)
2
{
3
    float   regelAbw;
4
    float   soll;
5
    float   mess;
6
    float   pAnteil;
7
    float   iAnteil;
8
    float   dAnteil;
9
    float   stellwert;
10
    
11
    soll = sollwert;
12
    mess = messwert;
13
14
    regelAbw = soll - mess;
15
16
    //Berechnung des P-Anteils
17
    pAnteil = pid->integralSum * regelAbw;
18
19
    //Berechnung des I-Anteils mit Begrenzung der Integralsumme (Anti-Windup)
20
    iAnteil = pid->integralSum + regelAbw;
21
...
22
..
23
.

Der Regler beeinhaltet spezielle Routinen die ich nicht öffentlich 
machen darf, aber ich habe den Regler selber geschrieben.
Der Regler ist gestestet und funktioniert. Ich habe einfach nur dieses 
"lästige" Problem mit der Konvertierung float nach int oder IEEE nach 
Decimal ...

von Karl H. (kbuchegg)


Lesenswert?

Dann sind wir wieder bei dem hier

http://ftp.equilibrium-wow.de/cgi-bin/nph-proxy.cgi/30/http/www.mikrocontroller.net/topic/266731#2779642

Die zweite Spalte. Ist das die Adresse der Variablen?
Die 0x0 da machen mir sorgen. 0x0 sollte in einem Debugger normalerweise 
eher selten zu sehen sein.

von Peter D. (peda)


Lesenswert?

Vermutlich ist bei diesem speziellen Compiler der float-Typ mit anderen 
Formaten überlagert und daher funktionieren die standard Konventionen 
nicht mehr.
Sowas ist sehr ungünstig, da wäre ein neuer Typ besser gewesen.

Es läßt sich bestimmt auch irgendwo einstellen, ob float wirklich als 
float oder als was anderes verwendet wird.


Peter

von Sebastian (Gast)


Lesenswert?

float wird im IEEE 754 Format gespeichert. Ich müsste also eine Routine 
geben um von diesem in das integer Format zu konvertieren.
Ich weiß leider nicht mehr weiter. Hätte nicht gedacht, dass durch 
solche "Kleinigkeiten" ein Projekt nicht mehr weiter geht.

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


Lesenswert?

Sebastian schrieb:
> float wird im IEEE 754 Format gespeichert.
Genau darum kümmert sich normalerweise der Compiler. Du hast da evtl. 
etwas verstellt, oder kannst (wie schon vermutet) noch was umstellen...

von (prx) A. K. (prx)


Lesenswert?

Sebastian schrieb:
> float wird im IEEE 754 Format gespeichert.

Sicher? Gibt bei PICs m.W. auch Exotisches als float. Sowas wie 24-Bit 
Format.

von Sebastian (Gast)


Lesenswert?

Naja wenns gar nicht anders geht, so funktionierts (meine Werte liegen 
nur zwischen null und hundert):
1
float temp;
2
unsigned int i;            
3
4
            if (stellWert < 0)
5
            {
6
                pwmui = 0;
7
            }
8
            if (stellWert > 100)
9
            {
10
                pwmui = 100;
11
            }
12
            else
13
            {
14
                temp = 0;
15
                for (i=0; i<100; i++)
16
                {
17
                    if (stellWert >= temp && !(stellWert <(temp +1)))
18
                    {
19
                        pwmui=i;
20
                    }
21
                    temp++;
22
                }
23
            }
24
25
            PWMChangeDuty(pwmui);

Mich würde trotzdem interessieren ob und wo es da irgendwelche 
Einstellungen gibt, ich hab keine gefunden!

von Karl H. (kbuchegg)


Lesenswert?

A. K. schrieb:
> Sebastian schrieb:
>> float wird im IEEE 754 Format gespeichert.
>
> Sicher? Gibt bei PICs m.W. auch Exotisches als float. Sowas wie 24-Bit
> Format.

Selbst dann müsste der Compiler die Umwandlung machen.
Das ergibt keinen Sinn, wenn er zwar die Umwandlung von int->float drauf 
hat, aber die Umkehrung nicht.

Da ist was anderes faul.
Und ich denke mal, das hat was mit den 0x0 zu tun. An dieser Adresse 
steht im Flash/ROM die Bytefolge 6E 24 42 93
Und bei einer Anzeige im Debugger, die auf 4 Bytes rausläuft (wie zb 
float), wird eben alles angezeigt, während bei einem int eben nur die 
ersten beiden Bytes angezeigt werden.

Was kommt eigentlich raus, wenn du dir diese Bytefolge als float (also 
nicht in Hex-Form sondern richtig mit Dezimalpunkt und allem Drum und 
Drann) anzeigen lässt?

von Sebastian (Gast)


Lesenswert?

Die Bytefolge ist schon richtig, wenn ich sie mir in IEEE anzeigen lasse 
steht das richtige da!

von Bronco (Gast)


Lesenswert?

Geh mal in die "Build Options" Deines Projektes, dann im Reiter "MPLAB 
LINK30" die Category "Libraries" auswählen.

Was steht da?
Ist "Fast floating-point math" ausgewählt?
Ändert sich das Programmverhalten, wenn Du da etwas änderst?

von pic (Gast)


Lesenswert?

Könnte es eventuell sein, daß du die Funktion nicht declarierst und
der Compiler dann einen Int annimmt, und die int->float und float->int
einfach wegoptimiert und gleich den int Wert zuweist.

Ansonsten die Float value müsste 172 sein, auch das wäre ausserhalb 
deines
Bereiches von 0-100. Sind das reale Werte oder nur eine buggy 
Simulation.

Dein Code oben dürfte nur die Werte entweder 0, 100, 101 annehmen.
und auch die Vergleiche sind falsch codiert.

von pic (Gast)


Lesenswert?

sorry, 0 oder 100 wenn overflow/underflow, ansonsten kein Update.

von Sebastian (Gast)


Lesenswert?

Bronco schrieb:
> Geh mal in die "Build Options" Deines Projektes, dann im Reiter "MPLAB
> LINK30" die Category "Libraries" auswählen.
>
> Was steht da?
> Ist "Fast floating-point math" ausgewählt?
> Ändert sich das Programmverhalten, wenn Du da etwas änderst?

Das war des Rätsels Lösung!!

Vielen herzlichen Dank an Bronco und all die Anderen hilfsbereiten hier 
im Forum - Ihr habt mir den Tag gerettet!

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.