Multitasking im Mikrocontroller

Hallo,

es wird ja bei Mikrocontrollerprojekten oft eine Art Multitasking im Mikrocontroller implementiert, da z.B. alle paar Millisekunden eine Tastatur abgefragt werden soll...dann werden evtl. noch

7-Segment-Anzeigen durch Multiplexing angesteuert um Ports zu sparen...

Wie wird dieses Multiplexing denn programmtechnisch (interessant wäre Assembler und C) realisiert? Wie werden die Tasks zeitlich verwaltet? Weil ja z.B. beim 7-Segement-Multitasking die Segmente alle gleich lang angesteuert und gleich lang stromlos sein sollten, dass die Helligkeit einigermaßen stimmt.

Ich weiß zwar, dass dies eine Elektronik-Newsgroup ist und keine über's Programmieren...aber hier wird es sicher einige Programmierer geben, die sowas schon des Öfteren implementiert haben.

Mir ist auch bekannt, dass es zig verschiedene Arten von Multitasking gibt, aber vielleicht kann mir trotzdem jemand kurz auf die Sprünge helfen, wie ich sowas am einfachsten in nen Controller implementiere.

Danke,

Thomas

Reply to
Thomas Finke
Loading thread data ...

"Thomas Finke" schrieb im Newsbeitrag news: snipped-for-privacy@4ax.com...

Vergiss den Begriff Multitasking. So etwas gibt es nur ganz selten.

Was gemacht wird heisst 'ereignisgesteuert' (event driven) und die Ereignisse beim uC sind Interrupts, vor allem vom Zeitgeber (timer).

Wenn also jede Millisekunde die naechste Stelle ins Display soll, dann wird auf einen Zeitgeber-Interrupt das Hauptsprogramm unterbrochen und eine Funktion ausgefuehrt, die eben die naechste Stelle ins Display schreibt und danach zurueckkehrt.

Das Hauptprogramm macht (nach Initialisierung des Zeitgebers und der Ports) irgendwas unwichtiges (Daeumchen drehen :-)

Alternativ fuer ganz einfache Faelle macht das Hauptprogramm der Reihe nach ALLES und wiederholt sich gleich wieder in einer Schleife. Bei jeder Einzelaktion wird gefragt, ob sie in dieser Runde auch ausgefuehrt werden soll, oder uebersprungen wird.

for(;;) { if(tasten) tastenlesen(); if(display) zeigedaten(); ausgangspinssetzen(); }

Man /kann/ so ein Programm so schreiben, das es auf jedem Weg immer dieselbe Zeit braucht, dann kann es SCHNELL und GENAU reagieren und das kann leicht GARANTIERT werden.

for(;;) { if(tasten) tastenlesen(); else vertue(12); if(display) zeigedaten(); else vertue(22); ausgangspinssetzen(); }

--
Manfred Winterhoff, reply-to invalid, use mawin at gmx dot net
homepage: http://www.geocities.com/mwinterhoff/
de.sci.electronics FAQ: http://dse-faq.elektronik-kompendium.de/
Read 'Art of Electronics' Horowitz/Hill before you ask.
Lese 'Hohe Schule der Elektronik 1+2' bevor du fragst.
Reply to
MaWin

In den guten alten 8-Bit-Tagen hieß das einfach nur Interrupt -- Multitasking hatten die Schnösel mit dem Amiga ;-)

Will sagen: Echtes Multitasking -- ob kooperativ oder präemptiv -- ist mehr als Du auf einem µC typischerweise brauchst: Du brauchst nicht n Anwenderprogramme gleichzeitig -- es genügt, wenn der Prozessor sein

*eines* Anwenderprogramm (oder auch seinen Schönheitsschlaf) regelmäßig unterbricht, um sich Systemaufgaben wie der nächsten Ziffer in der Multiplex-Anzeige oder der Tastaturabfrage zu widmen.

Ein Timerinterrupt alle paar Millisekunden sollte genügen. Michael

Reply to
Michael J. Schülke

Und das wird bei jedem Timer-Interrupt neu festgelegt, was beim nächsten Durchgang ausgeführt werden soll und was nicht? Gibt's da wiederum eine Struktur die man einhalten sollte, damit die Interrupt-Routine nicht zu groß wird?

Dann noch ne Frage zu den eigentlichen Funktionen die aufgerufen werden sollen. Ich habe mal gesehen, dass sehr zeitintensive Funktionen immer nur einen kleinen Teil des Programmcodes abarbeiten, dann die Funktion verlassen...damit andere Funktionen auch mal zum Zuge kommen...und beim nächsten Aufruf arbeitet die Funktion an der Stelle weiter wo sie vorher rausgesprungen ist...das ganze halt durch ne Variable gemerkt wo es weitergehen soll. Wird dies auch so verwendet? Wenn ja, ist es ok die Funktion einfach zu verlassen und z.B. mit einer SELECT CASE Struktur abzufragen wo es weitergehen soll....oder gibt es da nen besseren Weg?

Thomas

Reply to
Thomas Finke

Idealerweise baut man sich eine State-Machine, in dem Fall auch einfach mitzählen :-)

void oninterrupt() { digit=(digit+1)%4; ShowDigit(digit); }

oder so...

Es sollte einfach möglichst wenig unnötiger (Prüf-)Code ablaufen.

Idealerweise packt man die langen Funktionen ins Hauptprogramm und die kleinen Funktionen die auch mal zum Zug kommen sollen in den Interrupt, dann funktioniert das verlassen und weitermachen nämlich automatisch. Ansonsten ist eine State-Machine per switch case vermutlich keine schlechte Idee...

Reply to
Andreas Koch

"Thomas Finke" schrieb im Newsbeitrag news: snipped-for-privacy@4ax.com...

Beim Dispaly: Beim naechsten ist halt die Stelle um 1 hochgezaehlt, die Funktion nimmt sich die naechste Stelle vor.

Na, wenn dein Programm jede Millisekunde einen Zeitgeber-Interrupt ausloest, ist es halt doof, wenn die Zeitgeber-Funktion laenger als 1 msec braucht.

Wenn das nur 1 Funktion ist, macht man das im Hauptprogramm, das dreht sonst ja nur Daeumchen.

Kommt drauf an. Letztlich ist immer DAS EINFACHSTE der beste Weg.

(Bruce Eckel: Subtraction: a design is finished when you cannot take anything else away)

Wie weit du ein Programm vereinfachen kannst (damit es immer noch seine Aufgabe erfuellt) liegt an dir, gute Programmierer machen halt einfache kleine schnelle uebersichtliche Programme.

Es kann sinnvoll (notwendig) sein, beim Interrupt erst mal nur eine kurze Funktion auszufuehren (schnelle Reaktion), dabei einen Wert zu setzen der 'Nacharbeit' ankuendigt, und diese Nacharbeit weniger wichtig ausfuehren zu lassen (dabei sollte die Nacharbeit aber nicht pro Ereignis stattfindne, sondern viele Ereignisse zusammenfassen), und wenn nichts zu tun ist macht man ganz unwichtiges.

--
Manfred Winterhoff, reply-to invalid, use mawin at gmx dot net
homepage: http://www.geocities.com/mwinterhoff/
de.sci.electronics FAQ: http://dse-faq.elektronik-kompendium.de/
Read 'Art of Electronics' Horowitz/Hill before you ask.
Lese 'Hohe Schule der Elektronik 1+2' bevor du fragst.
Reply to
MaWin

Naja, oft wohl eher nicht.

Das macht man mit Interrupts.

Das steht bei Assembler im Handbuch des Prozessors, und bei C im Handbuch des Compilers. Und das ist auch keinesfalls zwischen verschiedenen CPU-Typen 1:1 uebertragbar. Lediglich das Konzept kann man mitnehmen. Aber auch da kann man auf die Nase fallen. Z.b hat es mich oft geraergert das die AVRs keine priorisierten IRQs kennen.

An erster Stelle im Hirn des Programmierers. Soll heissen du musst wissen wie wichtig eine bestimmte Aufgabe ist und wie oft sie auftritt.

Timer-IRQ.

Olaf

Reply to
Olaf Kaluza

Du solltest sicherstellen das die IRQ-Routine nicht laenger dauert als die Zeit bis zum naechsten IRQ. :-) Das kannst du z.B durch abzaehlen der Taktzyklen erreichen. Oder man setzt am Eingang einen Port und loescht dem am Ausgang und schaut sich am Ossi das Taktverhaeltnis an.

Nein, eher nicht.

Ich wuerde so ein Vorgehen fuer toedlich halten was das Verstaendnis eines Programmes angeht. Es ist besser sich vorher genau Gedanken zu machen was ein Programm machen soll und in wie du es am besten aufteilen kannst. Dann gibt es Dinge die wirklich wichtig sind und andere Dinge koennen warten. Z.B darf eine Ansteuerung eines gemultiplexten Segments nichts aus dem Tritt geraten. Allerdings reicht es aus im wichtigen IRQ wirklich nur die einzelnen Segmente auszugeben. Das berechnen von Ausgabewerten und die Uebernahme davon kann dagegen irgendwann mal geschehen.

Ausserdem sollte man Dinge die sehr wichtig sind und immer statt finden muessen, sehr kurz halten.

Olaf

Reply to
Olaf Kaluza

Du musst zunächst zwischen präemptiven (also verdrängendem) und kooperativen (nichtverdrängendem) Multitasking unterscheiden.

Kooperatives Multitasking bedeuted einfach nur, dass die Aufgaben abwechselnd drankommen und jede einzelne Aufgabe (jeder "Task") jeweils "abgibt", wenn ein Teil seiner Arbeit fertig ist. Nachteil hier ist, dass falls ein Task abstürzt, das ganze System steht: wenn du also beispielsweise einen Task hast, der ein LCD-Display aktualisieren soll und auf ein Busy-Flag wartet. Das LCD wird abgesteckt oder geht kaputt, dadurch wird Busy dauerhaft HIGH. Wenn dein einzelnes Programm diesen Fall nicht abprüft, steht das System (hängt sich auf). Vorteil ist, dass du recht wenig Overhead zum Managen der Tasks hast.

Beim präemptiven Multitasking können alle Prozesse so programmiert werden, als würden sie als einziges Programm auf der Maschine laufen: alle heilige Zeit kommt ein Timer-Interrupt, der dann den Scheduler aufruft. Der Scheduler merkt sich, welcher Prozess gerade aktiv war und an welcher Stelle im Code dieser Prozess sich gerade befunden hat. Dazu sichert er dann alle CPU-Flags (beispielsweise aus einer Compare-Operation die Condition Codes) sowie den Stackpointer an eine definierte Stelle im speicher. Dann werden all diese Werte "verbogen", also die CPU-Flags von Prozess2, der SP von Prozess2 und die Condition Codes geladen und an die Stelle zurückgesprungen, an der Prozess2 zuletzt war. Vorteil hier: wenn der Scheduler funktioniert, kann das System nicht abstürzen, nur einzelne Prozesse. Nachteil: du musst vorher wenigstens ein bischen über das Speicherlayout nachdenken. Wenn du also mehrere "virtuelle" Stacks auf einen physikalischen Stack abbildest, definierst du einfach vorher, dass von Memorystelle 0-31 alles Prozess1 gehört, von 32-63 alles Prozess2 und so weiter. Wenn du einen einfachen uC nimmst, der keine MMU und damit auch keine Speicherschutzmechanismen anbietet, dann können Prozesse in den Speicherraum der anderen Prozesse reinschreiben (wenn beispielsweise rekursive Funktionen einen zu hohe Schachtelungstiefe erreichen). Das wäre also _die_ Katastrophe für so eine Systemarchitektur.

Wie auch immer: es ist ein Haufen Aufwand, präemptives Multitasking zu realisieren. Viel einfacher ist kooperatives MT. Auch beim Scheduling (also das Verteilen der Zeitscheiben) kannst du nach belieben vorgehen: es gibt einfache RR-Scheduler (Round-Robin, also einer nach dem anderen), SPF (Shortest Process First => der Prozess, der als nächstes wohl die geringste Zeit braucht, kommt dran) bishin zu komplexen MFQ (Multilevel Feedback Queue - mehrere "gestackte" FIFO-Warteschlangen) - ein Verfahren, das z.B. unter Solaris zum Einsatz kommt (und IIRC sogar patentiert ist).

Viele Grüße, Johannes

Reply to
Johannes Bauer

Ich schreibe gerade an einem Firmware-Handbuch. Da sind solche Sachen mannigfaltig erklärt.

formatting link

kann einen Eindruck vermitteln.

--
Mit freundlichen Grüßen
Helmut Schellong   var@schellong.biz
www.schellong.de   www.schellong.com   www.schellong.biz
http://www.schellong.de/c.htm
Reply to
Helmut Schellong

Hallo,

MaWin schrieb:

Man kann Programme schreiben, wo nach der Initialisierung alles in der Interruptserviceroutine läuft, Siebensegmentanzeige multiplexen, Tastatur abfragen und entprellen Sekunden, Minuten und Stunden zählen usw. Das Hauptprogramm besteht nur aus einem Jump auf sich selber (dynamischer Halt - Daeumchen drehen).

Funktioniert bei mir in mehreren Küchen- und Belichtungstimern seit Jahren prima :-)

Gruß Reinhard

Reply to
Reinhard Richter

"Thomas Finke" schrieb .

Hallo Thomas,

dafür brauchst du einen Timerinterrupt und sonst nichts. Wenn du mehrere Programmteile mit langen Rechen oder Wartezeiten hast, dann macht (einfaches) Multitasking einen Sinn. Die rechenintensiven Teile werden dann scheibchenweise abgearbeitet, wenn nichts wichtigeres zu tun ist. Die wartenden Teile werden schlafen gelegt und durch das Ereignis auf das sie warten wieder aufgeweckt. Aber wie schon gesagt ... Richtiges Multitasking mit Kommunikation und Synchronisation zwischen Tasks sind aber auf Micros selten.

Gruß

Hans-Georg

Reply to
Hans-Georg Lehnard

Die Sprache ADA-97 ist per Definition Multitasking-f=E4hig, hat aber auch Elemente der Interrupt-Steuerung.

Leider war die Sprache ein Flop, da sie kaum genutzt wurde und sich gegen C nicht durchsetzen konnte. (ist grob gesagt ein abgewandeltes C). Jedenfalls gibt es seit einiger Zeit keine neuen Compiler mehr, da die USA die Gelder gestrichen hat.

Man hat sie im selben Minitsterium umgeschichtet um aktive =DCberzeugungsarbeit mit Diskutierwerkszeugen gegen den Terrorismus zu f=FChren --> F wie Frieden.

Es soll auch Varianten f=FCr diverse Microcontroler gegeben haben, welche genau konnte ich nie in Erfahrung bringen.

Andere Sprachen lassen Multitasking simulieren (hatte mal ein Buch zu Pascal liegen)

Reply to
Stefan Engler

Wenn die IRQ-Routine nur manchmal länger dauert, als das Timer-Intervall, kann man bei einigen Microcontrollern, z.B. 8031 auch eine Zieladresse auf den Stack schreiben und ein RETI (Return from Interrupt) ausführen. Das Programm verzweigt dann an die Zieladresse, an der der zeitaufwändige Teil abgearbeitet wird. Der Timer-Interrupt kann dann zwischendurch erneut aufgerufen werden. Das funktioniert z.B. dann, wenn du für eine kurze Routine einen 100us Int benötigst und jedes

1000. Mal eine längere Routine aufrufen willst.

mfg

Stefan

Reply to
Stefan Bröring

Da müssen sie aber schwer geändert haben, früher wurde Ada als aufgemotztes Pascal gehandelt. Es gab ehedem als Ausgangspunkt eine Liste vorhandener Sprachen die analysiert wurden ob sie als Grundlage für Ada dienen könnten. Z.B. auch Pearl, nicht aber FORTH, bei C hat DoD bei Bell Labs nachgefragt wo ihnen beschieden wurde für sicherheitskritische Anwendungen ungeeignet, sodaß auch C nicht auf der Liste war. Am Ende der Vorauswahl war die einstimmige Meinung das Pascal die beste Grundlage sei. Wobei ein Teilnehmer nachträchlich allerdings feststellte es wäre damals politischer Selbstmord gewesen nicht zu sagen man nehme Pascal als Ausgangspunkt wenn man in die nächte Runde des Auswahlverfahrens kommen wollte.

DoD hat keine Subsets erlaubt also war Float erforderlich. Der typische Prozessor war damit Mil-Std-1750 der Float im Microcode mitmachte.

MfG JRD

Reply to
Rafael Deliano

Eine Methode die ich gerne anwende ist, eine Zählervariable im RAM zu definieren, die vom Timerinterrupt (den braucht man eigentlich immer) dekrementiert wird (es sei denn sie ist bereits 0).

Das Hauptprogramm kann sich dann einfach alle N Interrupts wecken lassen, indem es N in den Counter schreibt und darauf wartet, daß er 0 wird. Wenn die CPU sowas unterstützt, packt man noch ein WAIT oder SLEEP in die Schleife um die CPU bis zum nächsten Interrupt schlafen zu legen.

XL

Reply to
Axel Schwenke

"Stefan Engler" schrieb im Newsbeitrag news: snipped-for-privacy@g43g2000cwa.googlegroups.com...

Leider war die Sprache ein Flop, da sie kaum genutzt wurde und sich gegen C nicht durchsetzen konnte. (ist grob gesagt ein abgewandeltes C). Jedenfalls gibt es seit einiger Zeit keine neuen Compiler mehr, da die USA die Gelder gestrichen hat.

Hallo Stefan,

da muss ich dir etwas wiedersprechen ;-). Beim Militär und der Luftfahrindustrie wird ADA sehr wohl verwendet. Dort benutzt man sogar stellenweise redundante Hardware einmal mit C und einmal mit ADA programmiert. Sonst ist aber C die Norm. Embedded C++ konnte sich bisher noch nicht durchsetzen.

Gruß

Hans-georg

Reply to
Hans-Georg Lehnard

"Axel Schwenke" schrieb

Hallo Axel,

welcher Micro unterstützt das direkt ? Oder meinst du diese Stromsparmodis ?

Gruß

Hans-Georg

Reply to
Hans-Georg Lehnard

Die meisten. Bei AVR heißt das SLEEP, beim 68HC11 heißt es WAI.

Ja. BTW: Modi ist bereits Plural von Modus. Modis ist also Quatsch. ~ ~

XL

Reply to
Axel Schwenke

Ja und nein. Ich habe - lang ist es her - ein Chipkartentelefon mit integrierter Verzonungsauswertung gemacht, da liefen (auf einem 80C32 @

4,x MHz) insgesamt 13 Prozesse (kooperatives "event polling" mit state machines) zuzüglich 4 Interrupt-Routinen parallel. Der Code ist hauptsächlich in C (Keil) geschrieben, einige wenige Funktionen wurden in Assembler laufzeitoptimiert. ROM-Codegröße knapp unter 32K.

Und die Geräte laufen heute noch.

Beste Grüße

Stefan

--
http://www.svb-wagner.de
Reply to
Stefan Wagner

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.