Verstecken kann man in C fast alles. Ob es sinnvoll ist, ist eine andere Frage. Wäre zwar nicht meine Art, aber bitte schön, ein Q&D Vorschlag zum Verstecken von "Switch-Case-Gedöns":
Nachtrag:Code:#include "StateMachine.h" void longrunning(void) { STATEMACHINE_INIT ;/*...*/ // do something step++; STATEMACHINE_STEP(1) ;/*...*/ // do something more step++; STATEMACHINE_STEP(2) ; // do even more if(error) step = -1; else step = 0; STATEMACHINE_STEP(-1) ; // do some error handling step = 0; STATEMACHINE_END }
Ich hab die quick'n'dirty Macros etwas überarbeitet und mittlerweile gefällt mir die Lösung sogar
Geändert von witkatz (17.09.2015 um 23:51 Uhr) Grund: Angehängte Headerdatei im eigenen PIC Projekt getestet und korrigiert
Wenn ich das richtig verstehe, willst Du eigentlich ein Multitasking realisieren.
Task 1 ist dein Longrunning Prozess Task 2 alles andere.
Man müsste mal prüfen ob sich das mit einer Timer IRQ Routine realisieren lässt.
Das wäre die einzige Möglichkeit sicherzustellen, das der Longrunning Task sicher nach einer gewissen Zeit unterbrochen wird und in den andern Task zurückgekehrt wird.
Da ja normalerweise die IRQ Routine komplett abgearbeitet wird, bevor in das unterbrochene Programm zurückgekehrt wird, sollte entweder die Hauptschleife die IRQ Routine sein und nach einem Durchlauf in den Longrunning Prozess zurückkehren oder du befasst dich mal damit was Linus Torvalds als ersten Teil von Linux realisiert hat (Ein präemptives Multitasking das zwichen zwei Tasks hin und her springt und dabei die Rettung aller Register, Pointer und des Stacks übernimmt). Was du versuchst ist ein kooperatives Multitaksing, damit ist Microsoft schon bei Windows 1 bis 3 gescheitert. Bleibt ein Task hängen ohne das ein Reset verursacht wird, fällt das ganze wie ein Kartenhaus in sich zusammen.
Wie so was geht steht z.B. hier:
http://www.gbv.de/dms/ilmenau/toc/592544346.PDF
oder hier:
Multitasking mit AVR RISC-Controllern
Prof. Dr. Ernst Forgber
Franzis Verlag
Leseprobe:
http://www.ciando.com/img/books/extr...5270558_lp.pdf
Multitasking für AVR:
http://www.controllersandpcs.de/pdfs/vmavr.pdf
https://xivilization.net/~marek/bina...ltitasking.pdf
http://www.wseas.us/e-library/conferences/2015/Dubai/CEA/CEA-24.pdf
http://www.ripublication.com/irph/ij...4n17spl_16.pdf
http://www.ijert.org/view-pdf/7712/r...icrocontroller
http://citeseerx.ist.psu.edu/viewdoc...=rep1&type=pdf
Geändert von i_make_it (17.09.2015 um 13:24 Uhr)
Der TE wollte kein OS...
Mit so einer State Machine kann man so einiges erreichen, denke auch das es die ideale Lösung ist. Hatte auch mal so eine Aufgabe, eine leere State Machine, ca 5000 ? wie das gehen soll, dann die Erleuchtung und Erkenntnis das man damit einem Mikrokontroller super auslasten kann ohne das eine einzelne lange Berechnung alles blockiert.
Sozusagen Multitasking light.
LG!
alles über meinen Rasenmäherroboter (wer Tippfehler findet darf sie gedanklich ausbessern, nur für besonders kreative Fehler behalte ich mir ein Copyright vor.)
Multitasking und Betriebssysteme (OS) sind auch zwei verschiedene Sachen. Ein Multitasking bedingt noch kein Betriebssystem und Betriebsysteme müssen nicht zwingend Multitasking tauglich sein.
Eine State Machine (endlicher Automat) ist eine Form kooperatives Multitasking zu realisieren und kein "Multitasking light".
Der Nachteil ist halt wenn ein Task nicht kooperiert (Fehlerfall) dann gibt es einen Systemabsturz.
Präemptives Multitasking hat halt n+1 Tasks (der eine Task ist der Multitasking Task)
Der Multitasking Task steuert stur seine Zeitscheibe, unabhängig davon ob ein Task abgestürzt ist oder nicht.
Man könnte sogar über Status Informationen eine Überwachung des Laufverhalten der anderen Tasks realisieren und so einen abgestürzten Task nach maximal 3 Durchläufen der Zeitscheibe terminieren und ggf. neu starten.
Kooperatives Multitasking funktioniert solange alles fehlerfrei läuft.
Präemptives Multitasking kapselt die einzelnen Tasks und verhindert so ein Versagen des gesamten Systems wenn ein Einzeltask versagt.
Eine Selbstheilung des Gesamtsystems erfordert neben dem präemptiven Multitasking zusätzlich eine FST die die Zustände jeden Tasks überwacht und beim Verharren in einem Zustand entsprechende Masnahmen veranlasst.
Es kommt halt darauf an wie wichtig einem das korrekte Weiterlaufen bstimmter Tasks ist, bzw. welche Folgen das nicht korrekte arbeiten derselben hat, um zu entscheiden welche Form des Multitaskings man implementieren will.
Bei Servoreglern, geht man z.B. so weit das Motorstrom Regelung und Motorstrom Überwachung sogar in echtzeit parallel auf verschiedener Hardware laufen, da die Folge einer zu langsamen Motorstrom Überwachung, bei zu langem Überstrom, die Zerstörung des Reglers und des Motors zur Folge haben kann. Und in Folge die Beschädigung oder Zerstörung der Hardware die an dem Motor hängt (inklusive Personenschäden).
Geändert von i_make_it (18.09.2015 um 13:16 Uhr)
In einigen Sprachen werden solche State Machines auch automatisch vom Compiler erzeugt, z.B. bei Verwendung von async und await in C#. Das erspart einiges an Schreibarbeit und umgeht einige Fehlerfälle. Für einen zukünftigen C++ Standard ist das zumindest vorgeschlagen, einige Compiler (z.B. Visual C++ 2015) bieten schon experimentelle Unterstützung (mit __yield, __async und __await).
Hier (http://www.mikrocontroller.net/articles/Multitasking) steht einiges über kooperatives und präemptives Multitasking.
Allerdings steht auch drin, dass beim präemptivem Multitasking neben den Registern auch der Stack für jede Task umgebogen werden muss (das ist eigentlich auch logisch, wenn man weiß, dass bei einem Funktionsaufruf in einer Task Übergabeparameter und Rückgabewerte über den Stack transferiert werden). Das wird bei Controllern mit wenig RAM relativ schnell eng, insbesondere, wenn weitere ISRs auch noch ihre Register auf den Stack der aktuellen Task poppen wollen).
Alternativ zur Switch-Anweisung: Mehrere kleine Funktionen schreiben, statt der Step-Variable und dem Switch den Funktionszeiger für die "Task" in der Jobliste jeweils aus einer Funktion heraus auf die nächste Funktion schieben.
Geändert von Holomino (19.09.2015 um 11:45 Uhr)
Moin,
manche C-Versionen (z.B. c#) bieten die Funktion yield, die so etwas kann. Für c habe ich dies gefunden: http://stackoverflow.com/questions/1...ing-yield-in-c
Wenn ich das Problem richtig verstehe liegt folgende Situation vor:
1) Es gibt eine Liste von Aufgaben, die in einer bestimmten Reihenfolge abgearbeitet werden sollen (Jobstack).
2) Hin und wieder sollen bestimmte Aufgaben erledigt werden, dies aber auch während ein Job aus 1) ausgeführt wird.
Lösen kann man das Problem, indem man 1) und 2) nicht in einer gemeinsamen Funktion implementiert (z.B. in main()):
Preemptives Verhalten: Man packt 2) in eine Timer-ISR. Dann geschieht die Ausführung regelmäßig. Führt man die ISR als non-blocking Version aus, werden andere Interrupts nicht behindert. Dann wird 2) regelmäßig ausgeführt, ohne dass sich die Jobs darum kümmern müssten. main() würde sich dann nur noch darum kümmern, dass nach Beendigung eines Jobs der nächste gestartet würde. Ist die Aufgabe länger als die Timer-Periode, muss man den Timer zu Beginn der ISR stoppen und am Schluss wieder starten.
Kooperatives Verhalten: Man packt 2) in eine Routine und ruft diese in den gewünschten Stellen in den Jobs aus. Auch hier übernimmt main() die Verwaltung der Jobs. Diese sähe etwa so aus (Pseudo-Code):
Gibt es mehrere Dinge, die man in TueWasManNichtLassenKann() erledigen muss, dies aber nicht auf einmal machen will, wäre dafür die Lösung in einer kleinen State-Machine. Alternative Implementierung als Array von Funktionszeigern: Der Array-Index wird bei jedem Aufruf erhöht und die entsprechende Funktion aufgerufen. Komplexeres Verhalten lässt sich durch Variation der Index-Bestimmung ermöglichen.Code:main() { while(true) StarteNaechstenJob(); } TueWasManNichtLassenKann() { // Der Name sagt alles .. } Job1() { ... // erster Teil der Arbeit von Job1 TueWasManNichtLassenKann(); ... nächster Teil der Arbeit von Job1 TueWasManNichtLassenKann(); ... nächster Teil der Arbeit von Job1 }
Viele Grüße
RedBaron
Herausspringen zur aufrufenden Funktion ist ja einfach mit return, entweder mit oder ohne weitere Parameter.
Zum Zurückspringen:
wie wäre es, wenn man der Funktion z.B. zusätzlich zur eigentlichen 1. Variable (usw.) einen weiteren Parameter übergibt, der den Sprungpunkt definiert?
Code:int function_foo(int var1, int jaddr){ // (Deklarationsteil) if(jaddr==0) goto LABEL0; else if(jaddr==1) goto LABEL1; else if(jaddr==2) goto LABEL2; // usw. //... LABEL0: //...(Anweisungen) LABEL1: //...(Anweisungen) LABEL2: //...(Anweisungen) }
Geändert von HaWe (21.09.2015 um 17:12 Uhr)
Hat sich seit meinem letzten Besuch ja einiges getan ;D. Ja im Prinzip hab ich nach einem Multitasking-Light gesucht. Und zumindest für meinen UseCase tuts das Kooperative Multitasking via State-Machine.
Sollte eine Task nicht kooperieren, also hängen bleiben, ist der Kontroller in einem Fehlerzustand, aus dem er sich nicht mehr retten kann. Ein Fall der nicht auftreten darf/soll.
Abgesehen von dem Aufwand der für das Multitasking getrieben werden muss, kommt dann noch die globale Fehlerbehandlung dazu: wie wird reagiert, wenn ein Task nicht beendet werden kann.
Das sind für ein kleines Projekt zu viele unbekannte Zustände und führt zu unvorhersehbaren Problemen.
Lesezeichen