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. :-)
Hi
>ich versteh nicht wie man den timer ein oder ausschalten kann.
Sieh dir mal im Datenblatt die Beschreibung der CS-Bits in TCCR0B an.
MfG Spess
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. ...
ja und das hab ich schon mehrfach und eineige dokus gelesen. nur leider startet der timer immer automatisch :-(
http://www.mikrocontroller.net/articles/AVR-Tutorial http://www.mikrocontroller.net/articles/AVR-Tutorial:_Timer http://www.mikrocontroller.net/articles/AVR-Tutorial:_Uhr ...
...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?
genau da seh ich nicht druch. ich hab das jetzt so mal getestet. nur irgendwie passiert nix. die ausgänge sollten wenigstens blinken.
1 | .include "m8def.inc" |
2 | |
3 | .def temp = r16 |
4 | .def leds = r17 |
5 | |
6 | rjmp main ;reset |
7 | rjmp taste1 ;Int0 |
8 | ;reti ;Int1 |
9 | ;reti ;TC2 Compare |
10 | ;reti ;TC2 Overflow |
11 | ;reti ;TC1 Capture |
12 | ;reti ;TC1 Compare A |
13 | ;reti ;TC1 Compare B |
14 | ;reti ;TC1 Overflow |
15 | rjmp timer0_overflow ;TC0 Overflow |
16 | ;reti ;Serial Transfer complete |
17 | ;reti ;UART Rx complete |
18 | ;reti ;UART Data Register |
19 | ;reti ;UART Tx complete |
20 | ;reti ;ADC |
21 | ;reti ;EEPROM Ready |
22 | ;reti ;Analog Comperator |
23 | ;reti ;2-wire Serial |
24 | ;reti ;SPM ready |
25 | |
26 | main: |
27 | ; Stackpointer initialisieren |
28 | ldi temp, HIGH(RAMEND) |
29 | out SPH, temp |
30 | ldi temp, LOW(RAMEND) |
31 | out SPL, temp |
32 | |
33 | ldi temp, 0xFF ; Port D auf Ausgang |
34 | out DDRD, temp |
35 | |
36 | ldi leds, 0xFF |
37 | |
38 | ldi temp, (1<<ISC01) ; INT0 auf fallende Flanke konfigurieren |
39 | out MCUCR, temp |
40 | |
41 | ldi temp, (1<<INT0) ; INT0 aktivieren |
42 | out GICR, temp |
43 | |
44 | |
45 | ldi temp, (1<<CS00)|(1<<CS02) ;Teiler setzen |
46 | out TCCR0, temp |
47 | |
48 | sei |
49 | |
50 | loop: rjmp loop |
51 | |
52 | taste1: |
53 | ldi temp, (1<<TOIE0) ; TOIE0: Interrupt bei Timer Overflow |
54 | out TIMSK, temp |
55 | reti |
56 | |
57 | timer0_overflow: ; Timer 0 Overflow Handler |
58 | out PORTD, leds |
59 | com leds |
60 | reti |
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?
Hier ist ein Beispiel einer Eieruhr, das allerdings etwas umfangreicher ist (7-Segment-Anzeige, Tastenmatrix, Piepser). Da solltest Du Dir erstmal die Interrupt-Sprungtabelle ansehen: http://www.mikrocontroller.net/attachment/23620/eieruhr1.asm Deine kann nämlich nicht funktionieren, da sie auskommentiert ist. Der zugehörige Thread (zum Nachlesen und Lernen) ist hier: Beitrag "Re: 7 Segmentanzeige falsch eingekauft, reagiert nur auf low" ...
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 |
49 | out TIMSK, temp |
50 | |
51 | reti |
52 | |
53 | aus: |
54 | ldi temp, 0 ; Timer aus |
55 | out TCCR0, temp |
56 | |
57 | ldi temp, 0xFF |
58 | out DDRD, temp |
59 | |
60 | cbi PORTD, 5 |
61 | cbi PORTD, 6 |
62 | |
63 | ldi r17, 0 |
64 | |
65 | reti |
66 | |
67 | tc0_o: |
68 | push temp ; temp 1 sichern |
69 | in temp,sreg ; SREG sichern |
70 | push temp |
71 | |
72 | inc SubCount ; Wenn dies nicht der 15. Interrupt |
73 | cpi SubCount, 15 ; ist, dann passiert gar nichts |
74 | brne end_isr |
75 | |
76 | rcall aus |
77 | |
78 | end_isr: |
79 | |
80 | pop temp |
81 | out sreg,temp ; sreg wieder herstellen |
82 | pop temp |
83 | reti ; das wars. Interrupt ist fertig |
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. ...
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.