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
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
@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.
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...
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.
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).
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.
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_tBlink_2S(uint8_tstate)
2
{
3
switch(state){
4
5
caseINIT:
6
StartTimer(0,2000);// Timer starten, 2 Sekunden
7
returnWAIT_2S;// beim nächsten Aufruf soll die Statemachine im Zustand WAIT_2S sein
8
break;
9
10
caseWAIT_2S:
11
if(!IsTimerStopped(0))// Timer abgelaufen?
12
returnWAIT_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...
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.
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_ti=0;i<MAX_TASKS;i++)
2
if(AllTasks[i].currentTime>0)
3
AllTasks[i].currentTime--;
In RunScheduler dann entsprechend:
1
staticuint8_tNextTask=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)
...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...
(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.
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.
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!'"
--------
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...