Hallo zusammen,
sorry für diese Timer Frage, aber irgendwie versteh ich das nicht so
richtig. Ich möchte einen Timer per Tastendruck einschalten und wenn die
Zeit abgelaufen ist wieder ausschalten. Wie kann ich das per Assembler
machen? Muss ich da einen Interrupt setzen?
Danke für die Hilfe.
Steffen
Mit welchem Mikrocontroller möchtest du denn das machen?
Und wie lange soll der Timer0 denn laufen?
Und wie möchtest du erkennen, dass der Timer0 noch nicht läuft, gerade
läuft oder abgelaufen ist?
Ich denke das Projekt ist noch nicht ganz durchdacht :)
Ja, dafür musst du einen Interrupt verwenden, denn anders den Timer
abzufragen ist ziemlich aufwändig (falls es überhaupt möglich ist ohne
Interrupt). Du könntest z.B. den Pin an dem der Taster hängt mit einem
Timer pollen und sobald der Taster gedrückt wurde zählst du eben eine
Variable hoch, bis die von dir gewünschte Zeit erreicht ist. Kannst
natürlich auch den Tastaer irgendwie anders abfragen und dann den Timer
starten bzw. stoppen, kommt drauf an wie dein Programm ist...
Hallo und danke für die schnelle antwort.
na das soll mit einem mega8 laufen. das soll eine art nachlaufsteuerung
werden. d.h. ich schalte per taster ein und wieder aus. wenn man nicht
ausschaltet dann soll der Timer das nach x sekunden machen. was mir
fehlt ist, wie schaltet man den timer ein und wieder aus?
danke & gruß steffen
steffen schrieb:> Hallo zusammen,>> sorry für diese Timer Frage, aber irgendwie versteh ich das nicht so> richtig. Ich möchte einen Timer per Tastendruck einschalten und wenn die> Zeit abgelaufen ist wieder ausschalten.
Das Wort "Timer" kann verschiedene Bedeutungen haben. Timer0 ist eine
Hardware-Einheit im AVR, die Takte zählt und Interrupts auslösen kann.
Du willst aber eine Art Eieruhr realisieren. Der Timer0 kann dazu
hilfreich sein, ist aber alleine erstmal untauglich weil er zu schnell
ist.
> Wie kann ich das per Assembler> machen?
Da gibt es verschiedene Möglichkeiten. Im Prinzip macht man sich da
einen geeigneten Zeittakt, in dem man eine Count-Down-Variable prüft und
herunterzählt. Ist sie schon 0, dann lässt man sie in Ruhe, ist sie
nicht 0, dann zählt man sie herunter. Wird sie dabei 0, dann schaltet
man aus. Bei Tastendruck schaltet man ein und setzt die Zählvariable auf
Startwert.
> Muss ich da einen Interrupt setzen?
Ein Timer-Interrupt ist zum Erzeugen des Zeitnormals (Zeittaktes) und
zum Entprellen des Tasters sehr hilfreich. Ich würde es nicht ohne
Timer-Interrupt machen wollen.
>> Danke für die Hilfe.> Steffen
...
steffen schrieb:
...
> was mir> fehlt ist, wie schaltet man den timer ein und wieder aus?
Falsche Frage...
Du solltest Dich mehr dafür interessieren:
- Wie erzeuge ich mit einem Timer einen Zeittakt?
- Wie entprelle ich mit einem Timer Tasten?
- Wie reagiere ich auf Tastendruck?
- Wie programmiere ich einen Count-Down?
...
ja genau da liegt mein problem. ich versteh nicht wie man den timer ein
oder ausschalten kann. das mit der zeittberechnung und der dauer eines
impulses versteh ich. nun fehlen mir nur noch die befehle wie ich den
timer mit einer taste einschalte und wenn die zeit rum ist wieder aus.
:-)
steffen schrieb:> ja genau da liegt mein problem. ich versteh nicht wie man den timer ein> oder ausschalten kann. das mit der zeittberechnung und der dauer eines> impulses versteh ich.
Das glaub' ich nicht, Du unterscheidest vermutlich noch nicht zwischen
Timer und Timer (Timer als Hardware-Teil des Mega8 und Timer als
Eieruhr).
> nun fehlen mir nur noch die befehle wie ich den> timer mit einer taste einschalte
Die gibt es nicht, die musst Du Dir selbst basteln. Die Hardware-Einheit
Timer0 hat einige "Schalter", mit denen sie bedient wird. Diese liegen
als Register im I/O-Bereich des AVRs und können per Software bedient
werden. Und diese Schalter sind im Datasheet des Mega8 (oder des
betreffenden anderen AVRs) haarklein beschrieben. Also Datasheet
besorgen (gibts kostenlos bei Atmel), lesen, verstehen und danach
handeln.
> und wenn die zeit rum ist wieder aus.
Durch den Befehl CBI, wenn die Ausschaltbedingung erreicht ist.
...
...Hannes hat in seiner Auflistung weiter oben noch zwei wichtige Punkte
vergessen:
- wie erstelle ich eine Anforderungsspezifikation (und wenn's nur eine
Stichpunktliste ist, was das Gerät genau machen soll) und
- wie erstelle ich einen Programmablaufplan (nach welcher "Religion"
auch immer: Nasi-Schneider oder sonstwas).
Soll der "Timer" z.B. nachtriggerbar sein?
steffen schrieb:> ja und das hab ich schon mehrfach und eineige dokus gelesen. nur leider> startet der timer immer automatisch :-(
Wieso leider??
Also ich würde das Vorhaben so lösen:
- Mit einem Timer im CTC-Modus einen Zeittakt von 20 ms erzeugen. Es
wird also alle 20 ms ein Interrupt ausgelöst, und das immer, also egal,
ob die "Zeit läuft" oder ob das Ding in Bereitschaft ist.
- In diesem Interrupt würde ich die Tasten entprellen Entprellung
und einen Vorteiler laufen lassen, der mir jede 50. Runde (alle 1,00
Sekunde) eine Routine zum Bedienen des Count-Downs (des Software-Timers)
aufruft.
- In dieser würde ich den Timeout-Zähler auf 0 prüfen. Ist er 0, bin ich
fertig. Ist er nicht 0, würde ich ihn vermindern. Wird er dabei 0, dann
würde ich mit CBI Schaltport,Schaltbit den Ausgang abschalten.
- In der Mainloop würde ich die Tastenflags prüfen, die von der
Entprellroutine im Hintergrund bereitgestellt werden. Signalisiert ein
Tastenflag einen neuen Tastendruck, dann wird die zugehörige Aufgabe
erledigt. Bei der Starttaste ist das das Einschalten des Schaltports
(mit SBI Schaltport,Schaltbit) und das Setzen des Count-Down-Zählers auf
den Startwert (LDI CDZ,Startwert). Und natürlich noch das Entwerten
(Rücksetzen) des Tastenflags, denn der Job ist ja erledigt. Den Rest der
Mainloop würde ich den Mega8 bis zum nächsten Interrupt schlafen lassen.
- In der Initialisierung (Reset-Routine) würde ich den Stackpointer, die
I/O-Ports und den Timer initialisieren, dazu noch ein paar Kleinigkeiten
wie z.B Sleep-Mode IDLE.
Mit diesem Konzept hätte ich dann später alle Freiheiten, das Programm
zu erweitern, ohne dass ich bereits realisierte Funktionalität wieder
ändern muss.
...
Stefan Wimmer schrieb:> ...Hannes hat in seiner Auflistung weiter oben noch zwei wichtige Punkte> vergessen:>> - wie erstelle ich eine Anforderungsspezifikation (und wenn's nur eine> Stichpunktliste ist, was das Gerät genau machen soll) und> - wie erstelle ich einen Programmablaufplan (nach welcher "Religion"> auch immer: Nasi-Schneider oder sonstwas).
Richtig, aber darauf hatte ich keinen Bock, da ich das erst in einem
anderen Thread sehr deutlich getan habe:
Beitrag "Re: Verzweigungen">> Soll der "Timer" z.B. nachtriggerbar sein?
ich seh da nicht durch. wenn ich über interrupt den timer nehme
blockiert der das ich die tasten drücken kann. is mir bissel zu viel.
ich nehm für meine schaltung einfach einen externen zeitbaustein.
unabhängig vom atmega.
steffen schrieb:> ich seh da nicht durch.
Deine Vorstellungswelt ist falsch.
Du lebst in der Vorstellung, dass du den Timer startest und stoppst.
Aber das tust du nicht! Der Timer läuft die ganze Zeit durch und
generiert mit seinem Interrupt ein regelmässiges Signal.
Analogie:
Deine Stoppuhr am Handgelenk.
Die Feder im Inneren läuft die ganze Zeit und generiert ein
Zehntel-Sekunden Signal. Drückst du den Startknopf, wird der Zeiger an
die Uhrenmechanik gekoppelt und der Zeiger beginnt zu ticken. Drückst du
den Stopp-Knopf, so wird der Zeiger von der Uhrenmechanik wieder
entkoppelt und der Zeiger bleibt stehen. Aber die eigentliche
Uhrenmechanik läuft die ganze Zeit weiter unabhängig davon, ob der
Zeiger an der Mechanik hängt oder nicht.
Genauso kann man das programmierern. Der Timer Baustein in deinem
Programm läuft die ganze Zeit durch. In der ISR wird eine Variable
abgeprüft, ob sie 1 oder 0 ist. Ist sie 1, dann wird die Zeitvariable,
die angibt wieviel Zeit noch verstreichen soll bis 0 erreicht ist, immer
erniedrigt. Ist die Variable 0, dann passiert gar nichts (zumindest
nicht mit deiner Zeitsteuerung)
Ein Tastendruck für Start setzt jetzt einfach die Variable auf 1 und
koppelt so, bildlich gesprochen, den Zeiger ans Uhrwerk. Ein anderer
Tastendruck setzt besagte Variable auf 0, und entkoppelt so den Zeiger
wieder vom Uhrwerk. Anstelle eines 2.ten Tastendrucks kann sich
natürlich auch die Zeitsteuerung selber den Takt abdrehen. Jeder der
will kann besagte Variable auf 0 setzen und so die Eieruhr anhalten.
Aber der Timer läuft weiterhin durch und erzeugt regelmässige ISR
Aufrufe. Der wird nie ausgeschaltet.
ok, dann geht das bei mir nicht über interrupt, oder ich kann für die
tast keinen interrupt nehmen. so lange der timer läuft blokiert er mir
alles :-(
hier noch mal das komplette programm:
1
main: ; hier beginnt das Hauptprogramm
2
3
ldi temp, LOW(RAMEND)
4
out SPL, temp
5
ldi temp, HIGH(RAMEND)
6
out SPH, temp
7
8
ldi temp, 0x00
9
out DDRD, temp
10
11
ldi temp, (1<<ISC01) ; INT0 auf fallende Flanke konfigurieren
12
out MCUCR, temp
13
14
ldi temp, (1<<INT0) ; INT0 aktivieren
15
out GICR, temp
16
17
ldi temp, (1<<CS02) | (1<<CS00) ; Teiler 1024
18
out TCCR0, temp
19
20
clr SubCount
21
22
ldi ZL,low(daten) ; der Z-Zeiger wird hier exclusiv
23
ldi ZH,high(daten) ; für die Datenadressierung verwendet
24
25
ldi r17, 0
26
27
sei ; Interrupts allgemein aktivieren
28
29
loop: rjmp loop ; eine leere Endlosschleife
30
31
taste1:
32
cpi r17, 1 ;R17 auf 1 prüfen
33
breq aus ;breq = gleich 1
34
brne ein ;brne = ungleich 1
35
reti
36
37
ein:
38
ldi temp, 0xFF ;als Ausgang setzten
39
out DDRD, temp
40
41
sbi PORTD, 5 ;PD 5 = ein
42
43
ldi r17, 1 ;merken 1 = auf
44
ldi temp, 1
45
46
rcall EEPROM_write ;im EEprom speichern
47
48
ldi temp, 1<<TOIE0 ; TOIE0: Interrupt bei Timer Overflow
Aua aua!
Wenn das das komplette Programm ist, dann fangen wir mal ganz vorne an:
Wo ist die Interruptvektortabelle?
Zum Rest werden sicher andere noch gebührend Stellung nehmen...
> ok, dann geht das bei mir nicht über interrupt, oder ich kann für die> tast keinen interrupt nehmen. so lange der timer läuft blokiert er mir> alles :-(
Schau Dir nochmal die Interrupt-Sprungtabelle Deines ersten Listings an.
Du hast alle unbenutzten Zeilen auskommentiert, wodurch die Platzhalter
(reti) verloren gingen und die Sprünge nicht mehr zu den
Interruptquellen passen. Daher landet Dein Timer-ISR-Sprung auf dem
Platz des Ext-Int1. Da Dir dadurch 16 Platzhalter fehlen, beginnt Dein
Programm bereits in dem Adressbereich, der für die Interrupt-Sprünge
reserviert ist. Tritt nun das Ereignis für den Timer-Interrupt auf, so
wird einfach mitten in den Initialisierungscode gesprungen, was
natürlich in die Hose geht.
> hier noch mal das komplette programm:
Das ist nicht komplett, da fehlt der ganze Deklarationsbereich und die
Interrupt-Sprungtabelle. Da man nicht sieht, ob Du die Fehler in der
Sprungtabelle beseitigt hast, kann man auch nicht wissen, ob es
funktionieren könnte.
Aber unabhängig davon:
Wenn ich Dein Programm sehe, muss ich davon ausgehen, dass Du keinen
meiner oben genannten Links verfolgt, gelesen und verstanden hast.
Tasten fragt man nicht mit externen Interrupts ab, das macht man mit
einer Entprellroutine im Timer-Interrupt. Da dieses Thema hier schon
hunderte mal durchgekaut wurde, verweise ich auf das Wiki
Entprellung. Dort gibt es weiterführende Links zu Beispielen und
Diskussionen.
Da man zu diesem Zweck sowiso einen Timer braucht, lohnt es sich, seine
Interrupt-Frequenz so zu wählen, dass sie zum Entprellen und zum
Bedienen des Time-Outs (das Du cool "Timer" nennst) geeignet ist.
Alles Andere haben Karl-Heinz und ich oben bereits genannt. Lies diesen
Thread einfach noch mal von vorn. Und lies diesmal gründlich und
verfolge die Links.
Ehe Du einen weiteren (unsinnigen) Quelltext postest, solltest Du
erstmal über das Konzept nachdenken.
...