PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer-ISR "erzwingen"



Sauerbruch
11.05.2009, 23:33
Ich habe noch ein Problem:

Ich muss einen Timer-Interrupt unter bestimmten Umständen zwischendurch "erzwingen", d.h. zwischen zwei Überläufen. Der Grundrhythmus darf sich dabei aber nicht verschieben. Im Datenblatt habe ich gelesen, dass man dazu nur das Overflow-Flag setzen muss, und schon soll der Interrupt ausgeführt werden (vorausgesetzt, der spezielle und die Interrupts im allgemeinen sind freigegeben).

Um das zu probieren, habe ich mal folgenden Code geschrieben: Timer1 toggelt eine LED alle ca. 1,5 Sekunden. Ein Taster löst INT0 aus, in dessen ISR das Overflow-Flag von Timer1 (TIFR.2) gesetzt wird.




$regfile = "m8def.dat"
$crystal = 1000000

$hwstack = 128
$swstack = 128
$framesize = 160

Ddrb.0 = 1 'LED-Ausgang
Portd.2 = 1 'PullUp

Config Timer1 = Timer , Prescale = 1024
Timer1 = 64000 'Überlauf alle ca. 1,5 Sek.
On Timer1 Isr_timer1
Enable Timer1

Config Int0 = Falling 'Taste gegen Masse
On Int0 Isr_int0
Enable Int0

Enable Interrupts

Do
Loop

Isr_timer1:
Toggle Portb.0
Timer1 = 64000
Return

Isr_int0: 'Tastendruck:
Waitms 10 'Prellen abwarten (ich weiß - schlechter Stil...)
Tifr.2 = 0 'Timer1-Overflow-Flag setzen
Return


Die LED blinkt zwar stabil im 1,5-Sekundentakt - auf Tastendruck passiert aber gar nichts :-( Die INT0-ISR wird dabei korrekt angesprungen (ich habe in der ISR versuchsweise mal eine andere LED toggeln lassen - das geschieht bei jedem Tastendruck einwandfrei).

Was mach´ ich falsch???

for_ro
12.05.2009, 00:10
Kannst du nicht einfach in der Isr_Int0 die Timer ISR aufrufen:

Isr_int0:
Waitms 10
gosub Isr_Timer0
Return

Gruß

Rolf

Sauerbruch
12.05.2009, 00:21
Hmmm.. da hatte ich auch schon drüber nachgedacht. In der "richtigen" Anwendung (wo nicht nur ´ne LED blinkt) hatte ich etwas Bedenken, eine ISR aus einer anderen ISR anzuspringen.

Zugegebenermaßen funktioniert´s im Blink-Code einwandfrei. Die Geschichte mit dem Flag schien mir zwar elegant, aber wenn´s auch anders funktioniert... Werde es morgen einfach mal in der eigentlichen Anwendung testen.

Danke für den Tip - aber wenn doch noch jemand wissen sollte, wie man mit dem TOV1-Flag korrekt umgeht, bin ich weiterhin interessiert!

Gruß,

Daniel

kolisson
12.05.2009, 02:53
ups .. was lese ich denn da ?

INTERRUPTS ERZWINGEN ?

das hat mich nachdenklich gemacht, ob man diese ints denn erzwingen kann, obwohl sie ja schon erzwungen sind.

evt. istv die fragestellung falsch!

Interuupts sind ja erzwungene unterbrechungen des hauptprogrammes mit höherer priorität als das hauptprogramm.

im datenblatt gibt es doch eine liste der prioritäten der einzelnen ints.

wenn höherwertige disabled sind, würde doch dein timer der höherwetigste sein.

oder nicht ?

gruss klaus

Sauerbruch
12.05.2009, 07:04
das hat mich nachdenklich gemacht, ob man diese ints denn erzwingen kann, obwohl sie ja schon erzwungen sind.

evt. istv die fragestellung falsch!


Guter Einwand, guter Einwand... zumal das Gegenteil von "erzwungen" ja so etwas wie "freiwillig" ist - und schon wären wir bei der Frage, ob ein ATMega8 einen freien Willen haben kann... :-)

Deshalb hier nochmal der komprimierte, auf den Punkt gebrachte Kern meiner (vielleicht etwas wirr formulierten) Frage:

Wie kann ich die Timer-Overflow-ISR ausführen lasssen, ohne dass der Timer überläuft?
Oder die INT0-ISR ohne die dafür nötige Pegeländerung?
Oder die ADC-Complete-ISR ohne eine vollendete AD-Wandlung?

(to be continued)

Die einzelnen Interrupts kommen sich dabei nicht in die Quere, so dass deren Priorität in diesem ganz speziellen Fall eine eher untergeordnete Rolle spielt.

PicNick
12.05.2009, 08:34
Technisch gesehen kannst du hemmungslos die ISR-Routine mit GOSUB aufrufen. Dem eigentlichen Timer-Counter is das im Grunde egal.
Nur wird ja deine ISR-Routine wohl den Timer-Preload setzen, und das is natürlich weniger gut.
Ausserdem ist die PUSH /POP Orgie einer ISR auch eher unnötig, also überleg' dir, ob das in dieser Form wirklich notwendig ist.

Sauerbruch
12.05.2009, 08:50
Okay, ich sehe schon, dass die Gosub-Lösung wohl wirklich die beste ist. Dass das den Timer als solchen stört war auch nicht meine Sorge, sondern eher eine "Aufhänge"-Problematik von wegen verschachtelten Sprüngen. Aber das scheint bei ausreichendem Stack ja kein Problem zu sein.
Und den Timer-Preset kann man ja auch relativ einfach von einem gesetzten bzw. geclearten Flag-Bit abhängig machen.

Trotzdem wundert es mich, weshalb das Setzen des TOV1-Flags keinen Interrupt bewirkt...

Ceos
12.05.2009, 09:17
in C hätt ich einfach das FOC bit im TCCR gesetzt (habs aber bei mir auch so gelöst, dass ich einfach ne methode aufrufe, die cih bei bedarf direkt aus der hauptroutine aufrufe) :)

PS: das steht aber auch im datenblatt, dass das setzen des flags nicht geht, sondern explizit FOC benutz werden muss, denn treffender weise heisst das flag Force Output Compare (erzwinge output compare) ^^

Sauerbruch
12.05.2009, 09:39
Auch in Bascom könnte man ja ohne weiteres das FOC-Bit setzen - so weit so gut. Aber ich brauche einen außerplanmäßigen Timer-Overflow-Interrupt, und nicht den Output-Compare-Interrupt. Und das sind ja nun mal zwei Paar Schuhe.

Zum TOV1-Flag habe ich nur folgendes gefunden:

TOV1 is automatically cleared when the Timer/Counter1 Overflow Interrupt Vector is executed. Alternatively, TOV1 can be cleared by writing a logic one to its bit location.

Und so dachte ich mir halt, dass sich das Flag auch manuell setzen lassen müsste, wenn man es schon manuell löschen kann.

An welcher Stelle hast Du denn den Hinweis gefunden, dass man dieses Flag nicht einfach so setzten kann?
(Blöd, aber solche Dinge lassen mir einfach keine Ruhe, auch wenn das eigentliche Problem schon längst gelöst ist...)

Ceos
12.05.2009, 09:59
oh dass du den overflow meinst, ist mir glatt entgangen >_<

das problem ist, dass dieses bit mit dem schreiber einer 1 in sein register gelöscht wird, beim schreiben einer 0 wird der wert nicht verändert!

also wenn das bit den wert x hat und du einen 0 reinschreibst, hat es immernoch den wert x, schreibst du eine 1 rein, hat das bit anschliessend den wert 0!

das dient dazu, dass du das bit verändern kannst(schreiben einer 1), dich aber nciht um seinen ursprünglichen zustand kümmern musst, sondern einfach das bit auf 0 lässt wenn du andere bits des registers bearbeitest... das wird bei einigen anderen registern auch so gehandhabt, da stand auch irgendwo ne kurzerklärung zu

Sauerbruch
12.05.2009, 10:09
Okay - das erklärt natürlich so einiges! Da muss man aber erstmal drauf kommen :-)

Dann werde ich das Kapitel "TOVF1" ganz genüsslich zu den Akten legen und die entsprechende ISR einfach mit Gosub ausführen lassen.

Danke für die Info!!

Besserwessi
12.05.2009, 21:36
Wenn man die ISR einfach per Gosub aufruft, muß man eventuell aufpassen, denn dann kann der Aufruf per Gosub auch noch per Interrupt unterbrochen werden. Nicht jeder Code verträgt es wenn er quasi 2 mal läuft. Ein Beispiel für Mögliche Probleme wäre der zugriff auf 16 Bit Variablen oder Register.

Ceos
13.05.2009, 13:25
also eventuell als allererstes beim betreten der ISR-Sub das interrupt enable flag löschen und anschliessend wieder setzen

Sauerbruch
13.05.2009, 14:50
Sehr guter Tip mit dem Globalen Enable Interrupts - hab es gerade ausprobiert und (bislang) läuft´s wie geschmiert!

Besserwessi
13.05.2009, 18:36
Das Interrupt flag in der ISR zu löschen ist eine gute Idee: beim Aufruf als interrupt passiert nichts, beim Aufruf per Gosub weren interrupts gespeert. Auf das explizite setzen des Interrupt flags sollte man aber besser verzichten, denn sonst kann man 2 geschaltelte ISRs kriegen und braicht 2 mal den Stack für die ganzen Register. Am ender der ISR sollter der Interrupt ohnehin wie der frei gegeben werden (durch dem ASM befehl RETI am den Ende).