Hi! In meinem aktuellen Bastelprojekt (Atmega32, avr-gcc) möchte ich eine Funktion, die als "scheduler" abwechselnd verschiedene Dinge tut, mehr oder weniger regelmäßig aufrufen. Dies soll immer geschehen, egal wo das Programm gerade ist. Normalerweise würde ich dafür einen Timer mit ISR nehmen. Das Problem ist aber, dass die Jobs des "schedulers" durch ISRs unterbrochen werden dürfen sollen müssen. Wenn ich den Scheduler aus einer ISR heraus aufrufe, würden ja auch alle vom Scheduler aufgerufenen Funktionen/Jobs innerhalb der ISR laufen. Mit allen Konsequenzen (volatile-Deklarationen usw). Meine aktuelle Lösung ist im Moment, aus jeder Schleife im Programm, die längere Zeit laufen kann (z.B. Warten auf Eingaben usw.) die Scheduler-Funktion aufzurufen. Das finde ich aber nicht wirklich elegant. Geht das auch anders? Wie funktionieren die unterbrechbaren Interrupts? Gruß, Chris
Chris schrieb: > jeder Schleife im Programm, die > längere Zeit laufen kann (z.B. Warten auf Eingaben usw.) Besser die Programmstruktur ändern und diese Schleifen ersetzen Das Programm kann doch immer: Eingaben abfragen Ausgaben abhängig von Programmzuständen machen Sceduler aufrufen wenn ein Blinktakt gerade 1 ist usw.....
>Wie funktionieren die unterbrechbaren Interrupts?
Die werden mit INTs höherer Prio unterbrochen. (Der mit der höchsten
Prio kann nicht mehr unterbrochen werden)
Du kannst alles einfach nur INT-basiert aufrufen, auch mit (mehreren)
Timer-INT.
GGfs mehrere Timer-INTs, damit bei längeren Intervallen auch 'Platz' für
mehrere Befehle ist.
(Main hätte sozusagen die niedrigste Prio)
MCUA schrieb: >>Wie funktionieren die unterbrechbaren Interrupts? > Die werden mit INTs höherer Prio unterbrochen. (Der mit der höchsten > Prio kann nicht mehr unterbrochen werden) Nicht auf dem AVR. Da entscheidet die Priorität nur darüber, welche ISR aufgerufen wird wenn mehrere Interrupts GLEICHZEITIG anliegen. Eine ISR wird nicht durch eine andere ISR unterbrochen. (Es sei denn, man setzt das I-Flag in der ISR. Dann kann es aber auch passieren, das sie sich selbst unterbricht. Nur für Profis, die genau wissen was sie tun!)
>Nicht auf dem AVR. Da entscheidet die Priorität nur darüber... Von wegen. Der einfache AVR hat nichtmal verschiedene INT-Prio-Ebenen!! (XMEGAS habens) (Die Aufruf-Priorität innerhalb gleicher INT-Prio-Ebenen ist dazu untergeordnet)
So besonders schwierig ist das nicht eine ISR unterbrechbar zu machen. Man gibt per SEI() interrupts wieder frei - entweder von Hand, oder man sagt dem Compiler das das gleich noch in der Einleitung so kommt. Aufpassen muss man vor allem das der selbe Interrupt nicht noch einmal kommt, bevor die eine Version des Interrupts abgearbeitet ist. Bei einem Timer Interrupt geht das meist über eine nicht zu hohe Frequenz für den Interrupt. Einen externen Interrupt, der schneller kommen kann, muss man ggf. von Hand abschalten. Man braucht zusätzlichen Platz auf den Stack für eine zusätzliche ISR. Hinsichtlich volatiler Variablen gibt es eigentlich nichts weiter zu beachten - so weit ich weiss macht das GCC keinen Unterschied in der ISR zu normalem Code. Es wird also nicht angenommen oder ausgenutzt das die ISR nicht unterbrechbar ist. Für andere CPUs wäre das ja ggf. auch ein Fehler.
Chris schrieb: > In meinem aktuellen Bastelprojekt (Atmega32, avr-gcc) möchte ich eine > Funktion, die als "scheduler" abwechselnd verschiedene Dinge tut, mehr > oder weniger regelmäßig aufrufen. Dies soll immer geschehen, egal wo das > Programm gerade ist Die Denkweise ist falsch. Einfacher und nachvollziehbarer wird es so: in deiner Software gibt es eine Haupptschleife, die dauernd schnellstmöglich durchlaufen wird. Keine Abzweigung aus dieser Schleife darf länger als z.B. 10ms dauern. D.h. wenn du 10 Abzweigungen hast, kannst du dann sicher sagen: jede Abzweigung in der Hauptschleife wird mindestens alle 100ms abgefragt. Und diese Abzweigungen werden dann von kurzen und knackigen Interrupts bestimmt: "ein Zeichen ist von der SIO gekommen", "schon wieder eine Sekunde vorbei", usw. Andere Gründe für eine Abzweigung können sein: ein Eingang hat sich geändert, eine Taste wurde gedrückt... So funktionieren weltweit SPSen zur Zufriedenheit zigtausender Anwender. Und lustigerweise wissen da viele nicht mal, dass sie einen Automaten programmiert haben (die nennen das dann Merkerkette). Also: Hauptschleife: Eingangssabild einlesen. Berechnungen durchführen. Ausgangsabbild schreiben. Springe zur Hauptschleife
Chris schrieb: > Meine aktuelle Lösung ist im Moment, aus jeder Schleife im Programm, die > längere Zeit laufen kann ... die > Scheduler-Funktion aufzurufen. In Häppchen aufteilen. Nach Abschluss eines Happens ggf. prüfen was ansteht und was das wichtigste ist. Die ISR setzt Flags was zu tun ist. Chris schrieb: > z.B. Warten auf Eingaben usw. Die ISR erkennt die Eingabe und setzt ein Flag. Wenn das Flag "neue Eingabe" gesetzt ist wird die mit eher hoher Priorität abgearbeitet. Auf Eingabe warten würde ich nie im Hauptprogramm, außer es kann bis zur Eingabe definitiv nichts anderes anfallen. In die ISR kommt nur Code mit schlankem Fuß, oder Dinge die zwingend sofort gemacht werden müssen (z.B. Software-PWM). Verschachtelte ISRs machen Programme schnell zum Glücksspiel. Eine Zusatzfunktion, eine Verschachtelung kommt dazu und schon gibts schwer reproduzierbare Fehler.
a) Wie wär es mit einem RTOS? b) State-Machines? Jede Aufgabe wird mit einer State-Machine kontrolliert in Teilen abgearbeitet.
>So funktionieren weltweit SPSen zur Zufriedenheit zigtausender Anwender.
..die aber alle rel. langsame Zeitanforderungen haben
Ein spezielles uC-System kann aber viel zeitkritischer (ms, us, einige
ns) sein, als die typ. SPS, die alle Eingänge u Ausgänge mit gleicher
Zeitspanne (typ einige zig ms) bearbeitet. Dafür bräuchte die CPU
nichtmal Interrupts zu können.
Hallo, man muss halt geeignet strukturieren (wenn man kein RTOS verwenden will, dass einem das Nachdenken abnimmt): alle Ereignisse, die eine Reaktion in Echtzeit erfordern, werden in ISRs abgearbeitet, die aber nur so schnell wie möglich das unbedingt Nötige tun, z.B. auf Rx-Int ein Zeichen vom UART holen und in den Eingangpuffer schieben. Warteschleifen in ISRs sind kapitale Fehler, ebenso länger dauernde Programmteile. Dann kann das Hauptprogramm ganz entspannt in einer Endlosschleife die nötigen Tasks abarbeiten, darunter z.B. die Reaktion auf ein empfangenes Zeichen (Interpretation, Änderung des Zustands). Natürlich muss die Gesamtleistung stimmen, z.B. muss das Hauptprogramm sich um Eingaben kümmern, bevor der Eingabepuffer überläuft. Man kann auch die hardwareseitigen Ein/Ausgaben in einer einzigen Timer-ISR abarbeiten, wenn der Zeitrahmen reicht. Wenn etwa die Baudrate max. 9600 Baud beträgt, kann ein Timerinterrupt mit 1 ms durchaus einige UARTs bedienen. Die ISR darf nur nicht auf ein Zeichen warten, sondern nur prüfen, ob eins da ist, wenn nicht, weiterspringen, kriegen wir nächstesmal. Gruss Reinhard
Die oben schon aufgeführten Methoden werden in diesem Artikel sehr gut erklärt bis es dann tatsächlich zum "echten" Multitasking übergeht. Das muß vielleicht nicht sein für deine Anwendung aber die Erklärung zu Hauptschleife + "Call der einzelnen Funktionen" ist sehr gut erklärt. http://www.mikrocontroller.net/articles/Multitasking
Hm, ein interessantes Thema :) Ich werde versuchen, mein Programm zumindest in Teilen umzubauen. Dazu habe ich z.B. schon die 1wire-Funktionen zerlegt, da die Dallas-Temperaturfühler ja fast eine Sekunde für die Wandlung benötigen. Bisher war mein Programm in dieser Zeit blockiert. Jetzt startet ein Job des Schedulers die Wandlung, ein weiterer rund 2 Sekunden später holt das Ergebnis.
MCUA schrieb: >>Wie funktionieren die unterbrechbaren Interrupts? > Die werden mit INTs höherer Prio unterbrochen. (Der mit der höchsten > Prio kann nicht mehr unterbrochen werden) Das halte ich aber auch für ein Gerücht zumal hier von Atmega32 die Rede war. Mir fällt das auf, da ich diesem Irttum auch schon aufgessen war. Im Atmega Datenblatt gibt es ja die schöne IRQ Tabelle. Offenbar hatte ich das ungeprüft ins Hirn übernommen und gedacht es wäre eine Prioritätentabelle (so wie damals beim 8086 PC). Es ist wohl nicht so. Ulrich, Lothar, Stefan sagten ja schon einiges dazu. Auch ich möchte meine Betrachtungsweise mal beitragen. Wenn die Hauptschleife nur aus : Do Loop bestehen würde wäre das doch schon Prima. Alle IRQ laufen dann schön hintereinander ab. Nun könnten wir das ganze noch etwas verfeinern indem wir in einer Timed-IRQ (Scheduler) einen Satz ToDo-Flags abragen (nur abfragen) Die müssen dann je nach Priorität auf einen kleinen hausgemachten Stack (ein array z.B.) . Nun könne wir, wohl überlegt in der Hauptschleife noch ein paar If Abfragen einbauen die dann diesen ToDostack bearbeiten. Bin nicht sicher, ob mein Beitrag hilft aber es vielleicht ein denkansatz indem man das Hauptprogramm leer lässt. Gruss Klaus de Lisson
Klaus De lisson schrieb: > Im Atmega Datenblatt gibt es ja die schöne IRQ Tabelle. > Offenbar hatte ich das ungeprüft ins Hirn übernommen und gedacht > es wäre eine Prioritätentabelle (so wie damals beim 8086 PC). > Es ist wohl nicht so. In gewissem Sinne doch. Liegen mehrere Intterruptbedingungen gleichzeitig vor, werden die mit niedrigerer Vectornummer zuerst behandelt.
Ich schrieb: die Erklärung zu Hauptschleife + "Call der einzelnen Funktionen" ist sehr gut erklärt. Oh je, sollte heißen : die Erklärung zur Hauptschleife + " Call der einzelnen Funktionen " ist sehr gut geschrieben.
... schrieb: > Klaus De lisson schrieb: >> Im Atmega Datenblatt gibt es ja die schöne IRQ Tabelle. >> Offenbar hatte ich das ungeprüft ins Hirn übernommen und gedacht >> es wäre eine Prioritätentabelle (so wie damals beim 8086 PC). >> Es ist wohl nicht so. > > In gewissem Sinne doch. Liegen mehrere Intterruptbedingungen > gleichzeitig vor, werden die mit niedrigerer Vectornummer zuerst > behandelt. Muss man sich dann auch nochmal explizit merken. .. und die verschiedenen Intterruptbedingungen können sich ja ordenlich anhäufen. allerdings gibt es keinen IRQ Stack. Dadurch werden Mehrfachanforderungen ignoriert klaus de lisson
>Das halte ich aber auch für ein Gerücht zumal hier von Atmega32 >die Rede war. sagte ich doch oben: >>Nicht auf dem AVR. Da entscheidet die Priorität nur darüber... >Von wegen. Der einfache AVR hat nichtmal verschiedene INT-Prio-Ebenen!!
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.