Forum: Mikrocontroller und Digitale Elektronik 8051 mit Multitask???


von Dirk (Gast)


Lesenswert?

Ich muss ein Programm schreiben auf dem zwei oder drei Task scheinbar
zur selben Zeit ausgeführt werden.
Lösungsansatz:
- erster Task wird nach 10ms per Interrupt unterbrochen
- derzeitige Stelle im Task1 "merken"
- Wechel zum zweiten Task
- zweiter Task wird nach Ablauf von 10ms wieder unterbrochen
- derzeitige Stelle im Task2 "merken"
- Wechsel zum ersten Task
- Ausführung an gemerkter Stelle fort führen

Das Ganze soll in C programmiert werden. Der Interrupt dient dabei zur
Zeitgenerierung (Prozessor-Zeit für den jeweiligen Task).

Mein Problem ist, wie bekomme ich es hin, dass ich den jeweiligen Task
wieder an der gleichen Stelle fortsetze?

von KoF (Gast)


Lesenswert?

du mußt dir den stackpointer merken ;-)

von Dirk (Gast)


Lesenswert?

Ja, okay. Hatte ich auch schon dran gedacht. Aber wie stelle ich dann
beim Weitermachen den richtigen Stackpointer wieder ein?

von KoF (Gast)


Lesenswert?

task1 wird unterbrochen:
> sp vom task1sichern
> register vom task1 sichern
task2 wird zurückgeholt
> sp vom task2 zurückschreiben
> register vom task2 zurückschreiben
task2 wird unterprochen
> sp vom task2 sichern
> register sichern
task1 wird geladen
> sp vom task1 zürückschreiben
...

von Peter Dannegger (Gast)


Lesenswert?

Was sind denn das für Tasks ?

Am einfachsten geht es, wenn die Tasks selber zur Mainloop
zurückkehren, z.B. an Stellen, an denen sie auf irgendwas warten
müssen.

Aber so mal eben schnell ein Multitasking in C hinzaubern:

Vergiß es !!!


Peter

von KoF (Gast)


Lesenswert?

http://users.ints.net/skidan/SOS/

^^ tultitasking in C (für den msp430)

von Jochen (Gast)


Lesenswert?

hab mir auch mal nen kleines Task OS aufgebaut allerdings für nen M16C
Jeder Task braucht nen eigenen Stack
beim Taskwechsel/ Interrupt durch timer wird ja auch beim 8051 die
rücksprungaddr. im Stack abgelegt. Durch das tauschen der stack ist auf
jedenfall schon mal der rucksprung gesichert. Desweitern muss aber noch
mehr gespeichert werden: die register (entweder aufm stack am besten
aber register bänke verwenden) -> PSW, acc, b und dptr würd ich alles
auf den stack legen

so jetzt zum taskwechsel
alles wie oben besprochen sichern auf Stack
stack austauschen
alles vom neuen stack wieder runterholen
reti

ich würde sagen dass man den taskwechsel in asm programmiert

jeder task muss natürlich am anfang entsprechen initialisiert werden
damit er beim erstenmal aufrufen auch an die richtige stelle hüpft
hilfreich sind hier structures

gruß
jochen

leichte fehler vorbehalten :) da ich mehr mit m16c auskenne hab zwar
mit 8051 was gemacht aber ...

von Dirk (Gast)


Lesenswert?

Okay, danke erst einmal! Werde mal am Wochenende etwas rum spielen.

Zum Hinweis das die Task alleine zum Mainprog zurückkehren:
Leider geht das für mindestens einen Task nicht. Dieser soll nach
Möglichkeit vom restlichen Geschehen nichts mitbekommen.

von Tester (Gast)


Lesenswert?

#asm
;save registers
      PUSH     ACC             ;
      PUSH     PSW             ;
      PUSH     DPL             ;
      PUSH     DPH
      PUSH     00              ;push R0 from bank 0
      PUSH     01              ;push R1 from bank 0
      PUSH     02              ;push R1 from bank 0
      PUSH     03              ;push R1 from bank 0
      PUSH     04              ;push R4 from bank 0
      PUSH     05              ;push R5 from bank 0
      PUSH     06              ;push R5 from bank 0
      PUSH     07              ;push R5 from bank 0


.
. Dein Code
.

.OUT:
      POP      07              ;pop reg 5 from bank 0
      POP      06              ;pop reg 5 from bank 0
      POP      05              ;pop reg 5 from bank 0
      POP      04              ;pop reg 4 from bank 0
      POP      03              ;pop reg 1 from bank 0
      POP      02              ;pop reg 1 from bank 0
      POP      01              ;pop reg 1 from bank 0
      POP      00              ;pop reg 0 from bank 0
      POP      DPH
      POP      DPL
      POP      PSW
      POP      ACC
      RETI
#endasm

Abgesehen davon würde ich das "ohne Stack" retten ganz einfach als
quasi Multitasking System in C programmieren.
Geht doch viel einfacher.

Aber dazu müsstest du doch noch ein paar Infos mehr rauslassen ...

von Bolle (Gast)


Lesenswert?

>Jeder Task braucht nen eigenen Stack
>Desweitern muss aber noch
>mehr gespeichert werden: die register (entweder aufm stack am besten
>aber register bänke verwenden)

Korrekt.  Das ganze nennt man einen "context switch".  Wer so was
proggen will, sollte sich aber klarmachen, daß er sich damit bereits
voll auf dem Gebiet des Betriebssystem-Baus bewegt.  Die context
switches und das task scheduling sind dabei nur ein kleiner Teil der
Angelegenheit.  Die Prozesse wollen/müssen ja im allgemeinen auch
untereinander kommunizieren, und da fängt die Geschichte dann an, ganz
und gar nicht mehr einfach zu sein (Stichworte Critical Sections,
Semaphore, Mutexe...).

Deshalb an alle, die sich "mal eben schnell" daran versuchen wollen,
ein gutgemeinter Rat: Bitte unterschätzt die Sache nicht - ein
(funktionierendes) Betriebssystem zu schreiben ist eine sehr
anspruchsvolle Aufgabe.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Peter, ein einfaches kooperatives Multitasking ist mit Hilfe von
setjmp/longjmp keine große Sache:

http://www.mikrocontroller.net/forum/read-4-157859.html#159124

von Peter Dannegger (Gast)


Lesenswert?

@Andreas,

"Peter, ein einfaches kooperatives Multitasking ist mit Hilfe von
setjmp/longjmp keine große Sache:"


So wie ich das verstanden habe, soll aber eine Task nicht kooperativ
sein.

Dafür ginge dann folgende Lösung:

Die nicht kooperative Task läuft im Main uneingeschränkt bzw. braucht
auch nie dahin zurück kehren.

Alle anderen kooperativen Tasks laufen dann einfach in einer Schleife
im Timerinterrupt.


Für die Nichtkenner des 8051 sei gesagt, daß er üblicher Weise nur 128
Byte SRAM hat und das deshalb der Compiler lokale Variablen direkt im
RAM per Overlaying ablegt. Auch sind die Bibliotheksfunktionen nicht
reentrant geschrieben.

Was also auf dem ARM keine große Sache ist, ist aber bestimmt eine auf
dem 8051.


Peter

von Dirk (Gast)


Lesenswert?

Ich werde mal die gestellte Aufgabe genauer beschreiben.
Das Ganze soll eine Art Monitor-Programm sein. Auf dem Mikrocontroller
(MSC1211 von TI - mit 8051 Kern) soll ein User-Programm laufen. Während
das User-Programm läuft sollen gelegentlich Register ausgelesen und
evtl. manipuliert werden können (z.B. um Einstellungen des AD- bzw.
DA-Wandler im Betrieb zu ändern).
Das User-Programm soll von der Main-Funktion gestartet werden und kehrt
danach eigentlich nie wieder zur Main-Funktion zurück.

von Jochen (Gast)


Lesenswert?

das stimmt natürlich was Bolle schreibt, der taskswitch ist nicht das
aufwendige
jedoch denke ich das Dirk auf Semaphore verzichten kann, da sein
Multitasking bestimmt nicht vorsieht task schlafen zu legen
meiner ansicht will er eher ein einfaches roundroubin mit festen
taskzeiten keine prioritäten
hier muss er nur drauf achten nicht "gleichzeitig" auf resourcen zu
zugreifen

und hier ein beispiel
es wird eine resource z.B. das LCD von mehreren genutzt
das Problem befindet sich ein Task gerade in der LCD Ausgabe oder sonst
einer LCD Operation und wird unterbrochen bevor er fertig ist muss
aufjedenfall unterbunden werden dass ein weiter task jetzt aufs LCD
zugreift denn sonst weiß das LCD gar nicht mehr wo es lang geht.
Lösung hier: die angesprochenen Mutexe
dieser würde ein weiteren zurgriff unterbinden und ein Taskswitch
durchführen

von Tom (Gast)


Lesenswert?

Hi

Ich habe neulich mal etwas in die Richtung implementiert (nur als Test
auf meinem PC), wenn mich nicht alles täuscht nennt sich das
kooperatives Mulitasking. Das sieht etwa so aus:

Eine Tabelle speichert Funktionspointer zu allen Tasks, die
abzuarbeiten sind, sowie deren Prioritäten und was sonst noch so sein
muss (je nach Anwendung halt).

Die von mir genannten Tasks sind Funktionen, welche ihre Aufgabe oder
einen Teil davon in möglichst kurzer Zeit erfüllen und sich danach
wieder beenden. Der Rückgabewert sagt aus, ob noch mehr Durchläufe der
Funktion notwendig sind oder nicht.

Ein Taskmanager geht dann die Tabelle durch und arbeitet die Tasks je
nach Priorität öfter oder weniger oft ab und verweilt je nach
Rückgabewert bei einem Task oder kümmert sich zuerst um wichtigeres.

Ich finde diese Lösung einfach, ressourcensparend und flexibel. Du
kannst mir ja mal eine Mail schreiben, wenn du den Prototypen
(PC-Version) haben willst.

Gruss & HTH

Tom

von A.K. (Gast)


Lesenswert?

In dem erwähnten Zeitraster von 10ms ist kooperatives Multitasking
problemlos machbar, nur muss man natürlich darauf achten, dass alle(!)
Warteschleifen oft genug den Scheduler aufrufen.

Präemptives Multitasking wird beispielsweise dann nötig, wenn Tasks
kurzfristig auf Interrupts reagieren müssen. Mann muss dann zwar in
Warteschleifen nicht immer auf den Scheduler achten, dafür kämpft man
dann mit Semaphoren, Deadlocks, Timern.

Bei einfachem kooperativem Multitasking kann man auf Semaphoren
verzichten. Auch sind in der Beschreibung oben keine komplexen
Timerstrukturen zu erkennen. Also wird ein simpler setjmp-basierender
Scheduler ausreichen.

Auch interessant, und ein deutlich anderer Ansatz als klassisches
kooperatives Multitasking, besonders geeignet für kleine Devices mit
wenig Raum für Stacks: Protothreads => http://www.sics.se/~adam/pt/.
Kommt ohne Stack-Switch aus, beim 8051 beispielsweise klar von Vorteil.

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.