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
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
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.
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 | }
|
@Peter II: "Schneidet" der Compiler bei deiner Methode ebenfalls die Nachkommastellen einfach weg?
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?
John_der_Seemann schrieb: > "Schneidet" der Compiler bei deiner Methode ebenfalls die > Nachkommastellen einfach weg? was soll der denn sonst machen?
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.
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
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.?
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.
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?
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:-)
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?
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
Sebastian schrieb: > regelStellWert = 0x4293 6E24 > > pwm = 0x6E24 Das wundert mich jetzt aber doch. Probier mal float nach sint16_t, geht das besser?
Vielleicht kann Dir jemand im MicroChip-Forum helfen, oder Du wendest dich dort direkt an den Support.
Kannst Du mal den Assembler-Code von der Stelle posten? Es müßte ja irgendeine impliziete FloatToInt-Convertierungs-Funktion aufgerufen werden...
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.
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)
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.
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:
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?
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.
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);
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
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?
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.
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.
@Karl Heinz Buchegger: Die Funktion PidController habe ich selber geschrieben. Dazu gibts (noch) keine Doku.
Sebastian schrieb: > @Karl Heinz Buchegger: > Die Funktion PidController habe ich selber geschrieben. Dazu gibts > (noch) keine Doku. Zeigen
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 ...
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.
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
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.
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...
Sebastian schrieb: > float wird im IEEE 754 Format gespeichert. Sicher? Gibt bei PICs m.W. auch Exotisches als float. Sowas wie 24-Bit Format.
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!
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?
Die Bytefolge ist schon richtig, wenn ich sie mir in IEEE anzeigen lasse steht das richtige da!
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?
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.