Forum: Mikrocontroller und Digitale Elektronik ICP Atmega 8


von Dietrich Arndt (Gast)


Lesenswert?

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

von Dietrich Arndt (Gast)


Lesenswert?

Wo ist ueberhaupt Vorteil von ICP gegenueber normalem Interrupt ebim
messen von Impulslaengen?

von Hannes L. (hannes)


Lesenswert?

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

...

von Dietrich Arndt (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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