Forum: Compiler & IDEs 32Bit Variablen in GCC mit Atmega8


von Malte (Gast)


Lesenswert?

Hi zusammen,

ich habe eine Problem und komme nicht weiter. Suche im Netz hat nicht 
geholfen. Ich hoffe hier finde ich Hilfe?!

Ich arbeite mit einem ATMEGA8 und ImageCraftCV v8 (ICCAVR).

Mein Problem ist, um den AD Wandler vernünftig auszuwerten muss ich, um 
Kommarechnung zu vermeiden, kurzzeitig den 16-Bit Bereich verlassen und 
benötige 32Bit Variablen.

Deklarieren kann ich sie auch (uint32_t wird akzeptiert), aber er 
rechnet dennoch nur mit 16Bit.

Liegt's am ATMEGA8? Ich dachte er würde es in 4x8 ablegen und irgendwie 
berechnen können (Compiler)?

Vielen Dank und Gruß, Malte

von (prx) A. K. (prx)


Lesenswert?

Malte schrieb:

> Deklarieren kann ich sie auch (uint32_t wird akzeptiert), aber er
> rechnet dennoch nur mit 16Bit.

Das liegt ziemlich sicher nicht am Compiler sondern am Code. Nur 
diskutiert es sich besser über Code den man kennt.

Einen Tipp ins Blaue hätte ich aber trotzdem: Der Typ links vom "=" hat 
keinerlei Einfluss darauf, wie der Ausdruck rechts davon berechnet wird.
  uint32_t result = 10000 * 10000;
geht bei 16-Bittern also definitiv in die Fritten.

PS: Was hat der Imagecraft Compiler mit dem GCC zu tun?

von Karl H. (kbuchegg)


Lesenswert?

A. K. schrieb:

> Einen Tipp ins Blaue hätte ich aber trotzdem:

Auf dasselbe Problem hätte ich auch getippt:
Der OT hat wieder mal seine Hausaufgaben nicht gemacht und will das 
jetzt dem Compiler anhängen :-)

Etwas näher beleuchtet ist die vermutete Problematik 
hier:http://www.mikrocontroller.net/articles/FAQ#Datentypen_in_Operationen

Einfach anstelle von double/float gedanklich uint32_t einsetzen. Ist das 
gleiche "Problem".

von Malte (Gast)


Lesenswert?

Danke für eure Antworten...

Wahrscheinlich ist euer Tipps in Blaue schon ein Volltreffer!
Habe ich nicht drüber nachgedacht.

Ich teste das mal und sonst veröffentliche mal den Code...

Danke!

VG, Malte

von Malte (Gast)


Lesenswert?

Hi!

Also der Tipp ins Blaue hat nicht ganz in Schwarze getroffen.

Der Code ist recht umfangreich, mittlerweile, aber ich habe mir ein 
Beispiel geschrieben, um diesen Teil zu testen.

Ganz simpel:

-------------------
int16_t current=0;
int32_t current_avr=0;
char Buffer[20]; // in diesem {} lokal

current_avr=100000;
current=current_avr/100;

itoa( Buffer, current, 10 );  //Strom dezimal umwandeln in ASCII
lcd_string(Buffer);
-------------------

So - nun kann ich auf meinen LC Display das sehen:

Stelle ich current_avr auf 10000 wird mir 100 auf dem Display angezeigt.
Stelle ich ihn auf 100000 (32 Bit Bereich) wird mir -310 angezeigt.

Ich habe das Gefühl, der ATMEGA8 begrenzt die Anzahl und kann keine 
32Bit oder mache ich etwas falsch?

Danke!

von mork (Gast)


Lesenswert?

Gibt Dein Compiler bei "current_avr=100000;" denn keine Warnung aus? 
100000 ist nämlich vom Typ int (also 16) bit lang, passt jedoch garnicht 
in einen 16-bit int rein -> die restlichen bits werden abgeschnitten und 
die Zahl wird in diesem Fall ein negativer int, was -31073 ist, soweit 
ich richtig gerechnet habe. Dacher auch die -310.

Deshalb musst Du ein L nach 100000 schreiben, also current_avr=100000L; 
Dies sagt dem Compiler, dass die Zahl ein 32-bit long ist.

MfG Mark

von Karl H. (kbuchegg)


Lesenswert?

Malte schrieb:


> Der Code ist recht umfangreich, mittlerweile, aber ich habe mir ein
> Beispiel geschrieben, um diesen Teil zu testen.

Das ist der richtige Weg

> -------------------
> int16_t current=0;
> int32_t current_avr=0;
> char Buffer[20]; // in diesem {} lokal
>
> current_avr=100000;
> current=current_avr/100;
>
> itoa( Buffer, current, 10 );  //Strom dezimal umwandeln in ASCII
> lcd_string(Buffer);
> -------------------
>
> So - nun kann ich auf meinen LC Display das sehen:
>
> Stelle ich current_avr auf 10000 wird mir 100 auf dem Display angezeigt.
> Stelle ich ihn auf 100000 (32 Bit Bereich) wird mir -310 angezeigt.

Und das ist wirklich dein Code?
100% so läuft der ab?

Kannst du mal ein komplettes Beispiel fertig machen, welches man hier 
kompilieren kann (die LCD Routinen kannst du dir sparen)

> Ich habe das Gefühl, der ATMEGA8 begrenzt die Anzahl und kann keine
> 32Bit oder mache ich etwas falsch?

Der Mega8 hat damit nichts zu tun. Der führt nur Befehle aus. Befehle 
die ihm der Compiler erzeugt.

von Karl H. (kbuchegg)


Lesenswert?

mork schrieb:
> Gibt Dein Compiler bei "current_avr=100000;" denn keine Warnung aus?
> 100000 ist nämlich vom Typ int (also 16) bit lang,

ist es nicht

 passt jedoch garnicht
> in einen 16-bit int rein

genau deswegen ist es kein int, sondern ein long

von Daniel V. (danvet)


Lesenswert?

Der ICCAVR8 vertseht kein int16_t oder int32_t oder dergleichen,habs 
grad getestet.
Welchen Compiler verwendest du also bzw. wie ist dein int16_t etc. 
definiert?

von mork (Gast)


Lesenswert?

@Karl heinz Buchegger

Ok, das current_avr ist wirklich ein long, hab das beim Schreiben 
irgendwie nicht ganz beachtet.

Aber wieso ist 100000 kein int?

von Daniel V. (danvet)


Lesenswert?

mork schrieb:
> @Karl heinz Buchegger
>
> Ok, das current_avr ist wirklich ein long, hab das beim Schreiben
> irgendwie nicht ganz beachtet.
>
> Aber wieso ist 100000 kein int?

2^16 = 65536

von Karl H. (kbuchegg)


Lesenswert?

mork schrieb:

> Aber wieso ist 100000 kein int?

Weil es zu groß für einen 16 Bit int ist.
Ist ganz einfach: Ist eine Konstante für einen Datentyp zu groß, dann 
kriegt sie automatisch den nächstgrößeren Datentyp in den sie reinpasst.

Sooo dämlich waren Kernighan&Ritchie dann auch wieder nicht. Und für den 
Compiler ist das eine leichte Übung.

von mork (Gast)


Lesenswert?

Ja e

Daniel V. schrieb:
> mork schrieb:
>> @Karl heinz Buchegger
>>
>> Ok, das current_avr ist wirklich ein long, hab das beim Schreiben
>> irgendwie nicht ganz beachtet.
>>
>> Aber wieso ist 100000 kein int?
>
> 2^16 = 65536

Ja eben. Deshalb passen die 100000 da garnicht rein, und in current_avr 
steht 100000 - 65536 = 34464. Diese werden als 16-bit signed 
interpretiert, also - (65536 - 34464) = -31072. (ich glaub irgendwo muss 
da noch ne +1 1 hin, was aber in diesem Fall egal ist). (31072 +-1) / 
100 = -310, eben das, was beim Malte auf dem Display ausgegeben wird.

MfG Mark

von mork (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> mork schrieb:
>
>> Aber wieso ist 100000 kein int?
>
> Weil es zu groß für einen 16 Bit int ist.
> Ist ganz einfach: Ist eine Konstante für einen Datentyp zu groß, dann
> kriegt sie automatisch den nächstgrößeren Datentyp in den sie reinpasst.
>
> Sooo dämlich waren Kernighan&Ritchie dann auch wieder nicht. Und für den
> Compiler ist das eine leichte Übung.

Also vom avr-gcc hab ich das irgendwie anders in Erinnerung. Da muss man 
doch auch bei größeren Zahlen ständig ein L hintendran hängen, bei 
Definition von F_CPU z.B.

von Karl H. (kbuchegg)


Lesenswert?

mork schrieb:
> Ja e
>
> Daniel V. schrieb:
>> mork schrieb:
>>> @Karl heinz Buchegger
>>>
>>> Ok, das current_avr ist wirklich ein long, hab das beim Schreiben
>>> irgendwie nicht ganz beachtet.
>>>
>>> Aber wieso ist 100000 kein int?
>>
>> 2^16 = 65536
>
> Ja eben. Deshalb passen die 100000 da garnicht rein, und in current_avr
> steht 100000 - 65536 = 34464.

Das wäre dann ein Compilerfehler, wenn das passieren würde.
Da das aber einer ist, der beim Testen eines COmpilers ganz schnell 
auffällt, würde ich meine Hand hier nicht auf einen Compilerfehler 
verwetten.
Möglich wärs. Aber sehr unwahrscheinlich.

von Karl H. (kbuchegg)


Lesenswert?

mork schrieb:

> Also vom avr-gcc hab ich das irgendwie anders in Erinnerung. Da muss man
> doch auch bei größeren Zahlen ständig ein L hintendran hängen, bei
> Definition von F_CPU z.B.

Bitte!

Kauf dir ein C-Buch und arbeite es durch!
Es spielt keine Rolle, woran du dich erinnerst und woran nicht.
Entscheidend ist, was in den Normungsdokumenten zu C steht. Und dort 
steht drinnen, dass auf einer Maschine mit 16-Bit int die Konstante 
100000 den Datentyp long hat.
OK, in diesem Wortlaut steht es nicht drinnen, aber darauf läuft es 
hinaus.

von Daniel V. (danvet)


Lesenswert?

> -------------------
> int16_t current=0;
> int32_t current_avr=0;
> char Buffer[20]; // in diesem {} lokal
>
> current_avr=100000;
> current=current_avr/100;
>
> itoa( Buffer, current, 10 );  //Strom dezimal umwandeln in ASCII
> lcd_string(Buffer);
> -------------------
>

Also current_avr ist ja 32Bit, da kann man 100000 zuweisen.
Die Zeile "current = current_avr / 100" könnte durchaus Probleme machen.

Vielleicht so besser?:

current_avr = current_avr / 100;
current = (int)current_avr;

von mork (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> mork schrieb:
>
>> Also vom avr-gcc hab ich das irgendwie anders in Erinnerung. Da muss man
>> doch auch bei größeren Zahlen ständig ein L hintendran hängen, bei
>> Definition von F_CPU z.B.
>
> Bitte!
>
> Kauf dir ein C-Buch und arbeite es durch!
> Es spielt keine Rolle, woran du dich erinnerst und woran nicht.
> Entscheidend ist, was in den Normungsdokumenten zu C steht. Und dort
> steht drinnen, dass auf einer Maschine mit 16-Bit int die Konstante
> 100000 den Datentyp long hat.
> OK, in diesem Wortlaut steht es nicht drinnen, aber darauf läuft es
> hinaus.

Habs gerade ausprobiert, bei uint32_t = 100000; kommt keine Warnung -> 
wird wohl stimmen. Was ich dann aber nicht vestehe ist, wieso  der 
L-Suffix überhaupt gebraucht, wenn die Zahl schon sowieso ein long ist. 
Beim Rechnen wird doch mit dem größten Typ aber mindestens mit int 
gerechnet oder nicht?

MfG Mark

von Tom M. (Gast)


Lesenswert?

mork schrieb:
>Was ich dann aber nicht vestehe ist, wieso  der
> L-Suffix überhaupt gebraucht, wenn die Zahl schon sowieso ein long ist.
> Beim Rechnen wird doch mit dem größten Typ aber mindestens mit int
> gerechnet oder nicht?

Die Suffixe wirste bei DEFINES verwenden, nicht bei Deklarationen von 
Variablen. Sie helfen dem Compiler beim Berechnen von konstanten 
Ausdrücken, Rechtzeitig den "int"-Bereich zugunsten von long zu 
verlassen.

von Malte (Gast)


Lesenswert?

Also ich habe jetzt mal Folgendes gemacht:

current_avr=100000L;
current_avr=current_avr/100;
current=(int)current_avr;

Hilft aber auch nicht. Also weder die INT Wandlung noch die L 
Geschichte.

Mein Compiler hat keine Warnung ausgegeben und ich dachte auch, es wäre 
ok. Schließlich habe ich die current_avr als 32Bit definiert - dann 
müsste man doch 100.000 zuweisen können, oder?

Compiler ist wie gesagt der interne von ICCAVR 8.01.
Aber der Compiler muss ja irgendwie dem kleinen 8-Bit Controller die 
16-Bit-Werte beibringen. Da es mit 16Bit geht, dachte ich, er würde auch 
den 32Bit Wert schön zerlegen und in getennten Registern dann behandeln 
aber irgendwie klappt das nicht.

Der Code ist jetzt ein kleines Extrakt und oft kann der Fehler ja auch 
woanders stecken. Nur in diesem Fall ist es ja recht einfach: die 
Ausgabefunktion funktioniert auf dem LCD 1A. D.h. dadurch kann ich den 
16-Bit Inhalt von current gut visualisieren.

Ich habe jetzt mal 32700 eingeben --> Ausgabe 327. Geht. Dann 32800 bei 
current_avr. Ausgabe über current --> 327. Spricht ja dafür, dass er 
current_avr als int16_t und nicht als int32_t ansteuert...

Verstehe ich einfach noch nicht. Naja, ich muss jetzt eh mal los und 
vielleicht fällt der Groschen, wenn man an etwas anderes denkt :)

Danke euch!

von Karl H. (kbuchegg)


Lesenswert?

mork schrieb:

> wird wohl stimmen. Was ich dann aber nicht vestehe ist, wieso  der
> L-Suffix überhaupt gebraucht, wenn die Zahl schon sowieso ein long ist.
> Beim Rechnen wird doch mit dem größten Typ aber mindestens mit int
> gerechnet oder nicht?

Weil es ja auch diese Fälle gibt

#define QUDARAT_MILLIMETER  1000 * 1000


1000 ist ein int
Soweit alles ok. Aber 1000 * 1000 passt nicht mehr in einen int. Die 
Multiplikation wird überlaufen, weil sie in int durchgeführt wird.

#define QUDARAT_MILLIMETER  1000L * 1000L

liefert das richtige Ergebnis

von Tom M. (Gast)


Lesenswert?

Malte schrieb:

> Ich habe jetzt mal 32700 eingeben --> Ausgabe 327. Geht. Dann 32800 bei
> current_avr. Ausgabe über current --> 327. Spricht ja dafür, dass er
> current_avr als int16_t und nicht als int32_t ansteuert...

Nein, spricht dafür dass du dich mit den Deklarationen vertan und/oder 
dir mit wildem Casting selbst ins Bein geschossen hast.

von Karl H. (kbuchegg)


Lesenswert?

Malte schrieb:

> Compiler ist wie gesagt der interne von ICCAVR 8.01.
> Aber der Compiler muss ja irgendwie dem kleinen 8-Bit Controller die
> 16-Bit-Werte beibringen. Da es mit 16Bit geht, dachte ich, er würde auch
> den 32Bit Wert schön zerlegen und in getennten Registern dann behandeln

Das tut er auch.
Aber er bewegt sich dabei im Rahmen der C-Regeln.

Und irgendwo hast du ein Schlupfloch offen gelassen.

Und daher nochmal die Bitte:
Bitte, ein komplettes, kompilierbares Programm (von mir aus ohne die LCD 
Funktionen)
Bei deinem Problem sind die Details wichtig! Auch die, die du nicht 
zeigst.

von Daniel V. (danvet)


Lesenswert?

Malte schrieb:
>
> Compiler ist wie gesagt der interne von ICCAVR 8.01.
> Aber der Compiler muss ja irgendwie dem kleinen 8-Bit Controller die
> 16-Bit-Werte beibringen. Da es mit 16Bit geht, dachte ich, er würde auch
> den 32Bit Wert schön zerlegen und in getennten Registern dann behandeln
> aber irgendwie klappt das nicht.
>
> Der Code ist jetzt ein kleines Extrakt und oft kann der Fehler ja auch
> woanders stecken. Nur in diesem Fall ist es ja recht einfach: die
> Ausgabefunktion funktioniert auf dem LCD 1A. D.h. dadurch kann ich den
> 16-Bit Inhalt von current gut visualisieren.
>
> Ich habe jetzt mal 32700 eingeben --> Ausgabe 327. Geht. Dann 32800 bei
> current_avr. Ausgabe über current --> 327. Spricht ja dafür, dass er
> current_avr als int16_t und nicht als int32_t ansteuert...
>
> Verstehe ich einfach noch nicht. Naja, ich muss jetzt eh mal los und
> vielleicht fällt der Groschen, wenn man an etwas anderes denkt :)
>
> Danke euch!

Aaalso, ich hab hier den ICCAVR8.01.07, wenn ich das hier mache:
1
long current_avr;
2
int current;
3
4
current_avr = 100000;
5
current_avr = current_avr / 100;
6
current = (int)current_avr;

und im Debugger mir die Ergebnisse anschaue, dann erhalte ich für 
current = 1000.

Am Compiler liegt es NICHT!

Wie gesagt: "int16_t" oder "int32_t" versteht dieser Compiler NICHT! Wie 
hast du diese Typdefinitionen definiert?

Bitte wie schon offt erwähnt: Kompletter Code posten!

von Daniel V. (danvet)


Lesenswert?

Ja und sogar das:
1
long current_avr;
2
int current;
3
4
current_avr = 100000;
5
current = current_avr / 100;

bekommt er richtig hin...

von Daniel V. (danvet)


Lesenswert?

Ach ja, der Vollständigjkeit halber:
1
char text[20];
2
...
3
...
4
itoa(text,current,10);

Liefert natürlich das richtige Ergebnis, nämlich "1000".

Wenn man current_avr als "int" deklariert, dann kommt in der Tat für 
current -310 raus, wer hätte das gedacht...

von Malte (Gast)


Lesenswert?

Erstmal danke!
Sorry, ich konnte nicht früher antworten.

Mein Code sind 400 Zeilen... ich müsste erstmal etwas darauf 
extrahieren, damit es hier im Forum kompiliert werden kann. Ich kann 
auch alles posten, aber wird wahrscheinlich etwas unübersichtlich.
Ich müsste also erstmal einen Extrakt bauen, mach ich dann noch.

Der Rest des Codes lief ja auch solange ich in 16Bit Bereichen blieb.

Die int32_t definition habe ich wie folgt gemacht:

typedef signed char int8_t;
typedef signed short int16_t;
typedef signed long int32_t;

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;

Ich probiere jetzt erstmal alle Tipps hier aus und dann melde ich mich 
wieder.

Ich finde es super, wie schnell hier einem geholfen wird. Danke nochmal 
an alle!
Wenn ich nicht weiterkomme werde ich auf jeden Fall den Codes 
extrahieren und kompilierfähig posten!

VG, Malte

von Malte (Gast)


Lesenswert?

Ich glaube ich habe es.

Es war ein Doppelfehler:

Zum einen kann itoa nur 16Bit. Das hatte ich mir schon gedacht, aber 
beim Spielen dann doch ab und an auch 32Bit übergeben und das ging 
natürlich nicht.

Dann hatte ich noch einen 2ten typedef, da stand short statt long.

Die beiden Kombinationen führten dazu, dass nix klappte.

Jetzt sieht es sehr gut aus. Weder das "L" ist notwendig noch irgendwas. 
Es scheint zu gehen :)

Danke nochmals!

VG, Malte

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.