mikrocontroller.net

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


Autor: Malte (Gast)
Datum:

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

Autor: A. K. (prx)
Datum:

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

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

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

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

Autor: Malte (Gast)
Datum:

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

Autor: Malte (Gast)
Datum:

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

Autor: mork (Gast)
Datum:

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

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

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

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

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

Autor: Daniel V. (danvet)
Datum:

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

Autor: mork (Gast)
Datum:

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

Autor: Daniel V. (danvet)
Datum:

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

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

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

Autor: mork (Gast)
Datum:

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

Autor: mork (Gast)
Datum:

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

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

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

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

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

Autor: Daniel V. (danvet)
Datum:

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

Autor: mork (Gast)
Datum:

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

Autor: Tom M. (Gast)
Datum:

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

Autor: Malte (Gast)
Datum:

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

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

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

Autor: Tom M. (Gast)
Datum:

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

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

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

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht 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:
long current_avr;
int current;

current_avr = 100000;
current_avr = current_avr / 100;
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!

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja und sogar das:
long current_avr;
int current;

current_avr = 100000;
current = current_avr / 100;

bekommt er richtig hin...

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach ja, der Vollständigjkeit halber:
char text[20];
...
...
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...

Autor: Malte (Gast)
Datum:

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

Autor: Malte (Gast)
Datum:

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

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.