Hi...
Du wirst um den Timer-Interrupt nicht herum kommen...
Ansonsten wird das viel zu kompliziert.
Versuchs zuerst mit dem Timer0-Overflow, da ist das Wenigste zu
beachten. Stell den so ein, dass der alle paarhundert Takte ausgelöst
wird (erster Versuch: (Vorteiler)64 mal (Zählumfang)256). Wenn du mit
dem klar kommst, wirst du sehen, dass ein Programm mit Interrupts viel
einfacher wird als diese "WaitXYZ"-Aufrufe. Außerdem schafft der
Timer-Int die Basis dafür, mehrere verschiedene Programmteile
(scheinbar) gleichzeitig abzuarbeiten. Hängst du bei einem Programm mit
Wait-Aufrufen in der Warteschleife, dann kannst du nix Anderes machen,
der Prozessor ist mit der Warteschleife voll ausgelastet. Vergiss also
diese Programmiermethode... (möglichst schnell)
Deine Taste braucht übrigens neben dem Zähler noch eine Entprellung.
Der Externe Interrupt ist dazu denkbar ungeeignet, der würde bei einem
(mechanisch erzeugten) Tastendruck etliche male aufgerufen.
Geh also andersrum an das Programm ran:
- Bau kein Programm, in das du zum Verzögern Zeitschleifen
aufrufst,
- Bau einen Zeittakt (Timer-Int), in dem du Programm abarbeitest...
Dazu ist das "ganz spezielle Lauflicht" allerdings denkbar
ungeeignet...
Grundlagen zum Timer-Int findest du im oben erwähnten Blink-Programm.
Fang klein an:
- Int-Vektoren zu Programmbeginn anlegen (siehe Datenblatt
oder Include-Datei ganz unten),
- Reset-Routine schreiben, in der Folgendes gemacht wird:
- Stackpointer initialisieren,
- Ports initialisieren,
- Timer0 am Prozessortakt 1:64, (3 in tccr0 schreiben, Datenblatt
Seite 70)
- Timer0-Overflow aktivieren, (toie0 in timsk setzen, DB S.70)
- mit SEI Interrupts freischalten,
- Ein Hauptprogramm (Schleife) schreiben, in dem (vorerst) nix
gemacht wird:
main: rjmp main
Später kommt da noch Programm dazu, ist das fertig, dann schickt
es den AVR schlafen...
- eine ISR (Interrupt-Service-Routine) schreiben, dort musst du:
- SREG sichern,
- (später mal) Timer-Reload-Wert in tcnt0 schreiben,
- (später mal) ein Register hochzählen, welches vom Hauptprogramm
als "Stopuhr" genutzt werden kann (akt. Wert merken,
Wartezeit addieren, warten bis zum Gleichstand, geht auch mit
zwei Registern (16 Bit) für längere Wartezeiten),
- den Code meiner Hauptschleife (außer Warteschleife, denn das
macht jetzt der Timer, indem er den Programmteil periodisch
aufruft) einfügen (ohne Rücksprung am Ende zum Codebeginn),
- später mal weiteren Code einfügen, z.B. Tastenabfrage, aber
bitte nix mit Verzögerung! (Weitere Tricks folgen später, die
würden dich jetzt nur unnötig verwirren),
- SREG wiederherstellen,
- die ISR mit RETI abschließen.
Du musst allerdings darauf achten, dass zwischen den einzelnen Aufrufen
des Timer-Int genügend Zeit zur Abarbeitung der ISR bleibt (und auch
noch für das spätere Hauptprogramm!). Aber dabei ist der Simulator des
AVR-Studios dein Freund...
Wenn das alles läuft, kannst du ja mal darüber nachdenken, wie man
andere (ganz besondere?) Lauflichter so umstrukturiert, dass sie bei
periodischem Aufruf des Programmteils funktionieren.
Die Denkweise ist also völlig anders:
Der Timer-Interrupt gibt dir einen (recht genauen, zumindest von der
Länge der ISR unabhängigen) Takt vor, in dem der Programmteil, den man
sonst in einer Schleife (mit "Bremse") abarbeiten würde, zyklisch
aufgerufen wird. Brauchst du "Bremsen", so musst du halt die
ISR-Aufrufe zählen und deinen Programmteil überspringen, falls eine
Wartepause aktiv ist.
Viel Erfolg...
...HanneS...