Hallo, Ich muss Laenge einer Periode messen. Laenge von 3 - 30 ms . Jetzt mache ich es per Int0. Jede steigende flanke loest ein Interrupt aus. Dann wird in der Interrupt Service Routine der Wert des Immer laufenden Timer1 gespeichert, dann subtrahiert und wir haben das Ergebnis. Nun wird aber im unguenstigem Fall jede 3 ms ein Interroupt ausgeloest. Da ich aber die Messung nicht so oft brauche (es reicht eine Messung pro 0.1 Sekunden) und ich noch viele andere Sachen in meinem Programm mache auch andere Interrupts(Timerueberlauf, Counterueberlauf) habe, dachte ich mir es irgendwie anders/eleganter zu loesen. So ein Interrupt jede 3 ms kann schon stoerend sein. Ich habe schon versucht per Disable/Enable Int0 den Interrupt ab und zu zu deaktivieren, aber bischer ohne Ergebnisse. Woran kann sowas liegen? Darf man ueberhaupt sowas in einer anderer Interrupt Service Routine machen? Ich habe versucht in einer Timer1 Overflow Routine (erfolgt jede 0.5 sekunden)zu deaktivieren/aktivieren. Klappte aber wie gaseagt nicht. Was gibt es da noch fuer Moeglichkeiten? ICP ? aber dann habe ich doch dasselbe Problem , dass je nach Impulslaenge auch sehr oft ein Interrupt ausgeloest wird. Brauche ich doch um die Zeitstempel zu speichern .. ? mfg
Wo ist ueberhaupt Vorteil von ICP gegenueber normalem Interrupt ebim messen von Impulslaengen?
> Wo ist ueberhaupt Vorteil von ICP gegenueber normalem Interrupt > ebim > messen von Impulslaengen? Der Vorteil liegt darin, dass bei ICP der "Zeitstempel" exakt beim Auftreten der Flanke aus dem Timer kopiert wird und nicht erst beim Aufrufen der ISR. Das Deaktivieren eines Interrupts ist eigentlich kein Akt, man löscht dazu nur das entsprechende Flag im entsprechenden Interrupt-Maskenregister (GIMSK, TIMSK). Vor dem nächsten Aktivieren des Interrupts sollte man aber das entsprechende Flag im Interrupt-Flagregister (GIFR, TIFR) löschen (durch Schreiben einer Eins im entsprechenden Bit), damit bereits stattgefundene Ereignisse nicht berücksichtigt werden. Aber ein Interrupt, der alle 3ms auftritt, sollte kein Programm stören. Das ist bei 1MHz alle 3000 Takte, das verriecht sich. Allerdings sollte man die ISRs grundsätzlich sehr kurz halten, bei höherem Rechenaufwand lieber ein "Jobflag" setzen und den Job in der Mainloop erledigen. Auch ein paar für Interrupts reservierte Exklusivregister können die Abarbeitung der ISR beschleunigen, das erspart Zeitverlust durch Push&Pop. ...
@ HanneS Danke, hast mir sehr geholfen! Ein paar habe ich aber noch :) GIFR ist noch nicht ganz klar.. Wenn ein Inerruptanforderung vorliegt wird ein "1" im GIFR geschrieben. Wenn man aber diese loeschen moechte, schreibt man wieder eine "1" rein ? Hmm .. Dann ist ja immer eine "1" drin ? Zitat: Allerdings sollte man die ISRs grundsätzlich sehr kurz halten, bei höherem Rechenaufwand lieber ein "Jobflag" setzen und den Job in der Mainloop erledigen. ----------------------------------------------------------- Kannst du dazu etwas mehr sagen? Eventuell ein Beispiel wie ich das am besten mache.. Meinst du damit die Do-Loop Hauptscheife oder kann es auch jede beliebige Subroutine sein?
> GIFR ist noch nicht ganz klar.. Wenn ein Inerruptanforderung > vorliegt > wird ein "1" im GIFR geschrieben. Wenn man aber diese loeschen > moechte, schreibt man wieder eine "1" rein ? Hmm .. Dann ist ja > immer > eine "1" drin ? GFIR enthält die vom externen Ereignis (Pegelwechsel) gesetzten Flags für beide Interrupts (INTF0, INTF1). Tritt das in MCUCR (Datenblatt Mega8, Seite 64) vorgewählte Ereignis ein, dann wird das zugehörige Flag in GIFR (DB, S. 66) gesetzt. Ist auch das zugehörige Bit in GICR (DB, S. 65) gesetzt, dann wird der zugehörige Int-Vektor angesprungen, nachdem die Rücksprungadresse (für RETI) auf dem Stack gesichert wurde. Durch den Aufruf des Interrupt-Vektors wird das Flag in GIFR wieder gelöscht (cleared by Hardware). Will man es manuell löschen, so ist keine 0 in das Bit zu schreiben, sondern eine 1. Siehe Datenblatt Seite 66. > "Jobflag" Ich (nicht nur ich) reserviere mir gern ein Register, in dem ich mir bis zu 8 Boolsche Variablen zur Programmablaufsteuerung anlege. Das Register nenne ich bisher "flags", aber der Name "jobs" ist wohl treffender. Die einzelnen Bits stehen für unterschiedliche zu erledigenden Aufgaben. Irgendein Programmteil (meist ein Interrupt) vergibt einen Auftrag, indem das zugehörige Jobflag gesetzt wird. In der Mainloop werden dann alle Jobflags der Reihe nach abgefragt und wenn eines gesetzt ist, wird die zugehörige Rüutine aufgerufen. Diese Routine löscht dann das Jobflag und erledigt den Job. Dies entlastet Interrupt-Services-Routinen (ISRs), da diese recht kurz sein müssen. Dauert die Abarbeitung einer ISR zu lange, können andere in dieser Zeit auftretende Interrupts nicht bzw. nur verspätet abgearbeitet werden, was unter Umständen zum Verschlucken von Interrupts führen kann. Ein Beispiel für den Umgang mit Jobflags findest du hier: http://www.hanneslux.de/avr/zuenduhr/ZndUhr01.asm Es ist das Register "flags" (r23), in dem 7 Boolsche Variablen gehalten werden. Dabei sind die Bits "neusek" und "lcdtakt" als Jobflags zu sehen, sie werden im Timer-Interrupt gesetzt und beim Erledigen des Jobs wieder gelöscht. > Meinst du damit die Do-Loop Hauptscheife Nunja, bei mir ist das die Mainloop, beginnend mit dem Label "mainloop:" und endend mit "rjmp mainloop" nach "sleep". Dies sorgt dafür, dass alle zu erledigenden Jobs ausgeführt werden und danach in den Sleep-Mode gefallen wird. Ein auftretender Interrupt weckt den AVR aus dem Sleep-Zustand, führt die ISR aus und springt danach über den nach sleep stehenden Befehl "rjmp mainloop" die Hauptschleife aus, bis alle Jobflags gelöscht sind, dann wird wieder geschlafen, bis der nächste Interrupt "klingelt". ...
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.