mikrocontroller.net

Forum: Compiler & IDEs Keine Vergleiche mit long möglich???


Autor: Daniel Meyer (dandansen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Nepi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei einem Typen- oder Vorzeichenproblem meckert der Compiler 
normalerweise mit einer Warnung.

Meldet der was beim Kompilieren?

Oliver

Autor: Daniel Meyer (dandansen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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;
  }

Autor: Daniel Meyer (dandansen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weder Fehler noch Warnungen.

Autor: Detlef _a (detlef_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
caste doch Dein y_max mal auf long int, das liegt doch auf der Hand, 
oder habe ich was nicht gesehen ?!

Cheers
Detlef

Autor: Daniel Meyer (dandansen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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

Autor: Daniel Meyer (dandansen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>   y = kp * e;

Was ist kp.

Wenn kp ein int ist und e ein int ist, dann
hast du wahrscheinlich hier einen sauberen Overflow.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> caste doch Dein y_max mal auf long int, das liegt doch auf der Hand,
> oder habe ich was nicht gesehen ?!

Unsinn.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.


Autor: Daniel Meyer (dandansen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Daniel Meyer (dandansen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Karl Heinz B.:
Wenn ich long int nehme, wird kein Vergleich ausgeführt.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Daniel Meyer (dandansen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...Wenn du Symptome bekämpfen willst, musst du Arzt werden....

eher in die Politik..

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Daniel Meyer (dandansen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ALles klar. Vielen Dank nochmal! Deswegen hat mein Vergleich < 0 auch 
nicht funktionieren können. Wieder was gelernt.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.