Forum: Mikrocontroller und Digitale Elektronik value truncated..


von Kartoffel (Gast)


Lesenswert?

Hi zusammen,

also ich hab zwei kleine Problemchen im Programm, die ich noch beheben 
muss.
Auf die Lösung komm ich irgendwie nicht, vielleicht weiß einer ja Rat.
1
unsigned int Drehz_setzen(unsigned int Soll_dr)
2
{
3
unsigned int a = 0;  
4
a = (Soll_dr/15)*2;
5
Hexwert = MIN + a;  // MIN+Soll_dr*7,5
6
7
  if (Hexwert > MAX) // Begrenzung auf den max. Registerwert
8
    {
9
      Hexwert = MAX;
10
    }
11
12
return Hexwert;
13
}

MIN = 65135, MAX = 65535
Nach dem Kompillieren von diesem Code, bekomme ich eine Warnung : Value 
truncated. Ich bin aber der Meinung, dass alles passt, ich überschreite 
den Wertebereich doch gar nicht, die Soll_dr kann maximal 3000 sein.

Die zweite Sache: ich bestimme die Drehzahl aus Encoderimpulsen. Der 
Code dafür:
1
unsigned long int Drehzahl(void)
2
{
3
unsigned long int Drehz =0;
4
5
  
6
  if (CC1_CC9 < CC9alt)
7
    {
8
    Counter_dif = 0-(CC1_CC9-CC9alt);
9
    }
10
  else
11
    {
12
  Counter_dif = CC1_CC9-CC9alt;
13
    }
14
  CC9alt = CC1_CC9;
15
  Drehz = 1200000L/(int)Counter_dif; // Drehzahl in Umdrehungen pro Minute
16
  
17
18
   return Drehz; 
19
}

Die ermittelte Drehzahl stimmt fast immer (ist mit einem Drehzahlmesser 
überprüft), allerdings bekomme ich manchmal noch so komische Drehzahlen 
von 4294967175....ich geh davon aus, dass die Berechnung in manchen 
Fällen ne negative Zahl ergibt. Dachte aber, dass ich diesen Fall mit 
der if-Verzweigung abgefangen habe.

von Bernhard M. (boregard)


Lesenswert?

1
unsigned int Drehz_setzen(unsigned int Soll_dr)
2
{
3
unsigned int a = 0;  
4
a = (Soll_dr/15)*2;
5
Hexwert = MIN + a;  // MIN+Soll_dr*7,5
6
7
  if (Hexwert > MAX) // Begrenzung auf den max. Registerwert
8
    {
9
      Hexwert = MAX;
10
    }
11
12
return Hexwert;
13
}
ist ja wohl unvollständig, da "Hexwert" nirgendwo definiert wird. Das 
ist doch hoffentlich eine lokale Variable!
Ausserden kann es, falls es auch unsigned int ist, nie größer als MAX 
werden (da max ja die größte als unsigned int darstellbare Zahl 
ist)...d.h. die if-Abfrage ist überflüssig - Compiler merken sowas. Du 
solltest wohl eher abfragen:
1
if (a > (MAX - MIN))
2
...

Im nächsten Beispiel:
1
  if (CC1_CC9 < CC9alt)
2
    {
3
    Counter_dif = 0-(CC1_CC9-CC9alt);
4
    }
ist vermutlich falsch, denn ich denke, das Du hiermit den wrap-around 
des Zählers abfangen willst...

von Unbekannter (Gast)


Lesenswert?

> Ich bin aber der Meinung, dass alles passt, ich überschreite
> den Wertebereich doch gar nicht, die Soll_dr kann maximal 3000 sein.

Ja nach Compiler bzw. Architektur kann "unsigned int" nur 16 Bit breit 
sein.

Du kannst aber auch einfach den Roh-Wert vergleichen:
1
  if ( Soll_dr > 3000 )
2
    return MAX;
3
  else
4
    return MIN + (Soll_dr/15)*2;

Wie immer gilt: Konstanten wie 3000, 15 und 2 sind schlechter Stil beim 
Programmieren.

Daher wäre etwa folgendes besser:
1
#define MIN                 65135
2
#define MAX                 65535
3
#define SOLL_DR_DIV         15
4
#define SOLL_DR_MUL         2
5
#define SOLL_DR_TO_HEX(x)   ( MAX + ((x)/SOLL_DR_DIV) * SOLL_DR_MUL )
6
#define SOLL_DR_MAX         ( ((MAX-MIN) * SOLL_DR_DIV) / SOLL_DR_MUL ) 
7
8
[...]
9
10
  if ( Soll_dr > SOLL_DR_MAX )
11
    return MAX;
12
  else
13
    return SOLL_DR_TO_HEX( Soll_dr );

von Unbekannter (Gast)


Lesenswert?

1
#define SOLL_DR_TO_HEX(x)   ( MAX + ((x)/SOLL_DR_DIV) * SOLL_DR_MUL )

Soll natürlich heissen:
1
#define SOLL_DR_TO_HEX(x)   ( MIN + ((x)/SOLL_DR_DIV) * SOLL_DR_MUL )

von Kartoffel (Gast)


Lesenswert?

@Bernhard: also der Hexwert ist auch unsigned int und lokal deklariert.
1
if (CC1_CC9 < CC9alt)
2
    {
3
    Counter_dif = 0-(CC1_CC9-CC9alt);
4
    }

ja, damit möchte ich abfangen, dass ich beim Zählerüberlauf negative 
Geschwindigkeiten bekomme. Denn die Geschw.berechnung beinhaltet ja 
Counter_dif. Wieso ist das falsch? Liegt hier der Fehler?

von Bernhard M. (boregard)


Lesenswert?

Bei einem Überlauf ist ja CC9alt größer als CC1_CC9.
Die wahre Differenz zwischen beiden ist dann doch zum einen die 
Differenz von  CC9alt bis zum max. möglichen Wert plus CC1_CC9 (das ja 
die Differenz von 0 bis CC1_CC9 entspricht.

Bildlich dargestellt:
1
  0++++++--------------------------------------+++MAX
2
                                              ^CC9alt
3
        ^CC1_CC9
Du willst die "länge" des ++ Bereiches, berechnest aber die länge des -- 
Bereiches...

Also:
1
Counter_dif = CC1_CC9 + (MAX - CC9alt);
wobei MAX die Konstante für den Wert, bei dem es dem Wrap-around gibt, 
sein muß (geht aus Deinem Beispiel nicht hervor).

von Kartoffel (Gast)


Lesenswert?

ja klar!!!!
Hab alles schon behoben, danke schön.

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.