Hallo zusammen, ich hätte noch mal eine Frage: Ich habe nun drei verschiedene Lauflichter, die ich in Unterprogramme gegossen habe. Jeder Aufruf des UP ist EIN Lauflichtdurchlauf. D.h. im Kernprogramm muss in einer Schleife ständig mein Lauflichtunterprogramm aufgerufen werden. Nun würde ich gerne folgendes realisieren: Wenn ich eine bestimmte Taste drücke, (aber nicht gedrückt halte) soll ab diesem Zeitpunkt das erste Lauflicht in einer Loop aufgerufen werden, wenn ich dann die gleiche Taste nocheinmal kurz drücke, soll das andere Lauflichtprozedur in der Loop aufgerufen werden und das gleiche beim dritten Lauflicht. Beim vierten Tastendruck sollte wieder das erste Lauflicht in der Loop aufgerufen werden. So könnte ich durch Tastendrücke durch die einzelnen Programme durchsteppen. Ich nehme an, man braucht einen kleinen Zähler, der beim drücken der Taste hochgezählt wird, ab drei dann wieder auf Null gesetzt wird usw. Und in der Loop wird je nach Zählerstand die eine oder andere Prozedur angesprungen. Aber wie kann ich dieses durchsteppen realisieren? Möglichst ohne Interrupts, weil ich da noch gar nicht durchblicke. Vielen Dank Karl
"Möglichst ohne Interrupts, weil ich da noch gar nicht durchblicke." Dann ist das doch ein guter Zeitpunkt, damit anzufangen. Die externen Interrupts braucht man eher selten, aber die Timerinterrupts sind unverzichtbar, will man in seinem Programmablauf den Überblick behalten. In Deinem Fall brauchst Du ihn, um die Tasten zu entprellen und das hintereinander Drücken zu erkennen. Der Rest Deiner Aufgabe ist eine Statemaschine, z.B. Du hast eine Variable, die die verschiedenen Zustände kennzeichnet und je nach Zustand auf einen anderen Wert (=Zustand) wechseln kann. Am elegantesten könnte man beides mit meinem Sheduler-Beispiel machen, aber da sollte man schon etwas Erfahrung mit den Timern und mit C haben. Peter
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...
Ups... @Peter: Das kommt davon, wenn man abgelenkt wird (Insulin-Spritzzeit, essen) und daher über eine Stunde zum Schreiben des Beitrags braucht... ;-) ...HanneS...
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.