Forum: Mikrocontroller und Digitale Elektronik Wieviel Code in den Interrupt?


von Tine S. (tine)


Lesenswert?

Hallo,

Wie handhabt ihr die Programmierung der IR Routinen? Versucht Ihr nur 
Flags zu setzen oder Variablen zu ändern, die dann im Hauptprogramm 
aufgerufen und endverarbeitet werden, oder packt ihr schon größere 
Längen Code in den Interrupt? Oder unterscheidet sich das gar für die 
Art des IR (Timer, Capture)?
Vorteil von wenig Code im IR ist die schnelle Rückkehr ins Programm, und 
mögliche "Aufarbeitung" ansonsten verpasster IR's.
Das Problem ist dann natürlich, dass man im Hauptprogramm die Flags und 
Variablen pollen muss, was sinnlos Zyklen verheizt.
Viel Code im ISR dagegen spart zwar Zyklen, aber wenn im Hauptprogramm 
was zeitkritisches läuft (UART kommt rein...), könnte man da Probleme 
bekommen.
Irgendwelche Tipps oder Ansichten, oder frei nach soviel wie nötig und 
so wenig wie möglich?

von Reinhard Kern (Gast)


Lesenswert?

Tine Schwerzel schrieb:
> Hallo,
>
> Wie handhabt ihr die Programmierung der IR Routinen? Versucht Ihr nur
> Flags zu setzen oder Variablen zu ändern, die dann im Hauptprogramm
> aufgerufen und endverarbeitet werden, oder packt ihr schon größere
> Längen Code in den Interrupt? ...

Hallo,

es gibt eine 3. Möglichkeit: nur minimale Bearbeitung (Daten holen, Flag 
rücksetzen usw.), dann aber nicht Rückkehr ins Hauptprogramm (oder was 
immer sonst gerade läuft), sondern in eine Fortsetzungsroutine der 
Interrupt-Bearbeitung.

Das setzt natürlich perfekte Kenntnis des Befehlsablaufs, des 
Stackaufbaus usw. voraus. Und da diese Routine mit niedrigerer Priorität 
läuft und selbst interrupted werden kann - das ist ja der Zweck der 
Sache - sollte man auch in threaded und concurrent programming fit sein. 
Im Prinzip nutzt man so verschachtelte Interrupts obwohl sie der 
Prozessor nicht kann. Die Fehlersuche kann recht schwierig werden.

Wenn der Prozessor nested interrupts kann, braucht man das nicht.

Gruss Reinhard

von Antwort (Gast)


Lesenswert?

Ich packe immer soviel Code wie möglich in die ISR. Die Obergrenze gibt 
die noch verfügbare Rechenzeit an. Wenn der Controller sonst nicht viel 
zu tun hat und dies auch nicht sonderlich Zeitkritisch ist kann die ISR 
ruhig etwas Voluminöser ausfallen.

von Joerg W. (joergwolfram)


Lesenswert?

Ich habe es bisher immer so gehandhabt, möglichst nur einen 
Timer-Interrupt zu benutzen. Das Hauptprogramm selbst agiert nur über 
Variablen im Speicher und "sieht" bestenfalls von der Hardware gar 
nichts. Wenn etwas für einen Timerzyklus zu lange dauert (z.B. 
Umwandlung von PS2-Tastatur nach ASCII), dann teile ich das über eine 
FSM auf mehrere Slots auf.
Um beim Beispiel PS2-Tastatur zu bleiben, das Hauptprogramm nutzt 
letztendlich nur den aktuellen Tastaturcode (oder 0 wenn keine Taste 
gedrückt ist), den letzten Tastaturcode (wird nicht auf 0 zurückgesetzt) 
und ein Byte mit dem Status der Shift-, Control- und Alternate-Tasten. 
Für eine mobile Anwendung lese ich dann z.B. Tasten an einem Port ein 
und schreibe die entsprechenden Codes (Pfeiltasten, ENTER, ESC). Dem 
Hauptprogramm ist es dabei letztendlich egal, woher die Daten kommen.

Ich kenne aber auch genug Leute in verschiedenen Foren , die so eine 
Herangehensweise für absolut grauselig halten, weil sie der "reinen 
Lehre von den minimalen Interruptroutinen" wiederspricht.

Jörg

von Detlev T. (detlevt)


Lesenswert?

Joerg Wolfram schrieb:
> weil sie der "reinen
> Lehre von den minimalen Interruptroutinen" wiederspricht.

Du solltest nicht so tun, als wäre das ein grundloses Dogma. Ich halte 
diesen Ansatz "Fasse dich kurz" - zumindest für meine Projekte - auf 
jeden Fall für richtig.

Ein Interrupt hat meist den Zweck, eine Aktion auszulösen, die 
einigermaßen eilig erledigt werden muss. Hätte ich alle Zeit der Welt, 
bräuchte ich keinen Interrupt. Dann würde es reichen, im Hauptprogramm 
das Flag bei Gelegenheit abzufragen.

Verschiedene Interrupts blockieren sich aber. ("NOBLOCK" widerspricht da 
meiner Vorstellung von "eilig") Deshalb sollte jede ISR den Controller 
möglichst schnell wieder frei geben.

Dein Beispiel mit der PS/2-Tastatur (vermutlich über USART 
angeschlossen) würde ich zum Beispiel so gestalten, dass die ISR die 
Scancodes entgegen nimmt und wie bei entsprechenden UART-Routinen erst 
einmal in einen Puffer schreibt. Nur das Vorkommen einer 
Unterbrecher-Taste würde ich noch detektieren und ein entsprechendes 
Flag setzen. Die Auswertung der Tasten (Shift usw.) würde erst die 
Routine übernehmen, die eine Taste zurück liefern soll.

Im Gegensatz zu dir nutze ich auch eher mehr Interrupts. Das ist sicher 
auch ein Grund, warum ich hier eine anderen Standpunkt habe.

Gruß, DetlevT

von Zwölfliter (Gast)


Lesenswert?

Möglichst wenig in der Interrupt-Routine ist bei einfache Behandlung 
ohne sei() Pflicht. Daraus kann man aber keine Regel machen.

Z.B. habe ich eine Firmware so aufgebaut, dass im Hauptprogramm nur der 
Bildspeicher vom Controller zum Display übertragen wird, und das ohne 
Pause in einer while(1)-Schleife. Das eigentliche Programm, bzw. seine 
verschiedenen Teile, werden von einem Timer-Interrupt, je nach 
Wichtigkeit, verschieden oft aufgerufen.

Mit dieser Methode ist garantiert, dass alles Wichtige im Timer 
abgearbeitet wird und das Display nur die wirkliche Freizeit verbraucht. 
Mann muss sich aber in nested Interruptus rein denken, denn der 
Timer-Interrupt unterbricht sich dabei selbst.

von Detlev T. (detlevt)


Lesenswert?

Hallo Zwölfliter,

wir sollten vielleicht einmal klar stellen, was unter "ISR" zu verstehen 
ist, sonst reden wir aneinander vorbei. Ich verstehe unter einem ISR 
eine Routine, die Hardware (intern oder extern) möglichst zeitnah zu 
einem Ereignis ansteuern soll. Was du da beschreibst, nutzt den 
Interrupt als technisches Mittel, um ein Multi-Threading-System mit 
unterschiedlichen Prioritäten zu erzeugen. Das ist etwas ganz anderes 
als was ich mit da vorstelle. In solchen Fällen würde ich wohl eher auf 
ein entsprechendes (Pseudo-) RTOS zurückgreifen.

Gruß, DetlevT

von Ferkel (Gast)


Lesenswert?

Eine Interruptroutine muß soviel erledigen, wie bis zum Eintreffen des 
nächsten Interrupts unbedingt erforderlich ist.

Bei einem Zyklus von 1ms reicht es aus, die Dekodierung von 
Tastatureingaben im weiterverarbeitenden Programmteil auszuführen, da 
höchstens alle 0,1s ein neues Ereignis auftritt UND ein verlorener 
Tastendruck nicht so schlimm ist; man drückt noch einmal.
Liefert eine Mechanik ein Ereignis, was gezählt werden und immer stimmen 
muß, gehört die Verarbeitung in den Interrupt.
Soll ferner ein Timer mit 1ms hochgezählt werden, muß dies in der 
Routine erfolgen. Das leuchtet ein :-)

Was nie in eine Interruptroutine gehört, sind Warteschleifen, die über 
wenige µs hinausgehen.

von Klaus 2. (klaus2m5)


Lesenswert?

Ferkel schrieb:
> ...ein verlorener
> Tastendruck nicht so schlimm ist; man drückt noch einmal.

Solche Geräte kenne ich auch, und ärgere mich jedesmal. Das muss einfach 
nicht sein. Wenn für sowas keine Zeit übrig ist, hat der Entwickler was 
falsch gemacht.

von Anja (Gast)


Lesenswert?

Hallo,

pauschal kann man das nicht sagen:

Wenn ich nur einen einzigen Timer-Interrupt habe (z.B. DCF77-Uhr) dann 
ist fast der ganze Code im Interrupt (Multiplexen, Signalerfassung, 
Tastaturabfrage). Im Hauptprogramm ist dann nur noch der 1-Sekunden 
Tick. (Decodieren, Zeit hochzählen usw).

Wenn ich mehrehre zeitkritische Interrupts mit unvorhersehbaren 
Zeitabständen habe dann wird im Interrupt nur der erfaßte Wert in einen 
Ringpuffer gepackt oder ein Flag (Tastaturabfragetick, Sekundentick) 
fürs Hauptprogramm gesetzt. bei einem 16MHz AVR komme ich dann auf max. 
ca 60 Takte = 5us Interruptdauer.

Gruß Anja

von Ferkel (Gast)


Lesenswert?

>Solche Geräte kenne ich auch, und ärgere mich jedesmal.

Natürlich, aber ich meinte mit diesem Beispiel die unerwartete, absolute 
Ausnahme, die nie auftreten wird. Falls doch, wäre es dennoch nicht 
schlimm.
Wenn der Endschalter eines Antriebes nicht erkannt wird, wäre dies 
fatal.

von Falk B. (falk)


Lesenswert?

Siehe Interrupt und Multitasking. Das richtige Pollen von Flags 
verbrät keine nennenswerte CPU-Leistung.

MFG
Falk

von Klaus 2. (klaus2m5)


Lesenswert?

Ferkel schrieb:
> Wenn der Endschalter eines Antriebes nicht erkannt wird, wäre dies
> fatal.

Klar, dafür würde ich noch gleichzeitig den Motorstrom überwachen, 
zusätzlich ein Zeitlimit per Timer setzen und wenn alles nichts hilft 
per Watchdog abschalten.

Das alles darf mich aber nicht daran hindern, das "Human-Interface" am 
Leben zu halten. Der Frustrierte am Not-Aus-Schalter kann mehr Mist 
bauen, als Du Dir vorstellen kannst.

von Peter D. (peda)


Lesenswert?

Das hängt davon ab, ob die CPU Interruptprioritäten hat oder nicht.

Ohne Prioritätslevel behindern sich alle Interrupts gegenseitig. Dann 
müssen alle Interrutps zusammen weniger Zeit benötigen, als der 
schnellste Interrupt.
Hast Du z.B. einen Timerinterrupt alle 100µs auf einem AVR mit 16MHz, 
dann darf die Worst-Case Summe aller Interrupts max 1600 Zyklen 
betragen.

Bei MCs mit Prioritäten (z.B. 8051) kann man das deutlich entspannter 
angehen. Nur die Interrupts mit hoher Priorität müssen schnell genug 
sein.

Daneben sollte aber auch die Mainloop nicht zu stark verzögert werden. 
Z.B. ein Userinterface sollte schon alle <300ms zum Zug kommen.


Peter

von Grolle (Gast)


Lesenswert?

Tine Schwerzel schrieb:
> Ansichten, oder frei nach soviel wie nötig und so wenig wie möglich?

Die Programmierin ist der Gott des Computers. Letzterer macht es so wie 
DU willst und es vorschreibst. Wichtig ist nur, dass DU am Ende sagen 
kannst: "Und sie sah, dass es gut war."

Wenn es zuverlässig wie gewünscht funktioniert, ist es ok. Im Glauben an 
das gute Programmieren brauchen wir keine Religionskriege.

Ich bin ein Fan davon, zu messen, wie lange so eine ISR dauert. Das kann 
über einen Pin geschehen, der am Anfang der ISR gesetzt und am Ende 
zurückgesetzt wird (dann mit Oskar o.ä. anzeigen), das kann über ein 
Flag gemacht werden, mit dem die ISR prüft, ob sie rekursiv aufgerufen 
wird, das kann man manchen, indem die ISR die Zeit für ihren eigenen 
Ablauf misst und den Maximalwert irgendwo abrufbar abspeichert. So kann 
man dann gut einschätzen, ob man eine flinke Gazelle oder einen unter 
dem eigenen Gewicht sich erdrückenden Saurier programmiert hat.

von Klaus 2. (klaus2m5)


Lesenswert?

Grolle schrieb:
> Die Programmierin ist der Gott des Computers

Die Programmzeile "Es werde Licht" hat bisher noch kein Compiler 
angenommen - oder ist das nur bei mir so?

von Grolle (Gast)


Lesenswert?

Klaus 2m5 schrieb:
> ist das nur bei mir so?

Du verstehst halt nicht, worum es hier geht, lässt nur mal wieder ein 
wenig Verspottung am Überlauf raus, und schreibst deswegen komplett OT.

von Detlev T. (detlevt)


Lesenswert?

Peter Dannegger schrieb:
> Bei MCs mit Prioritäten (z.B. 8051) kann man das deutlich entspannter
> angehen. Nur die Interrupts mit hoher Priorität müssen schnell genug
> sein.

IMO verschiebt man das Problem damit aber nur. Denn wenn etwas nicht 
schnell sein muss, warum dann überhaupt ein Interrupt? Dann kann ich 
auch in der Hauptschleife nur das Flag pollen. Das sieht vielleicht 
nicht so elegant aus, erfüllt aber seinen Zweck.

Wichtiger als irgendwelche Hardware-Spezialitäten ist es wohl, am Anfang 
eine ordentliche Aufstellung der zeitlichen Anforderungen aufzustellen. 
Diesen Punkt überspringen viele aus Faulheit und versuchen dann erst am 
Ende, den Schaden zu beheben. Gute Planung sind nach meiner Erfahrung 
4/5 der Programmiererei.

von Ferkel (Gast)


Lesenswert?

>Denn wenn etwas nicht
>schnell sein muss, warum dann überhaupt ein Interrupt?

Damit man nicht unnütz Zeit vergeudet, immer wieder ein Ereignis 
abzufragen und dennoch optimal schnell reagieren kann. Auch bei geringer 
Baudrate ist es besser, per RX-Interrupt einen Ringpuffer zu füllen, als 
dauernd das RXC-Bit zu pollen.

von Rolf Magnus (Gast)


Lesenswert?

Klaus 2m5 schrieb:
> Grolle schrieb:
>> Die Programmierin ist der Gott des Computers
>
> Die Programmzeile "Es werde Licht" hat bisher noch kein Compiler
> angenommen - oder ist das nur bei mir so?

http://www.bible-reading.com/godpc.html

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Tine Schwerzel schrieb:
> Wie handhabt ihr die Programmierung der IR Routinen? Versucht Ihr nur
> Flags zu setzen oder Variablen zu ändern, die dann im Hauptprogramm
> aufgerufen und endverarbeitet werden, oder packt ihr schon größere
> Längen Code in den Interrupt?

Es kommt nicht so sehr auf die Länge des Codes in der ISR an, sondern 
auf die Zeit, die der Code im Interrupt verbrät. Man kann durchaus 
größere Zustandsautomaten in der ISR programmieren. Wenn pro 
Interrupt-Durchlauf davon nur ein Bruchteil durchlaufen wird, ist alles 
im grünen Bereich.

Ich selbst habe für IRMP eine ellenlage ISR geschrieben - da würden sich 
bei einigen hier die Zehennägel hochkringeln. Tatsächlich wird aber pro 
Zustand...

 - Es bleibt "hell"
 - Es bleibt "dunkel"
 - Wechsel von "dunkel" auf "hell"
 - Wechsel von "hell" auf "dunkel"

nur immer ein Teil des Codes durchlaufen. Während der meisten Zeit 
(keine Taste an der IR-Fernbedienung gedrückt) ist die Durchlaufzeit 
sogar verschwindend gering. So kann ein 2 bis 3 kb großer Code durchaus 
auch in einer ISR vertretbar sein.

Daher halte ich die generelle Regel

    "Der Code in der ISR soll möglichst kurz sein"

für absurd und falsch. Eher könnte es heissen:

    "Eine ISR sollte möglichst schnell beendet werden"

Dies lässt sich durch intelligente Verarbeitung/Beschreibung von 
Zuständen (Flags) erreichen.

Gruß,

Frank

von Juergen (Gast)


Lesenswert?

> Die Programmzeile "Es werde Licht" hat bisher noch kein Compiler
> angenommen - oder ist das nur bei mir so?

Du mußt das natürlich korrekt formulieren.
Oder hast du noch nie eine LED angesteuert?

von Ulrich (Gast)


Lesenswert?

Es hängt sehr von der Aufgabe ab. Gerde die Programme auf kleinen µCs 
sind sehr verschieden.  Wenn es nur darum geht ein Falg zu setzen, 
braucht man oft gar keine ISR mehr, das Flag kann man oft direkt aus der 
Hardware Auslesen.

Die Länge der ISR reicht von nur einen Pin toogeln bis zum Extremfall wo 
praktisch das ganze Programm in einer ISR steht, inclusive Wartezeiten 
im Sekundenbereich: das Hauptprogramm hat nur noch die Initialisierung 
und eine Endlosschleife, die den µC in den Stromsparmodus versetzt.

Die Regel die ISR kurz zu halten, ist vor allem ein erster Anhaltspunkt, 
vor allem für Anfänger.  Wenn man weiss was man macht, ist fast alles 
erlaubt, auch eine ISR nicht normal zu beenden, sonderen nach Korrektur 
des Stacks an eine bestimmte Stelle des Hauptprogramms zu springen. Wenn 
jemand anders das Programm verstehen soll, braucht es dann aber guter 
Kommentare und ggf. etwas länger.

von Ralli (Gast)


Lesenswert?

Wenn ich keine IRQ-Prioritäten verteilen kann, darf jede ISR nur
genau so lange dauern, wie sie keine weitere ISRs behindert.

Der Rest ist doch nur Faustregel "Wie gehe ich als Anfänger ran".

Nutze ich einen µC für hardwarenahe Signalverarbeitung, kommt
manchmal raus, dass sich der Prozessor zu 99% seiner sinnvollen
Prozessortätigkeit in IRS-en betätigt...

von Peter D. (peda)


Lesenswert?

Juergen schrieb:
>> Die Programmzeile "Es werde Licht" hat bisher noch kein Compiler
>> angenommen - oder ist das nur bei mir so?
>
> Du mußt das natürlich korrekt formulieren.
> Oder hast du noch nie eine LED angesteuert?
1
LED0_DDR = 1;
2
LED0 = LED_ON;  // "Es werde Licht"

funktioniert bei mir einwandfrei.


Peter

von Klaus 2. (klaus2m5)


Lesenswert?

Peter Dannegger schrieb:
> Juergen schrieb:
>>> Die Programmzeile "Es werde Licht" hat bisher noch kein Compiler
>>> angenommen - oder ist das nur bei mir so?
>>
>> Du mußt das natürlich korrekt formulieren.
>> Oder hast du noch nie eine LED angesteuert?
1
LED0_DDR = 1;
2
LED0 = LED_ON;  // "Es werde Licht"
>
> funktioniert bei mir einwandfrei.

Funktioniert das auch mit einer LED von der Größe einer Sonne? Ich muss 
in 7 Tagen mit allem fertig sein!

von Daniel B. (dannyboy1994)


Lesenswert?

ich unterscheide das immer noch art des iinteruppts. Bei timerinterupts 
pack ich einfach  so viel rein wie geht, ohne das der nächste overflow 
interupt oder so stört. Bei ADC und AC interupts ist das etwas 
kritischer. Da pack ich nur sehr wenig rein. und verarbeite die daten 
anschließend im hauptprogramm.

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.