Forum: Mikrocontroller und Digitale Elektronik Timer0 bei Bedarf


von steffen (Gast)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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 :)

von Mh. M. (mhm)


Lesenswert?

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...

von steffen (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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

...

von Hannes L. (hannes)


Lesenswert?

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?

...

von steffen (Gast)


Lesenswert?

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. 
:-)

von spess53 (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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.

...

von steffen (Gast)


Lesenswert?

ja und das hab ich schon mehrfach und eineige dokus gelesen. nur leider 
startet der timer immer automatisch :-(

von Hannes L. (hannes)


Lesenswert?


von Stefan W. (wswbln)


Lesenswert?

...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?

von steffen (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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.

...

von Hannes L. (hannes)


Lesenswert?

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?

von Hannes L. (hannes)


Lesenswert?

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"

...

von steffen (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von steffen (Gast)


Lesenswert?

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

von Stefan W. (wswbln)


Lesenswert?

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...

von Hannes L. (hannes)


Lesenswert?

> 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
Noch kein Account? Hier anmelden.