Forum: Mikrocontroller und Digitale Elektronik Festkommaarithmetik und itoa Problem


von Stefan H. (hohmi)


Angehängte Dateien:

Lesenswert?

Hallo Community,

ich möchte ein Gerät zur Neigungsmessung zusammen bauen und via LCD die 
Werte anzeigen lassen.

der Bereich geht von -90.0° bis 90.0°.

Jetzt wollte ich zu testzwecken auf meinem myAVR Board (inkl. LCD) das 
ganze schon mal mit dem LCD fertigstellen bis das IC und das neue LCD 
kommt.

Also Poti an den ADC und ne kleine Rechnung um meinen Werte-Bereich 
anzeigen lassen zu könnrn:
1
  // Wert aus ADC in Buffer übertragen
2
  buffer = ADC_Wandler(0);
3
  
4
  // Umwandlung von -500 bis +500; x ist eine int32_t und textfeld eine char[12] Variable
5
  x = (((1000*buffer)/255)-500);
6
7
  itoa (x, textfeld, 10);
8
9
  //Variable textfeld ausgeben
10
  lcd_goto(2, 10);
11
  _delay_ms(10);
12
  lcd_writeText(textfeld, 4);
13
  _delay_ms(10);



ADC ist auf 0-255 skaliert und mit der kleinen Rechnung, müsste dann 
-500 bis +500 als Ergebnis erscheinen. Um nun das "," einfügen zu können 
hab schnell diesen Code zusammen gebastelt (ist nicht schön ich weiß, 
aber für meine Zwecke vollkommend ausreichend):


1
//Variable textfeld mit ","
2
lcd_goto(1, 4);
3
if ((x >= (-999)) && (x <= (-100))) {
4
      lcd_write('-');
5
      lcd_write(textfeld[1]);
6
      lcd_write(textfeld[2]);
7
      lcd_write(',');
8
      lcd_write(textfeld[3]);
9
    } else if ((x >= (-99)) && (x <= (-10))) {
10
      lcd_write('-');
11
      lcd_write(' ');
12
      lcd_write(textfeld[1]);
13
      lcd_write(',');
14
      lcd_write(textfeld[2]);
15
    } else if ((x >= (-9)) && (x < 0)) {
16
      lcd_write('-');
17
      lcd_write(' ');
18
      lcd_write('0');
19
      lcd_write(',');
20
      lcd_write(textfeld[0]);
21
    }else if (x == 0) {
22
      lcd_write(' ');
23
      lcd_write(' ');
24
      lcd_write('0');
25
      lcd_write(',');
26
      lcd_write('0');
27
    } else if ((x > 0) && (x <= 9)) {
28
      lcd_write(' ');
29
      lcd_write(' ');
30
      lcd_write('0');
31
      lcd_write(',');
32
      lcd_write(textfeld[0]);
33
    } else if ((x >= 10) && (x <= 99)) {
34
      lcd_write(' ');
35
      lcd_write(' ');
36
      lcd_write(textfeld[0]);
37
      lcd_write(',');
38
      lcd_write(textfeld[1]);
39
    } else if ((x >= 100) && (x <=999)) {
40
      lcd_write(' ');
41
      lcd_write(textfeld[0]);
42
      lcd_write(textfeld[1]);
43
      lcd_write(',');
44
      lcd_write(textfeld[2]);
45
    }

Aber aus mir unerklärlichen Gründen kommt bei x ein falscher Wert raus.

Daher hab ich den ganzen Code kopiert und in Dev-C++ eingefügt und alle 
lcd_write befehle durch print_f ersetzt --> Es funktioniert ohne wenn 
und aber.

Das einzige was ich mir erklären kann, ist das der DEV-C Kompiler eine 
andere Biblitothek für itoa benutzt als der des AVR Studio 6.

Habe auch schon den ABS vonx gebildet und dann erst gewandelt. Ebenso 
die Rechnung in einzelen Rechenschritte einzuteilen mit 
Zwischenergebnissen, es klappt im AVR Strudio einfach nicht.

Hat einer von euch nen Rat? Code sind im Anhang, danke euch im Voraus. 
Ich weiß nicht mehr weiter...

mfg
Hohmi

von Stefan H. (hohmi)


Angehängte Dateien:

Lesenswert?

Sorry, da war noch ein grober Schnitzer im ADC Kommentar, nicht dass das 
einer so abpinselt und sich wundert^^.

mfg
Hohmi

von Peter II (Gast)


Lesenswert?

> uint8_t buffer = 0;
> x = (((1000*buffer)/255)-500);

wenn buffer > 66 ist dann wird 1000*buffer > 66000 und das Passt nicht 
mehr in einen int.

 x = (((1000l*buffer)/255)-500);

müsste funktionieren.

von Andreas H. (ahz)


Lesenswert?

Huhu Stefan

Nur mal ein Schuss ins Blaue:

Stefan H. schrieb:
> x = (((1000*buffer)/255)-500);

Wenn buffer = 255 ist, wird der Wert (1000 * buffer) natürlich 255000.
Das ist aber vermutlich größer als der MAXINT des AVRs.

Mit anderen Worten: Du hast da einen Zahlenüberlauf. Darum klappt das 
dann auch auf dem PC, der ja mit 32, bzw. 64 bit rechnet.

Grüße
Andreas

von Andreas H. (ahz)


Lesenswert?

Peter II schrieb:
> wenn buffer > 66 ist dann wird 1000*buffer > 66000 und das Passt nicht
> mehr in einen int.

Ups, da war Peter schneller ;-)

Grüße
Andreas

von Falk B. (falk)


Lesenswert?


von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter II schrieb:
>  1000l

Besser: 1000L dann gibt's auch keine Fehler beim Lesen (ja nach 
Firle-Font).

von Stefan H. (hohmi)


Lesenswert?

Sooooooooo, danke an alle!!!!
an der buffer Variabel hat es nicht gelegen. Die hatte ich als int32_t 
deklariert.

Die Festkommaarithmetik hatte ich mir schon durchgelesen aber nicht 
genau genug...

Die Lösung:

"Man sollte mindestens eine Variable auf der rechten Seite genauso groß 
deklarieren wie das Ergebnis auf der linken Seite oder einen Cast 
benutzen."

ein cast dabei und das Problem hat sich in Luft aufgelöst:
1
x = (((1000 * (long) buffer)/255)-500);


Danke an alle die daran mitgewirkt haben!

mfg Hohmi

von Mike (Gast)


Lesenswert?

Stefan H. schrieb:
> "Man sollte mindestens eine Variable auf der rechten Seite genauso groß
> deklarieren wie das Ergebnis auf der linken Seite oder einen Cast
> benutzen."

Da ist ein dicker Übersetzungsfehler drin. Richtig muss es heißen:
"Man muss mindestens ...", sonst nützt das alles nichts.

von Falk B. (falk)


Lesenswert?

@ Stefan H. (hohmi)

>an der buffer Variabel hat es nicht gelegen. Die hatte ich als int32_t
>deklariert.

Dann hätte die Rechnung funktioniert. In deinem geposteten Code war sie 
uint8_t!

http://www.mikrocontroller.net/attachment/highlight/217499

>ein cast dabei und das Problem hat sich in Luft aufgelöst:

wenn buffer WIRKLICH uint32_t ist, ist der cast überflüssig.

von Stefan H. (hohmi)


Lesenswert?

Hast recht falk!

Ich meinte die Variable x.

Sorry für den vertipper

mfg

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.