Forum: Compiler & IDEs Problem: verschachtelte Statemachines [ATMega328] [ANSI C]


von Christian S. (christian_s593)


Lesenswert?

Hallo,

Ich hab ein Projekt wo ein ATMega328 ein Sim-Modul steuert. Das 
Grundprogramm ist mittlerweile fertig, jedoch habe ich versucht 
Spaghetti-code zu vermeiden, was mir jedoch nicht ganz gelang.

Die Grundschleife läuft im 50ms Zyklus, indem Statemachines abgearbeitet 
werden und der µC für den Rest der Zeit im Sleep Mode befindet.

Die Statemachine in main() hat 23 Zustände, wobei bspw. in einem State 
sich wiederrum eine Statemachine befindet, die 8 Zustände beinhaltet, 
diese wiederrum hat auch eine verschachtelte Statemachine mit 9 
Zuständen, und die hat wieder eine mit 5 Zuständen.

Soweit so schlecht.

An sich funktioniert der Code jetzt, jedoch sollen jetzt Funktionen 
hinzukommen, bei den mir das Implementieren schwer fällt.

Die Verschachtelung habe ich so umgesetzt, da diese Abschnitte 
wiederholt aufgerufen werden, weshalb eine Auflösung als eine große 
Statemachine den Programmspeicher unnötig füllt und unpraktisch ist, 
wenn man was ändern will.

Jedoch hat die Verschachtelung ein Problem. Die Statemachine in main() 
hat ein Timer, der nach Ablauf einer Zeit den State verlässt, und den 
Vorgang nach bestimmter Zeit wieder versucht (z.B. Loginschwierigkeit 
durch schlechten Empfang oder Timeout bei keiner Tastereingabe).

Das Problem:
Durch diesen Abbruch sind jedoch die verschachtelten Statemachines noch 
in ihren alten Zuständen, was bei Wiedereintritt für Probleme sorgt.

Um das Problem zu lösen, muss vor dem Abbruch die unterliegende 
Statemachine über den Abbruch informiert, die wiederum auch alle 
unterliegenden informiert. Gibt es elegantere Lösungen? Dadurch wird das 
ganze Konstrukt sehr undurchsichtig. Wenn ich eine Funktion hinzufüge, 
muss ich gucken, ob abgebrochen wird, und an welcher Unterfunktion 
dieser Abbruch bekannt gemacht werden muss.

Eine Möglichkeit die ich gerade sehe, ist die Umsetzung Yakindu, wo ich 
den Code aus Statecharts generieren lasse. Ich denke ich gewinne daraus 
etwas Übersicht, jedoch ist das für mich Neuland und ich denke die 
Einarbeitung erfordert sehr viel Zeit.

Eine Umsetzung mit Funktionspointern und Transitionsstabelle statt 
Switch-Case könnte auch für mehr Übersicht sorgen, jedoch löst es nicht 
das Problem mit den Verschachtelungen.

Hat jemand ein Vorschlag für mich, wie ich so eine Statemachine umsetzen 
kann, zum Beispiel, dass die verschachtelten Statemachines sich 
automatisch zurücksetzen, oder was eine Verschachtelung überflüssig 
macht?

von Peter II (Gast)


Lesenswert?

Christian S. schrieb:
> Durch diesen Abbruch sind jedoch die verschachtelten Statemachines noch
> in ihren alten Zuständen, was bei Wiedereintritt für Probleme sorgt.

sollte man dann nicht dieses Problem lösen?

Sorge doch einfach dafür das bei eintritt alle untergeordneten dinge 
zurückgesetzt werden.

von Possetitjel (Gast)


Lesenswert?

Christian S. schrieb:

> Die Statemachine in main() hat 23 Zustände, wobei bspw.
> in einem State sich wiederrum eine Statemachine befindet,
> die 8 Zustände beinhaltet, diese wiederrum hat auch eine
> verschachtelte Statemachine mit 9 Zuständen, und die hat
> wieder eine mit 5 Zuständen.

Das klingt schonmal etwas ungesund.

> Die Verschachtelung habe ich so umgesetzt, da diese
> Abschnitte wiederholt aufgerufen werden, weshalb eine
> Auflösung als eine große Statemachine den Programmspeicher
> unnötig füllt und unpraktisch ist, wenn man was ändern will.

???
Ich verstehe kein Sterbenswörtchen.

> Um das Problem zu lösen, muss vor dem Abbruch die
> unterliegende Statemachine über den Abbruch informiert,
> die wiederum auch alle unterliegenden informiert.

Richtig.

> Gibt es elegantere Lösungen?

Nein.
Wenn ein Reset notwendig ist, musst Du Reset passend beschalten.

> Eine Möglichkeit die ich gerade sehe, ist die Umsetzung Yakindu,
> wo ich den Code aus Statecharts generieren lasse. Ich denke ich
> gewinne daraus etwas Übersicht,

Glaube ich nicht.

Grundlagen der Automatentheorie wären wohl nützlich: Eingangs-
signale, Ausgangssignale, Zustände, Überführungsfunktion,
Ausgabefunktion.
Fertig ist der Automat.

> Eine Umsetzung mit Funktionspointern und Transitionsstabelle
> statt Switch-Case könnte auch für mehr Übersicht sorgen,

Die Überführungsfunktion würde ich immer als Tabelle (=Array)
formulieren; switch/case ist dafür ein Furunkel am Arsch.

Wozu man in dem Kontext Funktionspointer braucht, weiss ich
nicht. -- Ach so: Für die Ausgabe wahrscheinlich. -- Ja, das
sollte funktionieren.

> jedoch löst es nicht das Problem mit den Verschachtelungen.

Ich vermute Fehler im Automatenentwurf.

> Hat jemand ein Vorschlag für mich, wie ich so eine
> Statemachine umsetzen kann, zum Beispiel, dass die
> verschachtelten Statemachines sich automatisch
> zurücksetzen,

Ich vermute, Du hast Dich im switch/case-Dschungel verlaufen:
Man kann natürlich mehrere gekoppelte Automaten (="Verschachtelung") 
programmieren, aber Du musst in der Hauptschleife JEDEM Automaten
Rechenzeit geben!

> oder was eine Verschachtelung überflüssig macht?

Nicht "Verschachteln"! Die Automaten über Hilfssignale koppeln
(Freigaben bzw. Verriegelungen).

von Christian S. (christian_s593)


Lesenswert?

Danke schonmal für die Antworten

Possetitjel schrieb:
> Christian S. schrieb:
>
>> Die Verschachtelung habe ich so umgesetzt, da diese
>> Abschnitte wiederholt aufgerufen werden, weshalb eine
>> Auflösung als eine große Statemachine den Programmspeicher
>> unnötig füllt und unpraktisch ist, wenn man was ändern will.
>
> ???
> Ich verstehe kein Sterbenswörtchen.
>

Vielleicht mal ein konkretes Beispiel mit folgenden States:
Login -> Signalstärke anzeigen -> Logout -> Ereignis warten -> Login -> 
SMS senden -> Logout

Wobei jedes State wiederum ein eine eigene Statemachine ist.
Ich könnte eine natürlich eine riesige Statemachine daraus machen, was 
aber unsinnig ist, da ich dann zwei identische Abschnitte in der 
Statemachine habe.
Deshalb habe ich aus dem kompletten Loginvorgang wiederum eine eigene 
Statemachine gemacht, die als Funktion aus der "Haupt Statemachine" 
aufgerufen wird.
Der Loginvorgang kann ein Fehler zurückgeben, z.B. keine SIM-Karte oder 
kein Netzsignal, aber auch die "Haupt Statemachine" kann nach einer 
gewissen Zeit den Loginvorgang abbrechen und den State auf Fehlerausgabe 
wechseln (z.B. GSM Modul braucht zu lange für den Login zum 
Netzbetreiber).
Wenn das eintrifft muss der State das Loginvorgangs zurückgesetzt 
werden.

>> Eine Umsetzung mit Funktionspointern und Transitionsstabelle
>> statt Switch-Case könnte auch für mehr Übersicht sorgen,
>
> Wozu man in dem Kontext Funktionspointer braucht, weiss ich
> nicht. -- Ach so: Für die Ausgabe wahrscheinlich. -- Ja, das
> sollte funktionieren.
>

Ja, in der Transitionstabelle (Array) sind Pointer auf die Funktionen, 
die bei Eintritt, jedem Tick und Austritt das States ausgeführt werden 
sollen.

>> jedoch löst es nicht das Problem mit den Verschachtelungen.
>
> Ich vermute Fehler im Automatenentwurf.
>

Mag wohl sein, bin auch nicht so fit im Automatenentwurf, ich kenn nur 
einige Grundlagen. Aber deshalb auch meine Problemschilderung ;-)


>> Hat jemand ein Vorschlag für mich, wie ich so eine
>> Statemachine umsetzen kann, zum Beispiel, dass die
>> verschachtelten Statemachines sich automatisch
>> zurücksetzen,
>
> Ich vermute, Du hast Dich im switch/case-Dschungel verlaufen:
> Man kann natürlich mehrere gekoppelte Automaten (="Verschachtelung")
> programmieren, aber Du musst in der Hauptschleife JEDEM Automaten
> Rechenzeit geben!
>

Ich glaube ich hab ein jetzt ein entscheidenden Fehler im Entwurf 
gefunden.
Die "Haupt Statemachine" hat immer Rechenzeit, jedoch die aufgerufenden 
Statemachines takten nur durch Aufruf aus der "Haupt Statemachine". 
Deshalb auch ein Problem bei abbruch, die Statemachines bleiben stehen, 
und müssen umständlich zurückgesetzt werden.

>> oder was eine Verschachtelung überflüssig macht?
>
> Nicht "Verschachteln"! Die Automaten über Hilfssignale koppeln
> (Freigaben bzw. Verriegelungen).

Ja ok, jetzt ist der Groschen gefallen ;-)
Dann werd ich erstmal meine Freestyle State Machine etwas umschreiben 
;-)

von Peter D. (peda)


Lesenswert?

Christian S. schrieb:
> Die "Haupt Statemachine" hat immer Rechenzeit, jedoch die aufgerufenden
> Statemachines takten nur durch Aufruf aus der "Haupt Statemachine".

Nö, alle Statemaschienen takten parallel, d.h. werden von der Mainlopp 
aufgerufen.
Wie eine Statemaschine auf eine andere reagieren soll, wird über 
Ereignisse (Variablen) gesteuert.

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.