Hallo,
wollte mal kurz fragen obs eine Möglichkeit gibt verschiedenen
Interrups eine Priorität zuzuweisen?
Mir fällts nur so ein das ich am Anfang einer wichtigen Int.-Routine
einfach die Interrups ausschalte um nicht gestört zu werden, oder gibt
es eine möglichkeit Prioritäten zu verteilen. Braucht keine fertige
Lösung sein sondern eine Idee/Vorschlag genügt mir schon.
hi,
der "normale" weg ist es, zu beginn einer (längeren, kritischen)
interrupt-routine das ie-register zu sichern, interrupts auszuschalten,
befehle ausführen, ie zurückschreiben, interrupts an und feddich.
prioritäten bei irq's gibts afaik nicht, würde bei RISC auch wenig
sinn machen...
Ja, der AVR hat leider keine Interruptprioritäten.
Was das aber mit RISC zu tun haben soll, ist mir schleierhaft.
Egal ob RISC oder CISC, es macht in jedem Fall komplexere Anwendungen
einfacher. Sogar einige neuere PICs haben das.
Bisher habe ich es beim AVR immer geschafft, mit nur einer
Interruptpriorität auszukommen, indem ich die Interrupts so kurz wie
möglich halte, d.h. alle nicht eiligen Schritte ins Hauptprogramm
verlagere.
Interruptprioritäten in Software zu machen ist zwar theoretisch
möglich, aber sehr kompliziert. Man muß dabei höllisch aufpassen, daß
sich Interrupts nicht selber wieder aufrufen können und das auch
wirklich die richtigen Register richtig gesichert werden.
Da die Interrupt-Enable-Bits leider überall verteilt sind und obendrein
die Interrupt-Pending-Bits ausmaskiert werden müssen, ist das eine
äußerst langwierige Angelegenheit, wärend der alle Interrupts gesperrt
sind.
Mit anderen Worten, die Interrupt-Response-Zeit kann sich dadurch
drastisch verschlechtern.
Peter
Hallo,
immer wieder heißt es, der AVR hätte keine Interrupt-Prioritäten. Im
Manual, z.B. zum 2313, liest man jedoch:
"The complete list of vectors is shown in Table 2. The list also
determines the priority levels of the diferent interrupts. The lower
the adress, the higher the priority level. Reset has the highest
priority,...."
Widersprechen sich die beiden Aussagen nicht? Klar ist, daß man als
Anwender an diese Tabelle gebunden ist, außer man bemüht sich in der
Software, das zu ändern. Wie lassen sich denn beide Aussagen in
Einklang bringen?
Gruß
Ich vermute mal, daß es sich dabei um einen Übersetzungsfehler handelt.
In anderen Architekturen wird das richtiger als Auflösungsreihenfolge
bezeichnet.
D.h. es ist damit die Reihenfolge gemeint in der entschieden wird,
welcher Interrupt angesprungen wird, wenn mehrere Interruptquellen
gleichzeitig gesetzt sind, z.B. wenn alle Interrupts über eine längere
Zeit global gesperrt waren.
Peter
Genau so ist es. Denn der AVR löscht ja bei jedem Eintritt in eine ISR
das Interrupt-Enable-Bit. Nach der ISR wird es wieder gesetzt. Also
gibt es eigentlich eine Unterbrechung der ISR durch eine andere.
Ich habe das aber in einer Anwendung schon benötigt. Also hab ich in
meiner, um einiges längere, Routine das dazugehörige
Interrupt-Enable-Bit gelöscht und dann die Interrupts Global wieder
freigegeben. Am Ende der Routine hab ich das Bit dann wieder gesetzt.
So konnte diese ISR durch eine andere (in diesem Fall höhere ISR)
unterbrochen werden, aber Sie konnte sich nicht selbst aufrufen.
Gruß, Florian
Dann grabe ich mal dieses schöne Thema wieder aus! :-)
Wie sieht es denn bei folgenden Beispiel aus!
Ich habe zum Beispiel einen Overflow Timer Interrupt und ein INT0
Interrupt, wo ein Taster dran ist. Beim Timer Interrupt wird eine
Variable hochgezählt. Btw. muss die volatile sein?
So jetzt halte ich den Taster gedrückt. Kommt der Timerinterrupt
trotzdem noch zum Zuge?
Variable volatile? Ja wenn sie nicht nur im Timer Interrupt sondern auch
in einem anderen Interrupt oder Hautprogramm benutzt wird.
Sobald ein Interrupt aktiv ist sind alle weiteren Interrupt
Abforderungen gesperrt. Man muss in der Interrupt Routine ein EI machen
damit die anderen Interrup Anforderungen den aktuellen Interrupt
unterbrechen können.
Die Interrupt Priorität hat damit nichts zu tun. Sie regelt die
Reihenfolge bei gleichzeitigem Auftreten von mehreren Interrupt
Anforderungen.
> Die Interrupt Priorität hat damit nichts zu tun.
Doch , eigentlich ist sie genau das. Höherpriore Interrupts können
niederpriore unterbrechen, umgekehrt aber nicht. Das unterstützt der AVR
nicht, sondern nur:
> Sie regelt die Reihenfolge bei gleichzeitigem Auftreten von mehreren> Interrupt Anforderungen.
Siehe Posting in diesem Thread etwas weiter oben:
Beitrag "Re: AVR ASM Interrupt Priorität"
>So jetzt halte ich den Taster gedrückt. Kommt der Timerinterrupt>trotzdem noch zum Zuge?
Schreib doch ein Mini-Testprogramm im AVRStudio und lass es im Simulator
laufen.
Ich tippe übrigens auf "nein", d. h. der Timerinterrupt wird nicht mehr
aufgerufen, wenn der INT0-Interrupt auf "pegelgetriggert" konfiguriert
ist und deshalb bei gedrücktem Taster ständig ansteht. Dieser
Betriebszustand gibt aber in keinem normalen Programm einen Sinn. Man
benötigt den pegelgetriggerten INT0 zum Aufwachen aus dem Power Down und
zur Realisierung eines Single-Step-Modus für Debuggingzwecke, aber ich
glaube nicht, dass er für sonst noch was gut ist (heißt: etwas, das man
nicht auch mit einem flankengetriggerten INT0 erledigen kann).
> (heißt: etwas, das man> nicht auch mit einem flankengetriggerten INT0 erledigen kann).
Wobei Taster am flankengetriggerten Int0 kontraproduktiv sind, es sei
denn, man will einen Zufallsgenerator bauen. ;-)
~
Ahh so... und was würde man dann für ein Interrupt verfahren nehmen,
wenn man per Tastendruck eine Aktion machen will. Polling würde ja bei
kritischen Anwendungen nicht die optimale Lösung sein.
Worauf ich hinaus will ist, der Timer Interrupt ist wichtig aber der
Tastendruck Interrupt auch. Aber wie könnte man das jetzt lösen, wenn
zum Beispiel aus mechanischen Gründen der Schalter hängt. Dann würde ja
die kritische Timer Routine nicht mehr zum zugekommen, wenn ich das
jetzt richtig verstanden habe!?
Max wrote:
> Ahh so... und was würde man dann für ein Interrupt verfahren nehmen,> wenn man per Tastendruck eine Aktion machen will. Polling würde ja bei> kritischen Anwendungen nicht die optimale Lösung sein.
Ich nehme an, es ist für dich sehr wichtig, dass der Tastendruck nach
10µs und nicht erst nach 1000µs zur entsprechenden Reaktion führt. Denn
andernfalls ist entprelltes Polling im oft sowieso schon vorhandenen
regelmässigen Timer-Interrupt höchst einfach und problemlos:
http://www.mikrocontroller.net/articles/Entprellung#Interrupt-Verfahren_.28nach_Peter_Dannegger.29
>Wobei Taster am flankengetriggerten Int0 kontraproduktiv sind, es sei>denn, man will einen Zufallsgenerator bauen. ;-)
OK, das steht dann auf einem anderen Blatt. Ein denkbarer
Anwendungsfall: Jemand will herausfinden, wie oft ein Taster prellt.
Dann könnte er ihn an einen flankengetriggerten INT0 hängen und in der
ISR nur eine Variable inkrementieren, die sofort auf einen Port
geschrieben wird.
>Polling würde ja bei>kritischen Anwendungen nicht die optimale Lösung sein.
Nein, umgekehrt: Über Interrupt ist nicht die optimale Lösung.
Jeder Taster prellt. Wenn er beim Niederdrücken z. B. fünf mal prellt,
dann gibts zwei Möglichkeiten: 1. Der INT0-Handler wird auch fünfmal
aufgerufen, weil er so reaktionsschnell ist (das ist ja gerade seine
Besonderheit). Dies dürfte kaum jemals erwünscht sein. Also muss man 2.
irgendwie eine künstliche Verzögerung realisieren, die verhindert, dass
der Interrupt sofort nach dem ersten Pegelwechsel erneut stattfinden
kann. Eine Delayschleife ist dafür tabu, weil der µC in einer
zeitkritischen Anwendung nicht ein paar Millisekunden lang blockiert
sein darf, also muss man es mit einem Timer machen. Toll: Dann sind zwei
wertvolle Controllerresourcen (ext. Int. + Timer) mit der Abfrage
eines dämlichen Tasters belegt. Manche hält das nicht davon ab, es
tatsächlich so zu machen; der Rest erkennt die Vorteile der
Pollingmethode: Kein externer Interrupt nötig; die Resource Timer kann
gleichzeitig noch vielen anderen Zwecken dienen; CPU-Last
vernachlässigbar (wen nicht: Taktfrequenz des µC raufsetzen); so viele
Taster handelbar, wie man will. Die durch die Tastenabfrage erzeugte
CPU-Last kann man leicht rechnerisch abschätzen und kommt unter
realistischen Bedingungen (z. B. FOSC = 8 MHz, Abfrageintervall = 10 ms,
20 Takte für Tastenhandler) auf Werte weit unter 1 %.
Ah stimmt dran habe ich noch nicht gedacht. Auch wenn ich jetzt nicht
Timer und INT0 für einen "dämlichen" Taster verschwenden würde!
Da hätte ich noch eine Offtopic Frage! ;-) Nehmen wir an zwei Leute
arbeiten an einem Projekt. Jeder schreibt seinen Teil. Beide nutzen den
Timer Overflow Interrupt. Gibt es in einem Programm immer nur einen ISR
zu dem jeweiligen Interrupt?! Ich würde denke ja, aber wie organisiert
man dann so ein etwas größeres Programm?! Legt man sowas dann vorher
durch die Vorplanung fest?
@ Max (Gast)
>arbeiten an einem Projekt. Jeder schreibt seinen Teil. Beide nutzen den>Timer Overflow Interrupt. Gibt es in einem Programm immer nur einen ISR>zu dem jeweiligen Interrupt?!
Ja. Dort kann man aber mehrere Funktionen aufrufen.
> Ich würde denke ja, aber wie organisiert>man dann so ein etwas größeres Programm?! Legt man sowas dann vorher>durch die Vorplanung fest?
Wäre sinnvoll.
MFG
Falk
Modularisierung. Ein Timer-Modul bestehend aus .h und .c mit
Initialisierung und der dazu gehörenden ISR.
Wahlweise werden darin die Timer-Handler anderer Module direkt
aufgerufen - das ist die einfache Fassung für überschaubare Projekte.
Oder man geht einen Schritt weiter und bietet im Timer-Modul eine
Funktion, mit der sich beliebige Timer-Handler hinzufügen lassen - dann
wird ein flexibel (wieder-) verwendbarer Timer Scheduler draus.
>>Ist es dann auch sinnvoll alle ISR in eine seperate Datei zu legen?>> Kann man manchen, muss man aber nicht. Geschmackssache.
Wenn damit gemeint ist, dass jede ISR in ein eigenes Quellcode-File nur
für diese ISR soll: Das ergibt nur in besonderen Fällen Sinn, etwa wenn
der Code anders compilert werden muss (z.B. ARM/Thumb). Denn dadurch
steigt der Aufwand und man kann in C keine Modul-lokalen Variablen mehr
verwenden (static).
Ansonsten gehört zusammengehöriger Code zusammen und weitgehend
getrennter Code getrennt. Also ein Code-Modul für UART mitsamt seinen
Interrupts und getrennt davon eines für I2C.