Forum: Compiler & IDEs Multitasking


von Ralf (Gast)


Angehängte Dateien:

Lesenswert?

Moin, moin.
Ich habe hier mal was ausgegraben
(Beitrag "Re: Programm bzw. Ablaeufe steuern")
und bin dabei, mich durchzuarbeiten.

Dazu zwei Fragen:
Das Schlüsselwort static holt in der Funktion RunScheduler die 
Variable NextTask aus der Funktion raus? Oder warum wird diese nicht 
bei jedem Aufruf neu initialisiert?

Wenn man in der Struktur Task die Variable currentState auf 16 Bit 
erweitert, könnte man diese direkt als Zähler verwenden. Spart pro 
'Task' ein Byte und ein paar Funktionsaufrufe u. Zuweisungen. Oder kommt 
man da in die Rubrik: 'Das gehört sich nicht!'

P.S.: Quelltext von Karl Heinz Buchegger noch mal im Anhang

von XXX (Gast)


Lesenswert?

Kernigham & Ritchie
Programmieren in C
Ausgabe Hanser Verlag von 1983
Seite 87f
Kapitel 4.6 Die Speicherklasse "static"

Manchmal ist ein Buch verdammt von Vorteil.

Oder gurgle: 
http://de.wikibooks.org/wiki/C-Programmierung:_static_%26_Co.


Gruß
Joachim

von Ralf (Gast)


Lesenswert?

@XXX
Naja, mir ging es jetzt nicht so um das 'Gesetz', sondern mehr um die 
'Interpretation'. Beim nochmaligen Durchlesen ist mir allerdings klar 
geworden: Die Variable gehört zur Funktion, ist von außen nicht 
sichtbar und der Compiler organisiert die Initialisierung.

von Ralf (Gast)


Lesenswert?

Ralf schrieb:
> Wenn man in der Struktur Task die Variable currentState auf 16 Bit
> erweitert, könnte man diese direkt als Zähler verwenden. Spart pro
> 'Task' ein Byte und ein paar Funktionsaufrufe u. Zuweisungen. Oder kommt
> man da in die Rubrik: 'Das gehört sich nicht!'

Würde mich schon noch interessieren. Ich glaube, bei meinen 
Hobby-Programmierungen geht's manchmal noch 'kreuz und quer'. Nicht dass 
ich mich da verrenne...

von Helfer (Gast)


Lesenswert?

Ralf schrieb:
> Das Schlüsselwort static holt in der Funktion RunScheduler die
> Variable NextTask aus der Funktion raus? Oder warum wird diese nicht
> bei jedem Aufruf neu initialisiert?

Sie wird nicht ständig neu initialisiert, weil sie eben static ist. :)

> Wenn man in der Struktur Task die Variable currentState auf 16 Bit
> erweitert, könnte man diese direkt als Zähler verwenden. Spart pro
> 'Task' ein Byte und ein paar Funktionsaufrufe u. Zuweisungen. Oder kommt
> man da in die Rubrik: 'Das gehört sich nicht!'

Zähler wofür?
Der Scheduler muss sich den aktuellen State merken und tut das in 
currentState. Da wird nix gezählt.

von Ralf (Gast)


Lesenswert?

Da wird schon gezählt.
Vielleicht hat der Autor mal Zeit?

von Helfer (Gast)


Lesenswert?

Ralf schrieb:
> Da wird schon gezählt.
Wo?

> Vielleicht hat der Autor mal Zeit?
Wozu? Ist schönes Standard-C, das jeder fortgeschrittene Programmierer 
lesen kann/können sollte. (Auf die Gefahr hin, dass ich mich jetzt 
übelst blamiere hehe).

von Ralf (Gast)


Lesenswert?

Helfer schrieb:
>> Vielleicht hat der Autor mal Zeit?
> Wozu? Ist schönes Standard-C, das jeder fortgeschrittene Programmierer
> lesen kann/können sollte. (Auf die Gefahr hin, dass ich mich jetzt
> übelst blamiere hehe).

Na, dann lies mal etwas fortgeschritten. Es geht um Multitasking. Das 
werden den Tasks Rechenzeiten zugeordnet. Und die müssen (Timer) 
ermittelt werden.

von Helfer (Gast)


Lesenswert?

Ralf schrieb:
> Na, dann lies mal etwas fortgeschritten. Es geht um Multitasking. Das
> werden den Tasks Rechenzeiten zugeordnet. Und die müssen (Timer)
> ermittelt werden.

Nein, das sehe ich nirgends so. Es gibt zwar einen Hardware Timer und 
eine ISR, die ein Array von Zählern bearbeitet (AllTimers), aber das 
hat keinen Einfluss auf den Scheduler.

Der Scheduler arbeitet einfach die Task Liste ab und ruft die Task 
functions regelmässig auf und übermittelt deren aktuellen Status (die 
functions sind als FSM implementiert). Er kümmert sich nicht um die 
Timer.

StartTimer() enthält keinen Rücksprung zum scheduler, gibt keine 
Rechenzeit ab, implementiert keinerlei Multitasking. Beispielsweise:
1
uint8_t Blink_2S( uint8_t state )
2
{
3
  switch( state ) {
4
  
5
    case INIT:
6
      StartTimer( 0, 2000 );   // Timer starten, 2 Sekunden
7
      return WAIT_2S;        // beim nächsten Aufruf soll die Statemachine im Zustand WAIT_2S sein
8
      break;
9
      
10
    case WAIT_2S:
11
      if( !IsTimerStopped( 0 ) )   // Timer abgelaufen?
12
        return WAIT_2S;   // nein: Task bleibt im Zustans WAIT_2S
13
//... mehr code

Der Scheduler startet den Task (function Blink_2S) erstmal mit dem State 
INIT. Der initialisiert einen Sw-Timer und definiert den nächsten 
State. Damit geht's zurück zum Scheduler. Der startet den/die nächsten 
Tasks und irgendwann wieder Blink_2S, diesemal im State WAIT_2S. Dort 
wird der SW-Timer geprüft, und erst wenn er abgelaufen ist, in den 
nächsten State gewechselt. Usw...

von Ralf (Gast)


Lesenswert?

Bitte, Karl Heinz, bitte!
:(

von Bernhard M. (boregard)


Lesenswert?

Ralf schrieb:
> Da wird schon gezählt.
> Vielleicht hat der Autor mal Zeit?

Kannst Du mal sagen wo?
Ich sehe nur, daß NextTask hochgezählt wird.

Und ein Zustand hat nichts mit zählen zu tun, deshalb sollte man die 
nicht vermischen...

Aber villeicht postest Du mal den geänderten Code, so wie Du es Dir 
vostellst.

von Ralf (Gast)


Lesenswert?

Also gut:
In der Timer-ISR wird für alle Tasks die Startzeit ermittelt, indem 
AllTimers runtergezählt wird.
In RunScheduler werden die Tasks nacheinander aufgerufen. Diese 
prüfen, ob 'ihre Zeit gekommen' ist, wenn ja, wird currentState 
umgestellt und beim nächsten Durchlauf der entsprechende Zweig 
abgearbeitet und neu initialisiert.

Ich hätte jetzt die Timer-ISR weiter hinten deklariert und 
currentState bzw. dann besser currentTime direkt zugewiesen:
1
for (uint8_t i=0; i < MAX_TASKS; i++)
2
 if (AllTasks[i].currentTime > 0)
3
  AllTasks[i].currentTime--;
In RunScheduler dann entsprechend:
1
static uint8_t NextTask=0;
2
if (AllTasks[NextTask].currentTime > 0)
3
 (*AllTasks[NextTask].execute)(/* Parameter nicht nötig */);
4
NextTask++;
5
if (NextTask > MAX_TASKS)
6
 NextTask=0;
Spart RAM und und Code... (sag ich)
Oder: Mach's lieber nicht, weil... (Begründung)

von Bernhard M. (boregard)


Lesenswert?

Ich verstehe nicht, wo Du jetzt den State unterbringst.
Die Tasks sind doch State-Maschinen, wo wird jetzt der State 
gespeichert?

von Bernhard M. (boregard)


Lesenswert?

...oder meinst Du, weil im Beispiel eh nur Zeitgesteuert umgeschaltet 
wird ist der State direkt mit der Zeit verknüpft...

Damit reduzierst Du aber die Statemaschine zu einer reinen 
Zeitsteuerung, und das geht nur mit dem Beispiel...

Eine Task, die nicht nur eine LED blinken lässt, sondern den State z.B. 
für Datenübertragung benutzt (mit entsprechenden Zuständen) kannst Du 
dann nicht mehr realisieren...

von Ralf (Gast)


Lesenswert?

Na die Zeit selbst! 'Zeit abgelaufen' ist wie 'true', sonst 'false'.

von Ralf (Gast)


Lesenswert?

(hatte ich noch nicht gelesen:)
Bernhard M. schrieb:
> Eine Task, die nicht nur eine LED blinken lässt, sondern den State z.B.
> für Datenübertragung benutzt (mit entsprechenden Zuständen) kannst Du
> dann nicht mehr realisieren...

Dass die LED blinkt, ist ja nur 'Zufall'. Der Task soll ja, egal was er 
dann macht, starten, wenn seine Zeit ran ist.

von Karl H. (kbuchegg)


Lesenswert?

Ralf schrieb:
> (hatte ich noch nicht gelesen:)
> Bernhard M. schrieb:
>> Eine Task, die nicht nur eine LED blinken lässt, sondern den State z.B.
>> für Datenübertragung benutzt (mit entsprechenden Zuständen) kannst Du
>> dann nicht mehr realisieren...
>
> Dass die LED blinkt, ist ja nur 'Zufall'. Der Task soll ja, egal was er
> dann macht, starten, wenn seine Zeit ran ist.

Dann wirds aber komplizierter.

Dann muss der 'Scheduler' Buch darüber führen, wenn er die Task wieder 
ausführen darf.

Einfacher ist es, wenn du ganz einfach in jede State Maschine einen 
entsprechenden Wartezustand einführst, der überprüft, ob seine Zeit 
schon gekommen ist. Wenn nicht, gibt er sofort wieder an den Scheduler 
zurück; wenn schon dann wechselt die State Maschine in einen anderen 
Zustand.

Ob jetzt letzten Endes der Scheduler die 'Däumchen dreht', oder ob er 
reihum allen 'Tasks' Gelegenheit gibt nachzusehen, ob ihre Timer schon 
abgelaufen sind, ist für den µC Jacke wie Hose.
Für dich ist aber kooperatives Multitaksing, bei dem sich die Tasks 
selbst die Zeitsteuerung machen, viel leichter zu implementieren, als 
nicht kooperatives Multitasking, bei dem der SCheduler einem Task die 
Kontrolle unter dem Allerwertesten wegziehen kann.

von Ralf (Gast)


Lesenswert?

Ich war gerade beim Schreiben und habe vor dem Absenden noch mal schnell 
einen Seiten-Refresh ausgeführt.

Karl Heinz Buchegger schrieb:
> Dann wirds aber komplizierter.
Ich meine jetzt, das ist was völlig anderes, als ursprünglich gedacht.

Hier, was ich erst nur schreiben wollte:
--------
Ich denke nur mal laut:

Ralf schrieb:
> Dass die LED blinkt, ist ja nur 'Zufall'. Der Task soll ja, egal was er
> dann macht, starten, wenn seine Zeit ran ist.

Ich merke jetzt, dass das für die ursprüngliche Aufgabe der falsche 
Ansatz ist. Mit meiner Idee kann man zwar zeitlich flexibel die 
einzelnen Tasks aufrufen, aber das war ja hier nicht gewollt. Mich hat 
die Übergabe von currentState im Scheduler durcheinander gebracht. 
Dass nur beim Ablauf des Timers der Task 'sinnvoll produktiv' wird, das 
ist rein zufällig.
Also kann ich mir die Antwort jetzt selbst geben:
Kann man zwar machen, hat mit der eigentlichen Aufgabe des Schedulers 
nichts zu tun. Deswegen "Rubrik: 'Das gehört sich nicht!'"
--------

von Ralf (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ralf schrieb:
>> (hatte ich noch nicht gelesen:)
>> Bernhard M. schrieb:
>>> Eine Task, die nicht nur eine LED blinken lässt, sondern den State z.B.
>>> für Datenübertragung benutzt (mit entsprechenden Zuständen) kannst Du
>>> dann nicht mehr realisieren...
>>
>> Dass die LED blinkt, ist ja nur 'Zufall'. Der Task soll ja, egal was er
>> dann macht, starten, wenn seine Zeit ran ist.
>
> Dann wirds aber komplizierter.
>
> Dann muss der 'Scheduler' Buch darüber führen, wenn er die Task wieder
> ausführen darf.
>
...usw. ...

... hab' ich mir jetzt noch mal genauer durchgelesen. Das ist genau das, 
was ich etwas spät nun auch erkannt habe. Eine Änderung hätte ich jetzt 
noch im Kopf: Die Tasks timerinterruptgesteuert (1ms) aufrufen und die 
Tasks kümmern sich selbst um das 'Zeitzählen'. Vielleicht gibt's ja auch 
mal Tasks, die auf ganz andere Ereignisse warten müssen...

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.