Forum: Mikrocontroller und Digitale Elektronik For-Schleifen als Zeitglied verschachteln


von Zander (Gast)


Lesenswert?

Hallo zusammmen,

ich hoffe jemand kann mir bei meinem Problem weiterhelfen. Habe schon 
diverse Foren durchsucht, aber leider nichts passendes gefunden.

Ich möchte über einen ATMega8, welchen ich unter AVR Studio programmiere 
(Compiler ist der Gnu Compiler) zwei LED´s auf meinem 
Funk-Evaluationsboard von Pollin als Wechselblinker betreiben.

Hier mal der Quellcode:

#define   F_CPU 12000000
#include  <avr/io.h>
#include   <stdio.h>
#include   <inttypes.h>
#include   <stdint.h>
#include  <util/delay.h>

int a, b, c, d;

int main()
{
   while(1)
     {
     PORTD = (1<<PD5);              // LED1 an
     for (a=1; a<=1000; a++)        // warte eine gewisse Zeit
         {
         for (b=1; b<=10000; b++)
            {
            }
         }
     PORTD = (1<<PD6);          // LED2 an
     for (c=1; c<=1000; c++)       // warte eine gewisse Zeit
  {
  for (d=1; d<=10000; d++)
     {
            }
     }
}

Kurz zum Programm:
In einer Endlosschleife soll zuerst PD5 auf High gesetzt werden, somit 
ist LED1 an, danach wird via zweier for-Schleifen eine gewisse Zeit 
gewartet und danach das ganze für LED2 wiederhohlt. Somit sollte sich 
ein Wechselblinker ergeben. Zeitwerte müssten noch angepasst werden, 
damit man auch was sieht...

Wenn ich den Code Compiliere und ihn unter AVR Studio durchlaufen lasse, 
so lässt er die for-Schleifen immer aus, als ob sie nicht da wären und 
springt somit von LED1 nach LED2 setzen hin und her, sodass beide LED´s 
"dauerhaft" an sind.

Habe auch schon mit Freunden und Dozenten darüber geschaut, jedoch hatte 
keiner eine Antwort.
Kann es sein, dass der Compiler die Schleifen einfach wegoptimiert, da 
hier "nichts" gemacht wird?

Mir ist bewusst, dass es viele bessere Möglichkeiten gibt einen 
Wechselblinker zu programmieren, jedoch hätte ich es zur Übung gerne auf 
diese Art geschafft.

Ich hoffe, dass meine Angaben soweit verständlich sind, da ich absoluter 
Neuling auf dem Gebiet bin.

Zander

von Micha B. (chameo)


Lesenswert?

Nun, da in den Schleifen keine Befehle abgearbeitet werden, wird der 
Compiler sie schlicht wegoptimieren. Setz doch mal ein delay_ms(1) in 
die Schleifen.

Besser wär's aber, Du schaust Dir im Tutorial mal das Kapitel über Timer 
an...

von Matthias (Gast)


Lesenswert?

Der compiler optimiert die Schleifen weg, weil da nichts drin steht. 
Loesung: optimierung aussschalten oder den compiler zwingen, in den 
Schleifen was zu machen, zB ne volatile variable den aktuellen 
Schleifenzehlerwert annehmen lassen.

von der mechatroniker (Gast)


Lesenswert?

Ein asm volatile("nop") reicht aus. Optimierung ausschalten ist keine 
Lösung, sondern ein häßlicher Workaround.

von Zander (Gast)


Lesenswert?

@Micha B.
über die delay_ms-Funktion funktionierts, das hatte ich schon 
getestet...

@Matthias:
Hab leider keine Ahnung wo ich die Optimierung aussschalte, bzw. was 
eine "volatile" ist.

von Micha B. (chameo)


Lesenswert?

@zander
es geht darum, dass überhaupt etwas in den Schleifen drin steht. Das 
delay_ms war lediglich ein Beispiel.

Sonst nimm halt das 'asm volatile("nop")' welches der mechatroniker 
vorgeschlagen hat.

von Peter D. (peda)


Lesenswert?

Zander wrote:
> @Micha B.
> über die delay_ms-Funktion funktionierts, das hatte ich schon
> getestet...

Warum willst Du dann die optimale, genaue und compilermäßig einwandfreie 
Lösung durch ne inkompatible, ungenaue Krücke ersetzen ???


Wenn Du das Delay änderbar haben willst, dann nimm ein definiertes Delay 
(z.B. 1ms) und mach ne Schleife (n * 1ms) drumrum.


Peter

von Matthias (Gast)


Lesenswert?

Mit volatile kannst du den compiler zwingen, eben jenen mit volatile 
markierten Befehl definitiv auszufuehren, auch wenn sein optimierer 
sagt, dass es keinen sinn macht. Macht man zB, wenn in Interfaces zu 
bestimmten Zeiten Register gelesen werden muessen, obwohl mit dem Wert 
rein gar nichts zu machen ist. Aber um sicherzustellen, dass das 
Register, warum auch immer, gelesen wird, markiert man das mit volatile.

in deinem fall ginge sowas:
1
int loopcnt;
2
volatile int freaky_cnt;
3
4
for (loopcnt = 0; loopcnt < 10000; loopcnt++)
5
    {
6
    freaky_cnt = loopcnt;
7
    }

von Johannes M. (johnny-m)


Lesenswert?

Matthias wrote:
> Mit volatile kannst du den compiler zwingen, eben jenen mit volatile
> markierten Befehl definitiv auszufuehren,
volatile hat nichts mit Befehlen zu tun, zumal es in C keine "Befehle" 
in dem Sinne gibt. volatile ist ein sogenannter Typqualifizierer.

volatile (auf deutsch "flüchtig") besagt lediglich, dass die so 
gekennzeichnete Variable sich außerhalb des Zugriffsbereichs des 
Compilers bzw. des eigentlichen Programms ändern kann (z.B. durch ein 
asynchron auftretendes Hardware-Ereignis, einen Interrupt). Zugriffe auf 
normale Variablen, die nur vom Programm selbst geändert werden, können 
weggelassen werden, wenn der Compiler sieht, dass sich die Variable seit 
dem letzten Zugriff gar nicht geändert haben kann oder einfach nicht 
weiter verwendet wird (und das ist genau das, was in Zählschleifen 
passiert, da mit dem Wert der Variablen gar nichts weiter gemacht wird 
und der Compiler so den aus seiner Sicht überflüssigen Code 
rausschmeißt). Ist eine Variable mit dem Typqualifizierer volatile 
versehen, dann weiß der Compiler, dass er alle Zugriffe auf das Objekt 
durchführen muss, da es sein kann, dass die Variable von außen verändert 
wird oder dass ihr Wert von außerhalb des Programms benötigt wird.

Ein gutes Beispiel für die (für den Programmierer allerdings versteckte) 
Anwendung von volatile ist die Definition der I/O-Register der 
Mikrocontroller (die ja für den Compiler letztendlich auch nur 
irgendwelche Variablen bzw. Speicherstellen darstellen, denn der 
Compiler kennt ja den Aufbau des Controllers nicht), die allesamt intern 
als volatile qualifiziert sind.

von Zander (Gast)


Lesenswert?

Danke an alle für die Antworten, ihr habt mir damit sehr weitergeholfen.

@Peter Dannegger
Auch wenns so ne Krücke ist, hab ich jetzt doch wieder was dazugelernt. 
Darum gehts doch ;-)

Zander

von Ralph (Gast)


Lesenswert?

Grundsätzlich
Mit FOR schleifen eine Zeitbasis zu schaffen ist so ziemlich die 
ungeignetste Möglichkeit.
Das Zeitverhalten ist unkalkulierbar, und das sogar im extremen wenn 
Interrupts  genutzt werden.

Für Wartezeiten IMMER einen Hardware Timer nutzen, alles andere ist 
Müll.

von Michael U. (amiga)


Lesenswert?

Hallo,

mit FOR-Schleifen eine "Zeitbasis" zu schaffen ist vermutlich der 
einfachste Weg zu einer Verzögerung zu kommen.

Weder genau noch elegant, für einen Anfänger aber wohl ideal 
verständlich.

Ich habe früher (tm) jemandem, der irgendwie programmieren auf einem C64 
in Basic lernen wollte, damit beschaftigt, daß er eine Uhr programmieren 
sollte.

Keine genau gehende sondern eine überhaupt gehende.

Brachte Verständbis für For-Next-Schleifen, für If-Then-Abfragen, für 
Ausgaben mit Print.

Dann um ein brauchbares Ausgabeformat gebeten, also mit : dazwischen und 
führenden Nullen, wenn nötig.

Damit waren Strinvormatierungen ziemlich gut zu erschlagen.
Dann konnte man über genaue Laufzeiten nachdenken.

Wenn ein Anfänger eine LED blinken lassen will, dann soll diese doch 
bitte erstmal blinken. Was nutzt ihm der Kampf mit dem Timer und seinen 
Problemen, wenn er letztlich nichts davon zu sehen bekommt.

Nur so als Gedankengang...

Gruß aus Berlin
Michael

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.