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
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..
Diverse Prozessoren (z.B. Intel 80C186) haben explizit mehrere Prioritätsstufen für Interrupts. Von daher ist es nicht nur möglich, sondern auch sinnvoll, diese zu benutzen. Du hast leider nicht gesagt, welchen µC Du benutzt.
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
Warum pakst du nicht die Display ansteuerung komplett in die Mainloop rein? Der Timerinterupt sezt dann einfach nur ein Flag das es wieder zeit ist für ne aktualisierung und gut ist.
> 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
@ 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
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
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.
> 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
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
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.
Läubi .. schrieb: > @gjlayde Sorry trinke kein Bier sonst hätt ichs mir mal angesehen :P hehe, ich hab's ehlich gesagt eher mit nem kultivierten Tee und lecker Keksen. Aber der Spruch geht eben mit "Bier". Der Code ist in der ISR in main.c http://www.gjlay.de/pub/morpheus/morpheus_2009-06-06.zip Aber ich wollte nicht diesen Thread kapern ;-) Johann
@ 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
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.
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
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.