Forum: Mikrocontroller und Digitale Elektronik Funktion regelmäßig im "Hintergrund" ausführen, aber nicht per ISR (oder doch?)


von Chris (Gast)


Lesenswert?

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

von Simon H. (der_hier)


Lesenswert?


von Düsendieb (Gast)


Lesenswert?

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.....

von MCUA (Gast)


Lesenswert?

>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)

von Uwe .. (uwegw)


Lesenswert?

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!)

von MCUA (Gast)


Lesenswert?

>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)

von Ulrich (Gast)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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

von Stephan (Gast)


Lesenswert?

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.

von Coder (Gast)


Lesenswert?

a) Wie wär es mit einem RTOS?
b) State-Machines? Jede Aufgabe wird mit einer State-Machine 
kontrolliert in Teilen abgearbeitet.

von MCUA (Gast)


Lesenswert?

>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.

von Reinhard Kern (Gast)


Lesenswert?

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

von 900ss (900ss)


Lesenswert?

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

von Chris (Gast)


Lesenswert?

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.

von Klaus D. (kolisson)


Lesenswert?

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

von ... (Gast)


Lesenswert?

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.

von 900ss (Gast)


Lesenswert?

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.

von Klaus D. (kolisson)


Lesenswert?

... 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

von MCUA (Gast)


Lesenswert?

>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
Noch kein Account? Hier anmelden.