Discussion:
Multitasking im Mikrocontroller
(zu alt für eine Antwort)
Thomas Finke
2006-01-09 20:36:05 UTC
Permalink
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
MaWin
2006-01-09 20:47:07 UTC
Permalink
Post by Thomas Finke
es wird ja bei Mikrocontrollerprojekten oft eine Art Multitasking im
Mikrocontroller implementiert,
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.
Thomas Finke
2006-01-09 20:59:45 UTC
Permalink
Post by MaWin
Bei jeder Einzelaktion wird gefragt, ob sie in dieser Runde
auch ausgefuehrt werden soll, oder uebersprungen wird.
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
Andreas Koch
2006-01-09 21:12:07 UTC
Permalink
Post by Thomas Finke
Und das wird bei jedem Timer-Interrupt neu festgelegt, was beim
nächsten Durchgang ausgeführt werden soll und was nicht?
Idealerweise baut man sich eine State-Machine, in dem Fall
auch einfach mitzählen :-)

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

oder so...
Post by Thomas Finke
Gibt's da wiederum eine Struktur die man einhalten sollte, damit die
Interrupt-Routine nicht zu groß wird?
Es sollte einfach möglichst wenig unnötiger (Prüf-)Code ablaufen.
Post by Thomas Finke
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
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...
MaWin
2006-01-09 21:16:44 UTC
Permalink
Post by Thomas Finke
Und das wird bei jedem Timer-Interrupt neu festgelegt, was beim
nächsten Durchgang ausgeführt werden soll und was nicht?
Beim Dispaly: Beim naechsten ist halt die Stelle um 1 hochgezaehlt,
die Funktion nimmt sich die naechste Stelle vor.
Post by Thomas Finke
Gibt's da wiederum eine Struktur die man einhalten sollte, damit die
Interrupt-Routine nicht zu groß wird?
Na, wenn dein Programm jede Millisekunde einen Zeitgeber-Interrupt
ausloest, ist es halt doof, wenn die Zeitgeber-Funktion laenger
als 1 msec braucht.
Post by Thomas Finke
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.
Wenn das nur 1 Funktion ist, macht man das im Hauptprogramm, das dreht
sonst ja nur Daeumchen.
Post by Thomas Finke
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?
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.
Axel Schwenke
2006-01-10 12:53:51 UTC
Permalink
Post by MaWin
Es kann sinnvoll (notwendig) sein, beim Interrupt erst mal nur eine
kurze Funktion auszufuehren (schnelle Reaktion), dabei einen Wert
zu setzen der 'Nacharbeit' ankuendigt
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
Hans-Georg Lehnard
2006-01-10 21:08:59 UTC
Permalink
"Axel Schwenke" schrieb
Post by Axel Schwenke
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.
Hallo Axel,

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

Gruß

Hans-Georg
Axel Schwenke
2006-01-11 09:57:42 UTC
Permalink
Post by Hans-Georg Lehnard
"Axel Schwenke" schrieb
Post by Axel Schwenke
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.
welcher Micro unterstützt das direkt ?
Die meisten. Bei AVR heißt das SLEEP, beim 68HC11 heißt es WAI.
Post by Hans-Georg Lehnard
Oder meinst du diese Stromsparmodis ?
Ja. BTW: Modi ist bereits Plural von Modus. Modis ist also Quatsch.
~ ~

XL
Olaf Kaluza
2006-01-09 21:35:37 UTC
Permalink
Post by Thomas Finke
Gibt's da wiederum eine Struktur die man einhalten sollte, damit die
Interrupt-Routine nicht zu groß wird?
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.
Post by Thomas Finke
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?
Nein, eher nicht.
Post by Thomas Finke
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?
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
Stefan Bröring
2006-01-10 09:50:55 UTC
Permalink
Post by Olaf Kaluza
Post by Thomas Finke
Gibt's da wiederum eine Struktur die man einhalten sollte, damit die
Interrupt-Routine nicht zu groß wird?
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.
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
Reinhard Richter
2006-01-10 07:30:16 UTC
Permalink
Hallo,
Post by MaWin
...
Das Hauptprogramm macht (nach Initialisierung des Zeitgebers und
der Ports) irgendwas unwichtiges (Daeumchen drehen :-)
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
Stefan Engler
2006-01-10 09:42:43 UTC
Permalink
Post by MaWin
Vergiss den Begriff Multitasking.
So etwas gibt es nur ganz selten.
Die Sprache ADA-97 ist per Definition Multitasking-fähig,
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 Überzeugungsarbeit mit Diskutierwerkszeugen gegen
den Terrorismus zu führen --> F wie Frieden.

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

Andere Sprachen lassen Multitasking simulieren (hatte mal
ein Buch zu Pascal liegen)
Rafael Deliano
2006-01-10 11:46:06 UTC
Permalink
(ist grob gesagt ein abgewandeltes C).
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.
Es soll auch Varianten für diverse Microcontroler
gegeben haben,
DoD hat keine Subsets erlaubt also war Float
erforderlich. Der typische Prozessor war damit
Mil-Std-1750 der Float im Microcode mitmachte.

MfG JRD
Hans-Georg Lehnard
2006-01-10 21:03:48 UTC
Permalink
Post by MaWin
Vergiss den Begriff Multitasking.
So etwas gibt es nur ganz selten.
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
Michael J. Schülke
2006-01-09 20:55:49 UTC
Permalink
Post by Thomas Finke
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...
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.
Post by Thomas Finke
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.
Ein Timerinterrupt alle paar Millisekunden sollte genügen.

Michael
Stefan Wagner
2006-01-11 20:26:42 UTC
Permalink
Post by Michael J. Schülke
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.
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
Olaf Kaluza
2006-01-09 21:27:00 UTC
Permalink
Post by Thomas Finke
es wird ja bei Mikrocontrollerprojekten oft eine Art Multitasking im
Mikrocontroller implementiert,
Naja, oft wohl eher nicht.
Post by Thomas Finke
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...
Das macht man mit Interrupts.
Post by Thomas Finke
Wie wird dieses Multiplexing denn programmtechnisch (interessant wäre
Assembler und C) realisiert?
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.
Post by Thomas Finke
Wie werden die Tasks zeitlich verwaltet?
An erster Stelle im Hirn des Programmierers. Soll heissen du musst
wissen wie wichtig eine bestimmte Aufgabe ist und wie oft sie
auftritt.
Post by Thomas Finke
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.
Timer-IRQ.

Olaf
Johannes Bauer
2006-01-09 21:54:15 UTC
Permalink
Post by Thomas Finke
Wie wird dieses Multiplexing denn programmtechnisch (interessant wäre
Assembler und C) realisiert? Wie werden die Tasks zeitlich verwaltet?
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
Helmut Schellong
2006-01-10 02:25:17 UTC
Permalink
Post by Thomas Finke
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 schreibe gerade an einem Firmware-Handbuch.
Da sind solche Sachen mannigfaltig erklärt.

http://www.schellong.biz/tmp/ka.pdf

kann einen Eindruck vermitteln.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Hans-Georg Lehnard
2006-01-10 08:24:07 UTC
Permalink
"Thomas Finke" schrieb .
Post by Thomas Finke
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...
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
Wolfgang Strobl
2006-01-11 21:53:36 UTC
Permalink
Post by Thomas Finke
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.
Dafür braucht's kein Multitasking, jedenfalls dann nicht, wenn man nicht
gleichzeitig rechnen und anzeigen will. Ein praktisches Beispiel findest
Du hinter
http://www.mystrobl.de/ws/pic/mm47/index.htm genauer gesagt hinter dem
Link http://www.mystrobl.de/ws/pic/mm47/mm47bas.htm

Es geht nur um die beiden Schnipsel "display" und "convert". Das ist
m.E. kurz genug, um ohne weitere Erklärung verständlich zu sein.

Realisiert wird so ein zweistufiger Multiplex, es leuchten immer maximal
zwei Segemente gleichzeitig. Das Ergebnis ist brauchbar, wie man dem
(unretouchierten) Foto sieht.

N.B. In - simulierter - Aktion kann man sich das übrigens auf
http://tech-www.informatik.uni-hamburg.de/applets/hades/webdemos/72-pic/90-mastermind/fast-mastermind-mux.html
ansehen, worauf mich kürzlich ein Bekannter hinwies. Nett, wenn man
Feierabendbasteleien, mit denen man sich vor vielen Jahren mal die Zeit
vertrieben hat, Jahre später auf diese Weise recycled findet.

Wollte man gleichzeitig rechnen und anzeigen, würde man den
Zustandswechsel (quasi die "inner loop") in der (hier stillgelegten)
Interruptroutine erledigen. Das erfordert immer noch keine
Zeitverwaltung.
Post by Thomas Finke
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.
Na ja, eigentlich nur einmal. :-)
Post by Thomas Finke
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.
M.E. genau so: in der "idle loop" werden die einzelnen Segemente in
einem festen Schema angesteuert (in meinem Beispiel also nacheinander
alle vier Anzeigen, dann innerhalb einer Anzeige vier Blöcke a jeweils
zwei Segmente). Natürlich ist das an einige Bedingungen geknüpft
(beispielsweise sollte der Test, so vorhanden, ob die idle-loop
verlassen werden soll, nicht lange und vor allen Dingen nicht variabel
lang dauern), aber Du fragtest ja nach "am einfachsten".
--
Wir danken für die Beachtung aller Sicherheitsbestimmungen
Martin
2006-01-17 07:20:29 UTC
Permalink
Am Wed, 11 Jan 2006 22:53:36 +0100 schrieb Wolfgang Strobl
Post by Wolfgang Strobl
M.E. genau so: in der "idle loop" werden die einzelnen Segemente in
einem festen Schema angesteuert (in meinem Beispiel also nacheinander
alle vier Anzeigen, dann innerhalb einer Anzeige vier Blöcke a jeweils
zwei Segmente). Natürlich ist das an einige Bedingungen geknüpft
Was ist der Vorteil dieses unüblichen Multiplex gegenüber dem normalen
stellenweisen, wo man 7 Seg+DP als 8bit Wort rausschreibt, dann die Stelle
aktiviert usw. ?
--
Martin
Wolfgang Strobl
2006-01-17 18:15:42 UTC
Permalink
Post by Martin
Am Wed, 11 Jan 2006 22:53:36 +0100 schrieb Wolfgang Strobl
Post by Wolfgang Strobl
M.E. genau so: in der "idle loop" werden die einzelnen Segemente in
einem festen Schema angesteuert (in meinem Beispiel also nacheinander
alle vier Anzeigen, dann innerhalb einer Anzeige vier Blöcke a jeweils
zwei Segmente). Natürlich ist das an einige Bedingungen geknüpft
Was ist der Vorteil dieses unüblichen Multiplex gegenüber dem normalen
stellenweisen, wo man 7 Seg+DP als 8bit Wort rausschreibt, dann die Stelle
aktiviert usw. ?
Probier's aus. :-)

Es ist lange her, ich habe die genauen Werte nicht mehr im Kopf und mag
sie nicht nachschlagen, aber grundsätzlich ist es so. Ein PIC-Port kann
nur 20 mA liefern und 25 mA als Senke vertragen (oder umgekehrt),
insgesamt ist man auf ca 100 mA beschränkt. Ein Segment zieht lt.
Datenblatt 30 mA.

Nun überlege, wie es sich auswirkt, wenn man einen Port als gemeinsame
Kathode benutzt und alle acht Segmente über ihre Anoden gleichzeitig
einzuschalteten versucht: statt acht leuchtender Segmente siehst Du gar
nichts leuchten. Schon zwei Segmente sind rechnerisch zu viel, aber wie
man an dem Photo sieht, reicht die so erzielte Gleichmäßigkeit aus.

Natürlich behilft man sich in der Praxis mit separaten
Ansteuertransistoren. Ein Pfiff bei den PIC ist aber die recht robuste
Beschaltung der Pins, die - s.o. - sowohl als Stromquelle als auch als
Senke dienen können*), das wollte ich ausnutzen. Ein Ziel bei dieser
Fingerübung war, mit einem Minimum an Bauteillen auszukommen, vier oder
zwölf weitere Transistoren hätten sich da nicht so gut gemacht.

*) Im Ersatzschaltbild hat man einen FET gegen Plus, einen weiteren
gegen Masse.
--
Wir danken für die Beachtung aller Sicherheitsbestimmungen
Wolfgang Weinmann
2006-01-17 20:27:55 UTC
Permalink
Post by Thomas Finke
Hallo,
es wird ja bei Mikrocontrollerprojekten oft eine Art Multitasking im
Mikrocontroller implementiert ...
Ich hätte da auch noch was beizutragen:

http://www.embedded.com/2000/0009/0009feat4.htm

Gruß

Wolfgang
--
www.ibweinmann.de

Loading...