Forum: Mikrocontroller und Digitale Elektronik Timer für 30 Minuten


von Carsten (Gast)


Lesenswert?

Hallo Ihr Wissenden...
Ich brauche alle 30 Minuten einen Interrupt auf meinem Attiny2313.
Kann mir mal kur jemand sagen, ob ich das mit dem Timer richtig
verstehe?

Maximale Teilung für den Timer ist 1024. Ergibt bei 4MHz 25,6µs ?

Wie bekomme ich jetzt eine halbe Stunde hin ?
Das wären decimal 703125 Impulse.
Muss ich die jetzt mit verschachtelten schleifen zählen?

von Alex (Gast)


Lesenswert?

Der Timer macht mit dem angegebenen Prescaler alle 25,6us einen
Zählschritt. Interrupts gibt es erst beim Überlauf!

siehe avrgcc-Tutorial

von Carsten (Gast)


Lesenswert?

Das heisst bei Timer 1 kann ich maximal 65535 Impulse zählen und kann
dann auf den Interrupt reagieren ?
Das würde bedeuten ich müsste Interrupt ca. 107 mal mitzählen und hätte
dann meine halbe Stund voll.

Stimmt das so ?

von ...HanneS... (Gast)


Lesenswert?

Er reagiert nicht auf den Int, er erzeugt ihn...

...

von Carsten (Gast)


Lesenswert?

Ja, HanneS...
hab mich etwas komisch ausgedrückt.
Stimmt das , dass ich für T1 dann OCIE1A in TIMSK setzen muss, wenn ich
einen Zählwert von 65104 vorgeben möchte ?
Wie bekomme ich den Vorgabewert in das Register ?

von Stift (Gast)


Lesenswert?

rtfm

von Carsten (Gast)


Lesenswert?

Wie bitte ???
Könnte das funktionieren ?

  ;Timer 0 initialisieren
  ldi  Temp1, (1<<CS02)|(1<<CS00);Systemtakt /1024
  out  TCCR0B, Temp1

  ;Timer 1 initialisieren
  ldi temp1, (1<<CS12)|(1<<CS10)  ;Systemtakt /1024 =(0,00256s)
  out TCCR1B, Temp1
  ldi temp1,0b11111110    ;High-byte von 65104
  out TCNT1H,temp1
  ldi temp1,0b01010000    ;Low-byte von 65104
  out  TCNT1L,temp1

  ;Timer-Interrupt aktivieren
  ldi Temp1, (1<<TOIE0)|(1<<OCIE1A);Für T0 Overflow- und T1
Vergleichs-Interrupt setzen
  out TIMSK,Temp1

von ...HanneS... (Gast)


Lesenswert?

Tja, nun wissen wir schon mal, dass du in ASM werkelst...

Warum du nun beide Timer initialisierst, kann ich nicht
nachvollziehen.

Wenn du den Überlauf-Int des Timers1 benutzt, solltest du beachten,
dass der Timer aufwärts zählt (beim AT90S2313, beim Tiny2313 habe ich
jetzt nicht nachgesehen), wenn du also 65104 einstellst, der Timer bei
65536 (=0) den Int auslöst, dann dauert das keine 65104 Zählschritte.

Ansonsten solltest du dir mal die Output-Compare-Funktion des Timer1
ansehen.

Alternativ:
Einen Timer mit einem 1s-Takt klappern lassen und in diesem INT ein
paar Register runterzählen, die bei Null auf Startwert gesetzt werden
und die von dir gewünschte Aktion auslösen.

Achja, RTFM = read The Fine/Fucking Manual

Ein Blick ins Datenblatt schadet sicher auch nicht... :)

...

von Carsten (Gast)


Lesenswert?

Jo, das mit dem Datenblatt hatte ich vorher schon getan.
Ich hatte das so verstanden, dass der Kamerad anfängt bei 0 und dann
hochzählt.
Dann kommt dieses Vergleichregister / Flag zum Zuge (siehe OCIE1A).
Den Timer 0 brauche ich für eine Tastenentprellung.

von ...HanneS... (Gast)


Lesenswert?

Ein Timer kann mehrere Dinge erledigen.

Timer0 läuft mit einer festen Frequenz (100...250 Hz) durch. In seiner
ISR werden die Tasten entprellt.
Was hindert dich daran, in dieser ISR eine weitere Variable (16...32
Bit) herunterzuzählen, deren Erreichen von 0 dein Vorhaben aktiviert
und die Variable wieder auf Startwert setzt. Damit kannst du alles mit
nur einem Timer realisieren.

...

von Carsten (Gast)


Lesenswert?

Ok, könnte ich tun.
Damit ändert sich aber nichts an dem Problem, dass ich es auch
verstehen möchte.

Außerdem ist dann die Zeit extrem von der Schleife abhängig.
So muss ich "nur" 108 mal eine Schleife durchlaufen, während ich
sonst einige mehr brauche.
Ausserdem muss ich auch gestehen, dass ich noch nie 32Bit gezählt
habe.
Da man aber nicht alles auf einmal lernen kann, haqb ich nu mit dem
Timer angefangen. :-)

von Carsten (Gast)


Lesenswert?

Mein Timer scheint nicht zu zählen.
Ich sehe zumindest nichts im AVR Studio an TCNT1

So hab ich den initialisiert:
  ;Timer 1 initialisieren
  ldi temp1, (1<<CS12)|(1<<CS10)|(1<<CTC1);Systemtakt /1024 =(0,00256s)
& Counter löschen wenn vergleich passt
  out TCCR1B, Temp1
  ldi temp1,0b11111110    ;High-byte von 65104
  out OCR1BH,temp1
  ldi temp1,0b01010000    ;Low-byte von 65104
  out  OCR1BL,temp1

  ;Timer-Interrupt aktivieren
  ldi Temp1, (1<<TOIE0)|(1<<OCIE1A);Für T0 Overflow- und T1
Vergleichs-Interrupt setzen
  out TIMSK,Temp1

Hab ich hier was vergessen ?

von Sebastian (Gast)


Lesenswert?

ohne |(1<<CTC1) geht es.

von Carsten (Gast)


Lesenswert?

Na prima...
just in dem Moment wo der Zähler zum Vorgabewert passt, ist das
Programm grade in einer Schleife, wo die Interrupts ausgeschaltet
sind.
Also vergleichen kann man pauschal vergessen, wenn man nicht explizit
und ausschließlich auf Interrupts wartet ?

Wie soll es dann möglich sein, auf eine Zeitspanne zu warten ?
HanneS schrieb dass ich zählen soll aber auch dieser Interrupt kommt
dann ja wohl eher unregelmässig.

von Alex (Gast)


Lesenswert?

Warum schaltest du in einer Schleife die Interrupts aus? Der Interrupt
kommt mit der Regelmäßigkeit eines Uhrwerks. Wenn deine Schleife
natürlich so lange die Interrupts sperrt, dass in der Zeit mehrere
auftreten, dann kommt es natürlich zum "Vergessen" von Interrupts.
Ein einzelner Interrupt wird sofort nach dem Reaktivieren der
Interrupts abgearbeitet.

Was Hannes geschrieben hat ist voll i.O., so löst man dein Problem.

von ...HanneS... (Gast)


Lesenswert?

Schleifen sind unregelmäßig, Timer-Interrupts nicht!
Abgesehen von der leicht variablen Int-response-time, aber das kann man
stabilisieren indem man den AVR schlafen schickt.

Int deaktivieren macht man eigentlich nur, wenn es absolut erforderlich
ist, z.B. beim Schreiben auf EEPROM. Jedenfalls nicht für irgendwelche
Schleifen.

...

von Carsten (Gast)


Lesenswert?

Nundenn...
ich habe mit einem Timer meine Tasten entprell.
Um das Ergebnis auszuwerten, ohne wieder andere Tastenwerte dazwischen
zu bekommen, muss ich zwischenzeitlich den Timer deaktivieren.

Hier ist meine Hauptschleife:
Loop:
  cli
  mov   temp1,key_press
  andi   temp1,0b00000100    ;nur PD2 auswerten
  cpi  temp1,0b00000100        ;wenn's passt, springen
  brne   PC+2
  rcall   start1

  mov   temp1,key_press      ;nur PD3 auswerten
  andi   temp1,0b00001000
  cpi  temp1,0b00001000
  brne   PC+2
  rcall  start2

  sei

  clr   key_press            ;Tasten löschen nach Aktion
  sleep
  rjmp  Loop

von Carsten (Gast)


Lesenswert?

...was ist los ?
sprachlos ?

von Mike (Gast)


Lesenswert?

Nein, manche müssen nur nebenbei noch Geld verdienen und werden im
Gegensatz zum Forum dort auch noch fürs Denken bezahlt!

von Carsten (Gast)


Lesenswert?

ich dachte ja nur weil eben noch alles so sonnenklar war...
...by the way...
Die Entprellroutine ist von Peter Dannegger, das cli und sei auch :-)

von ...HanneS... (Gast)


Angehängte Dateien:

Lesenswert?

Und wieso muss man dazu den Timer deaktivieren??

Schau dir mal das Programm im Anhang an, das läuft z.B. ausschließlich
in der ISR. Und zwar deshalb, weil bis zum nächsten Aufruf der
Timer-ISR genügend Takte vergehen, also genügend Rechenzeit bleibt.
Aber das ist nicht der Grund, warum ich dir das Beispiel zeige.

Das Beispiel zeigt, wie man in der ISR neben der Tastenabfrage noch
andere Dinge erledigen kann.
Es zeigt weiter, dass man einzelne Bits in Registern auswerten und
manipulieren kann, man muss also nicht das Register nach temp kopieren
und dann das gewünschte Bit maskieren.
Es zeigt aber auch, wie man ein ASM-Programm einigermaßen lesbar
gestalten kann.

...

von peter dannegger (Gast)


Lesenswert?

"das cli und sei auch :-)"

Das muß auch so sein.
Allerdings sollte dazwischen eben kein Interrupt verloren gehen.

Ich weiß jetzt nicht, wie lange Deine Funktionen start1 und start2
dauern.

Wenn sie länger dauern, mach es doch so:


Loop:
  cli
  mov   temp1,key_press
  clr   key_press            ;Tasten löschen nach Aktion
  sei

  push  temp1

  andi   temp1,0b00000100    ;nur PD2 auswerten
  cpi  temp1,0b00000100        ;wenn's passt, springen
  brne   PC+2
  rcall   start1

  pop   temp1                 ;nur PD3 auswerten

  andi   temp1,0b00001000
  cpi  temp1,0b00001000
  brne   PC+2
  rcall  start2

  sleep
  rjmp  Loop


Peter

von Carsten (Gast)


Lesenswert?

Also den Timer nicht zu deaktivieren hat zur Folge, dass die Tasten
nicht mehr zuverlässig erkannt werden.
...klingt komisch - ist aber so...
Wenn ich Dein Programm richtig gelesen habe, hast Du den gesamten
Programmablauf im Timer-Interrupt.
Jetzt ist aber doch ein zu langes Programm verantwortlich dafür, dass
die Interruptzeit nicht mehr maßgeblich ist (es gibt Warteschleifen).
Wenn ich in dieser Timer-Routine dann das Zählen anfange, wird mein
Zähler respektive die Vergangene Zeit vom Programmablauf bestimmt.
Nicht vom Timer.
Innerhalb der Interruptroutine wird der Timer ja wohl kaum die Routine
neu starten. Dauert der Programmablauf 40µs ist's vorbei mit
Taktzeiten von 25µs.
Das soll heissen, wenn ich eine feste Zeitspanne brauche muss ich die
Interruptzeit und den Programmablauf zusammenzählen, bevor ich den
Zähler meiner Variablen erhöhe.
Dann habe ich einen Teiler mit dem man eine Zeitspanne kalkulieren
kann.
Habe ich das so richtig verstanden?

Ok, zur Lesbarkeit sieht Deins schick aus aber ich bin ja noch Anfänger
und arbeite daran.

von ...HanneS... (Gast)


Lesenswert?

In meinem Beispiel wird die ISR alle 10000 Takte aufgerufen (100Hz). Da
keinerlei Warteschleifen vorhanden sind, wird der Durchlauf einer ISR
mit Sicherheit beendet sein, ehe der Timer erneut "zuschlägt".

In der Mainloop schickt man den AVR besser schlafen, das habe ich aber
in dieser Vorab-Version noch nicht gemacht, ist aber inzwischen drin.

Auch ich habe die Tastenentprellung von Peter Dannegger benutzt und
bedanke mich bei Peter für diesen cleveren Algorithmus. Meine Register
haben zwar andere Namen, aber ich verweise grundsätzlich auf den
Urheber der Routine. :)

...

von Carsten (Gast)


Lesenswert?

Ich glaube ich muss mich mit dem Timer nochmal von Neuem
auseinandersetzen.
Im Moment versuche ich erneut die Entprellroutine zu verstehen.
Wenn der Timerzyklus ausreicht für meine LCD und RS232-Routinen, werde
ich den Programmaufbau wohl umbauen.
So hat man im Grunde den gleichen Ablauf nur zu festen Zeiten.
Wie ist das denn dann mit anderen Interrupts ?
Funktionieren die dann noch ? Ich denke da so ans UART.

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.