Gewissensfrage: Interrupt durch Interrupt unterbrechen lassen

Gast #1289954
Hallo,

ich bin hier etwas in der Zwickmühle. Ich habe hier einen recht 
aufwendigen Timer Interrupt, welcher ein Grafik Display ansteuert und 
einen von der Mainloop jederzeit veränderbaren Text über das Display 
Scrollen lässt. Damit da nichts ruckelt, habe ich alles in die Interrupt 
Routine gesteckt.

Klappt auch alles soweit ganz gut. Jetzt möchte ich auf meinem RS-485 
Bus mitlauschen und ggf. auch Antworten. Wenn jetzt gerade der 
Bildschirm neu berechnet wird, gehen mir dann natürlich Zeichen im UART 
verloren. Der Befehl wird nicht richtig gelesen, der Master erwartet 
aber eine Antwort -> Timeout. Das Zieht natürlich den genzen Bus runter.

Habe jetzt schon versucht folgendes versucht:

timer0over:
push r2
push r16
in r2,sreg

  ldi r16,0
  out timsk,r16    ; timer interrupts sperren
  sei

  .
  .
  . Display Ansteuerung
  .
  .


  cli
  ldi r16,(1<<TOIE0)    ; timer interrupt wieder freigeben
  out timsk,r16

out sreg,r2
pop r16
pop r2
reti


Klappt auch alles Super, aber die Feine Art ist es ja ganz und gar 
nicht. Im Uart Interrupt werden dann dann lediglich die Zeichen gelesen 
und in einen Ram Buffer geschrieben, bis die Zeichenkette in der 
Mainloop abgeholt und verarbeitet wird.

Gibt es hier vielleicht eine elegantere Lösung? Oder ist sowas gängige 
Praxis?

Gruß,
Tubie
Gast #1289959
Warum soll das nicht die feine Art sein?

Soweit ich dich verstanden habe, lässt du einen Interrupt niedriger 
Priorität (Display Ansteuerung) durch einen Interrupt höherer Priorität 
(UART) unterbrechen.

Das einlesen der UART Chars in einen Buffer in einem Interrupt und die 
spätere Verarbeitung wenn Zeit dafür ist, ist eine saubere Lösung.

Wie sollte man das denn auch sonst lösen?

Also ich sehe hier kein Problem. Sorge nur dafür dass die UART ISR 
schlank und schnell ist..
Gast #1289971
Jo, das klingt ja schonmal ganz Positiv alles. Ich verwende hier einen 
MEGA32. Der Sperrt normalerweise beim Einsprung in eine Interrupt 
Routine alle anderen Interrupts.

Gruß,
Tubie
Gast #1289979
> Warum pakst du nicht die Display ansteuerung komplett in die Mainloop
> rein?

Das hatte ich auch am anfang so vor, allerdings ist die Mainloop 
mittlerweile so Komplex geworden, das ich nach jedem Zwischenschritt den 
Displaystatus abfragen müsste.

Da ist auch dann noch ein Befehlsinterpreter drin, welcher sich seinen 
Code aud einem I²C EEProm holen muß und ggf. auch ins EEProm screiben 
darf. Ist halt absolut Zeitunkritisch bis auf das Display.

Gruß,
Tubie
#1290004
@  Tubie (Gast)

>Das hatte ich auch am anfang so vor, allerdings ist die Mainloop
>mittlerweile so Komplex geworden, das ich nach jedem Zwischenschritt den
>Displaystatus abfragen müsste.

Glaub ich nicht. Alles eine Frage des Kozepts und der Organisation. 
Schau mal bei Multitasking rein, dort gibt es ein kleines Beispiel 
wie man das macht.

>Da ist auch dann noch ein Befehlsinterpreter drin, welcher sich seinen
>Code aud einem I²C EEProm holen muß und ggf. auch ins EEProm screiben
>darf.

Und?

MfG
Falk
Gast #1290040
So wie im 2. Beispiel habe ich es im Prinzip gelöst. Im Interrupt werden 
verschiedene Timer auf 0 runtergezählt. Wenn dies der Fall ist, wird für 
das entsprechende Unterprogramm ein Flag gesetzt. Alle unterprogramme 
werden in der Mainloop nacheinander aufgerufen. Wenn das Entsprechende 
Flag gesetzt wurde, wird das entsprechende Unterprogramm auch 
abgearbeitet, ansonsten gleich wieder verlassen.

Jedes Unterprogramm kann wiederum Flags setzten, auf welche wiederum 
andere Unterprogramme zugreifen können. So wird zum Beispiel beim 
empfang eines korrekten Befehles über die Uart ein Flag gesetzt, welches 
das Uart Ausgangs Programm dazu veranlasst nach Prüfung des Busses eine 
Antwort auf den Bus zu senden.

Bei korrekter Planung ist ja fast alles möglich. Kann aber nicht wegen 
einer kleinen Änderung alles wieder über den Haufen werfen. Was zum 
jetztigen Zeitpunkt nicht bedacht wurde, muß halt irgendwie angepasst 
werden oder wegfallen. Dass habe ich mir bei der Laufschrift gesagt - 
wäre schön, wenns gehen würde muß aber nicht unbedingt sein.


Gruß,
Tubie
Persönliche Seite #1290072
Pack doch das Display zeug ganz anz Ende der Mainloop. Wenn alle anderen 
Tasks abgearbeitet sind wird das Display einmalig aktualisiert, danach 
geht es in die nächste Runde.
Ob Das Display alle 500ms oder alle 700ms oder vieleicht alle 1200ms 
aktualisiert wird sollte in den meisten Fällen doch überhaupt nicht 
stören.
Gast #1290106
> Ob Das Display alle 500ms oder alle 700ms oder vieleicht alle 1200ms
> aktualisiert wird sollte in den meisten Fällen doch überhaupt nicht
> stören.

Gerade das ist mein Problem bei den Vorgänger Schaltungen mit Text 
Display (4x20) war das egal. Jetzt habe ich ein Grafik Display (122x32) 
Theoretisch auch noch egal. Aber in der unteren Zeile eine Laufschrift 
(Wie bei den Nachrichtensendern die Börsenkurse unten durchlaufen). Da 
ist es ganz ganz wichtig, das die immer zum gleichen Zeitpunkt wieder 
aktualisiert wird. Sonst Stottert es gewaltig.

Gruß,
Tubie
Persönliche Seite #1290130
In mehreren AVR-ANwendungen hab ich auch 2 IRQ-Ebenen: Eine 
unterbrechbare, und eine nicht-unterbrechbare. Funktioniert prächtig.

Entgegen allen Empfehlungen enthält die unterbrachbare ISR sogar eine 
Endlosschleife nach folgendem Strickmuster:
1
ISR (timer)
2
    disble-timer-irq
3
    global-enable-interrupts
4
    =label=
5
    # mach was
6
    IF timer-irq-flag
7
       clear-timer-irq-flag
8
       GOTO =label=
9
    global-disable-interrupts
10
    enable-timer-irq

Die ISR ist recht aufwändig (wer mir sagt, wie sie einfacher zu bekommen 
ist, dem geb ich'n Bier aus :-)). Sie darf unterbrochen werden von einer 
Kommunikations-ISR, die eingehende Daten speichern muss.

Die Schleife dient dazu, je einen ISR-Prolog und -Epilog zu sparen, wenn 
die Timer-ISR lange dauert.

Johann
Persönliche Seite #1290160
Das Problem bei langen IRQs ist doch, das im schlechtesten Fall der IRQ 
sofort wieder aufgerufen wird.

@Laufschrift:
Lass die Laufschrift im Timer IRQ laufen, den rest in Main, ne neue 
Laufschrift wird auch erst in der "Main" gesezt während die Interupts 
gesperrt sind.

@gjlayde Sorry trinke kein Bier sonst hätt ichs mir mal angesehen :P
Aber das was du in der IRQ machst (die Schleife) könnte man sicher ins 
Hauptprogramm auslagern.
#1290190
@  Tubie (Gast)

>ist es ganz ganz wichtig, das die immer zum gleichen Zeitpunkt wieder
>aktualisiert wird. Sonst Stottert es gewaltig.

Logisch. Aber das kann man schon in einem Timer-Interrutp machen OHNE 
dass der UART-Interrupt zu sehr ausgebremst wird und ohne dass 
verschachtelte Interrupts benötigt werden. Der Trick ist ganz einfach. 
Möglichst viel in der Main-Loop vorausberechnen und im Timer nur noch 
ausgeben. Einige machen das so, dass sie im Timerinterrupt immer nur EIN 
Zeichen auf dem LCD neu schreiben. Das erspart das lange Warten zwischen 
den Zeichen (Abfrage des Busy-Flags macht das nicht wesentlich 
schneller).

MfG
Falk
Gast #1290192
Mach es doch einfach so, wie du es dir bereits ueberlegt hast. Der 
Displayinterrupt gibt die Interrupts wieder frei, Problem geloest. Wenn 
du damit rechnen musst, dass der Displayinterrupt mal laenger laufen 
koennte als sein Interruptintervall, sicherst du das einfach mit einem 
Flag ab.
Gast #1290488
So, vielen dank für die ganzen Antworten!

Bin jetzt zum Entschluß gekommen, allse so zu lassen, da es ja jetzt 
auch funzt. Beim nächsten mal werde ich wie oben beschrieben immer nur 
einen Teil im Interrupt machen lassen und die Vorberechnungen in der 
Mainloop. Könnte zwar noch machbar sein wird aber ein relativ großer 
Aufwand.

Danke nochmals,
Tubie

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 17 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.