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
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...
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.
Ein asm volatile("nop") reicht aus. Optimierung ausschalten ist keine Lösung, sondern ein häßlicher Workaround.
@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.
@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.
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
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 | }
|
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.
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
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.