Hallo Leute, ich programmiere meinen Atmega32 mit WINAVR. Leider habe ich ein problem mit den Datentypen. Meine Stellgröße y einer Regelung muß ich als long int definieren, um eine hohe Verstärkung nutzen zu können. Leider klappen damit keinerlei logische Vergleiche. if(y < 0) { direction = 0; y = -y; } klappt nicht. Auch wenn y wirklich < 0 ist, wird die Bedingung nie erfüllt. if((int) y < 0) { direction = 0; y = -y; } Obiges funktioniert hingegen. Da kriege ich dann aber Probleme, wenn y schon zu groß wird. Dann gibt es einen Überlauf und der gecastete Wert wird negativ. Auch so etwas klappt nicht: if(y > 3000) { y = 3000; } auch nicht so: if(y > 3000L) { y = 3000L; } Weiß jemand, wie man vernünftige long vergleiche erstellt oder wenigstens richtig casten kann? Gruß, Daniel
Poste mal ein wenig mehr aus dem Code. Sollten sich mehrere if(y...) Abfragen untereinander befinden versuchs mal mit switch(y). Vom Gefühl liegts daran das zwei Abfragen zutreffen und y zweimal das Vorzeichen wechselt.
Bei einem Typen- oder Vorzeichenproblem meckert der Compiler normalerweise mit einer Warnung. Meldet der was beim Kompilieren? Oliver
OK. Das Vorzeichenproblem habe ich gelöst, in dem ich das Vorzeichen des Fehlers checke. Der ist vom typ int und da passiert garantiert auch kein Überlauf. Hier mal meine Funktion: static int e; static long int y; void p_control(int x, int w) { e = w - x; y = kp * e; int direction = 1; if(e < 0) { direction = 0; y = -y; } lcd_clearln(); lcd_puti(y); lcd_puts(" "); int y_max = ICR1; //avoid values higher than TOP if(y > y_max) { y = y_max; } lcd_puti(y); lcd_puts(" "); lcd_puti(direction); lcd_newln(); set_pwm(y, direction); } Das Problem liegt eindeutig in der zweiten if Anweisung. So funktioniert es nämlich: //avoid values higher than TOP if((int) y > y_max) { y = y_max; }
caste doch Dein y_max mal auf long int, das liegt doch auf der Hand, oder habe ich was nicht gesehen ?! Cheers Detlef
Geht auch nicht: long int y_max = ICR1; //avoid values higher than TOP if(y > y_max) { y = y_max; } Das bringt nix. Ich kann einfach keine Vergleiche mit long typen machen? Das kann doch nicht sein.
>Das bringt nix. Ich kann einfach keine Vergleiche mit long typen machen? >Das kann doch nicht sein. Ist es auch nicht. aber long int scheint mir komisch. Probier mal nur long y; MfG Falk
OK. Damit funktioniert der Vergleich schon mal. Hatte diese long int Bezeichnung mal in einem Tutorial gesehen und dachte, daß man das unter c so macht. Jetzt habe ich aber immer noch das Problem, daß der Speicherbereich von y zu klein ist: if(y > y_max) { y = y_max; } wird y größer als 2^16, gibt es einen Überlauf. Auch wenn ich die Variable explizit als int32_t y; definiere.
@Daniel Meyer >wird y größer als 2^16, gibt es einen Überlauf. Auch wenn ich die Woran erkennst du das? >Variable explizit als int32_t y; definiere. long bzw. int32_t sind 32 Bit mit Vorzeichen und können damit +/- 2*10e9 irgendwas darstellen. MFG Falk
> y = kp * e;
Was ist kp.
Wenn kp ein int ist und e ein int ist, dann
hast du wahrscheinlich hier einen sauberen Overflow.
> caste doch Dein y_max mal auf long int, das liegt doch auf der Hand, > oder habe ich was nicht gesehen ?! Unsinn.
> aber long int scheint mir komisch
Ist aber völlig richtig. Der Datentyp heist
wirklich "long int". Durch die unsägliche "implizit int"
Regel ist es allerdings möglich, dies zu einfach nur
"long" abzukürzen.
Selbiges mit "unsigned int".
Anstatt
unsigned int i;
kannst du genausogut
unsigned i;
schreiben.
Der Compiler denkt sich das "int" dazu, wenn er nichts
anderes hat.
OK. Dummer Fehler: y = kp * e; wobei kp und e beide int variablen sind. Gibt natürlich einen Überlauf bevor das Ergebnis in die long variable y geschrieben wird. Sehen tu ich das, indem ich y ausgebe, daß später wieder < y_max wird, obwohl der wert eigentlich höher sein müte. Vielen Dank
@ Karl Heinz B.: Wenn ich long int nehme, wird kein Vergleich ausgeführt.
Daniel Meyer wrote: > OK. Dummer Fehler: > > y = kp * e; > > wobei kp und e beide int variablen sind. Gibt natürlich einen Überlauf > bevor das Ergebnis in die long variable y geschrieben wird. Eben. Und nach einem Überlauf kannst du dich auf gar nichts mehr verlassen. Weder auf das Vorzeichen noch auf sonst irgendwas. Moral von der Story: Wenn du in deinem Programm seltsames Verhalten hast, dann hast du in 99% aller Fälle irgendwo Mist gebaut. Es ist ganz selten, dass in einem derart gut getesteten Compiler wie dem gcc derart triviale Fehler auftauchen.
Daniel Meyer wrote: > @ Karl Heinz B.: > Wenn ich long int nehme, wird kein Vergleich ausgeführt. Dein Problem war schon lange vor dem Vergleich!!!! Die Berechnung hat einen Overflow produziert. Ob das Ergebnis dann positiv oder negativ ist, in welchem Zahlenbereich es liegt, hängt von den konkreten Zahlen ab, die zum Overflow geführt haben. Was du siehst, sind die Symptome. Es hilft aber nichts an den Symptomen herumzudoktorn. Du musst die Ursachen bekämpfen. Und die Ursache ist der Overflow! Wenn du Symptome bekämpfen willst, musst du Arzt werden.
Stimmt. Sorry! Evtl. war auch ein zusätzliches Problem in der Zeile: y = kp * e; Wie verhält es sich, wenn kp vom Typ unsigned int und e vom Typ int ist? Wird dann das Ergebnis vor der Zuweisung auch unsigned berechnet?
...Wenn du Symptome bekämpfen willst, musst du Arzt werden.... eher in die Politik..
long double double float unsigned long int (synonymous with unsigned long) long int (synonymous with long) unsigned int (synonymous with unsigned) int unsigned short int (synonymous with unsignd short) short int (synonymous with short) unsigned Char short Char Dies ist die Reihung. Der jeweils niedrigere Datentyp wird auf den höheren angeglichen.
ALles klar. Vielen Dank nochmal! Deswegen hat mein Vergleich < 0 auch nicht funktionieren können. Wieder was gelernt.
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.