Forum: Compiler & IDEs Anfänger: While-Schleife auf Atmega8


von Marc (Gast)


Lesenswert?

Guten Tag,

ich bin relativ neu was Microcontroller angeht und habe mir nach der 
Anleitung auf

http://s-huehn.de/elektronik/avr-prog/avr-prog.htm

den seriellen Programmieradapter für den Atmega8 aufgebaut.

Das Testprogramm funktioniert einwandfrei, und jetzt wollte ich, bevor 
ich das GCC-Tutorial durchgehe, noch einmal meine Uralt-c-Kenntnisse 
auffrischen.

An PC0 und PC1 hängen 2 LEDs und die wollte ich ganz doof durch 2 
while-Schleifen, in denen auf 60000 gezählt wird, abwechseln ein- und 
ausschalten (Ich weiss, dass das Programm albern ist, aber es ging mir 
wie gesagt erstmal nur darum, ein paar Zeilen C zu schreiben).

Wenn
1
PORTC = ...
 innerhalb der Schleifen steht, funktioniert das auch:
1
#include <avr/io.h>
2
#include <stdint.h>
3
4
int main (void) {
5
6
    uint64_t x=0,y=0;
7
    DDRC = 0xff;
8
   
9
while(1) {
10
11
    x=0;
12
        while (x<60000) {
13
                         x++;
14
                         PORTC = 0x00;   }
15
16
17
    y=0;
18
        while (y<60000) {
19
                         y++;
20
                         PORTC = 0xff;   }
21
22
        }
23
return 0;
}

wenn ich es jeweils danach ausführen lasse (was mir irgendwie sinnvoller 
erscheint), dann nicht mehr:

1
#include <avr/io.h>
2
#include <stdint.h>
3
4
int main (void) {
5
6
    uint64_t x=0,y=0;
7
    DDRC = 0xff;
8
9
10
while(1) {
11
12
    x=0;
13
        while (x<60000) {
14
                         x++;
15
                             }
16
PORTC = 0x00;
17
18
    y=0;
19
        while (y<60000) {
20
                         y++;
21
                             }
22
PORTC = 0xff;
23
          }
24
return 0;
25
}
Ich komme einfach nicht dahinter, woran es liegt.
Kann mir jemand auf die Sprünge helfen?

Viele Grüße!

Marc

von M. H. (kroggy)


Lesenswert?

Servus,
auch keine Ahnung. Versuch das mal so: volatile uint64_t x=0,y=0;

Eventl. Optimiert der Compiler da ein paar Sachen weg.

von Marc (Gast)


Lesenswert?

Hi,

danke, so funktioniert es!

Allerdings blinkt das Ganze jetzt viel langsamer als vorher. Ich würde 
eher das Gegenteilerwarten, weil doch jetzt pro Schleifendurchgang 
weniger Befehle ausgeführt werden...

Jemand eine Idee?

von Rolf Magnus (Gast)


Lesenswert?

> An PC0 und PC1 hängen 2 LEDs und die wollte ich ganz doof durch 2
> while-Schleifen, in denen auf 60000 gezählt wird, abwechseln ein-
> und ausschalten (Ich weiss, dass das Programm albern ist, aber es
> ging mir wie gesagt erstmal nur darum, ein paar Zeilen C zu
> schreiben).

Albern würde ich nicht sagen. Die blinkende LED ist das "Hello World" 
der Mikrocontroller-Programmierung. Da deine while-Schleifen nichts tun, 
außer Zeit zu verbrauchen, nimmt der Optimizer das als Gelegenheit, sie 
komplett zu entfernen, weil das Programm dann das gleiche macht, nur 
viel schneller (und das ist ja die Aufgabe des Optimizers). Du solltest 
lieber die delay-Funktionen der avr-libc verwenden.

von Marc (Gast)


Lesenswert?

Danke Rolf, jetzt hat's 'klick' gemacht!
Schönen Abend wünsch ich euch beiden noch!

Marc

von M. H. (kroggy)


Lesenswert?

Langsamer ja,
liegt daran das es noch nie richtig funktioniert hat.

Grund: Optimierung.

Für Zeiten würde ich immer einen Timer nehmen, die delay Funktion kenne 
ich nicht.

Fürs basteln reicht es die Compiler Optimierungen ausschalten. Mit der 
Option -O0.
Alternative kannst solche schleifen Variablen auch global deklarieren, 
dann passiert da auch nichts.

von Rolf Magnus (Gast)


Lesenswert?

Jetzt hab ich in der Eile noch die Erläuterung des Unterschieds der 
beiden Varianten vergessen. PORTC ist volatile. Das sagt dem Compiler, 
daß jeder Zugriff darauf, der im Code steht, auch wirklich ausgeführt 
werden muß. In der ersten Variante steht, daß die beiden Schleifen 
jeweils 60000 mal nach PORTC schreiben sollen. In der zweiten Variante 
kann die Schleife wegoptimiert werden, weil kein volatile-Zugriff 
erfolgt.

Daß es deutlich langsamer ist, wenn x und y volatile sind, ist klar. Zum 
einen muß der Schleifenzähler nicht nur geschrieben, sondern auch 
gelesen werden, zum anderen sind die Variablen vom Typ uint64_t und 
damit 8 mal so groß. Dadurch müssen jetzt pro Schleifendurchlauf 8 
Speicherstellen geschrieben und gelesen werden, statt nur eine zu 
schreiben.
Warum nimmst du eigentlich so einen riesigen Datentyp?

von Marc (Gast)


Lesenswert?

ich hatte keine Ahnung, wie schnell so eine Schleife durchläuft, deshalb 
wollte ich wohl mit einer etwas größeren Zahl anfangen.
Nicht dass es so schnell geht, dass man nichts mehr wahrnehmen kann. 
Irgendwie so war wohl mein Gedanke...

Das mit delay hat übrigens funktioniert. Und danke auch nochmal für die 
weiteren Erklärungen - sehr hilfreich!

Grüße

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.