Zustandsdiagramme

Die UML-Zustandsdiagramme gehen auf die von David Harel in den 1980er Jahren entwickelten Zustandsautomaten zurück.

Bei den Basiskonzepten haben Sie gelernt, dass Objekte Zustände besitzen. Das UML-Zustandsdiagramm ist ein Ausdrucksmittel, welches immer dann angewendet werden sollte, wenn im Mittelpunkt der Betrachtung ein komplexes zustandsorientiertes Problem steht. Des Weiteren ist die softwareseitige Implementation einer Zustandsmaschine nicht trivial. SiSy ist in der Lage, aus dem UML-Zustandsdiagramm den entsprechenden Quellcode zu generieren. Die automatisch generierte Zustandsmaschine verringert den Aufwand und reduziert die Fehleranfälligkeit gegenüber einer manuellen Implementation enorm. Zustandsmaschinen sind oft zyklisch und laufen, solange ein Objekt existiert. Die Zustandsänderungen sind in der Regel an Ereignisse und Bedingungen geknüpft. Das Zustandsdiagramm zeigt nur Zustände und Zustandswechsel eines Objektes, jedoch keine objektübergreifenden Sachverhalte. Ein Objekt kann aber durchaus mehrere Zustandsmaschinen gleichzeitig, also parallel, besitzen.

Zustandsdiagramme zeigen mögliche Zustände und Zustandswechsel eines Objektes.

Das folgende Zustandsdiagramm zeigt welchen Zustand und welche Zustandswechsel ein Objekt mindestens hat, auch ohne eine explizit realisierte Zustandsmaschine.

Die wichtigsten Modellierungselemente des Zustandsdiagramms sind:

  • Zustände
  • Zustandsübergänge
  • Pseudozustände: Startknoten, Endknoten
  • Zustandsaktionen: entry, do, exit

Zustände

Ein Objektzustand repräsentiert zu einem oder mehreren determinierten, konkreten Eigenschaftswerten (Zustandsattribute) zuordenbares Verhalten (Aktivitäten). Die dem Zustand zuordenbaren Aktivitätstypen sind zum Beispiel:

  • entry, einmaliges Verhalten beim Einnehmen des Zustandes
  • do, wiederholtes Verhalten während des Zustandes
  • exit, einmaliges Verhalten beim Verlassen des Zustandes

Die Notation von Zuständen erfolgt wie bei der Aktion und Aktivität als Rechteck mit abgerundeten Ecken. Zusätzlich ist es üblich, den Zustand detailliert darzustellen. Ähnlich wie bei der Klasse wird das Zustandssymbol unterteilt und es können zustandsbestimmende Attribute und Aktionen angegeben werden. Wichtig ist, dass ein Zustand nicht als etwas statisches angesehen wird. Ein Objekt führt, während es sich in einem Zustand befindet, auch immer das dem Zustand zugeordnete Verhalten aus. Deshalb ist es üblich die Zustandsaktivitäten auch mit zu modellieren.

Pseudozustände

inital node, Startknoten

Der Startknoten repräsentiert in nicht hierarchisierten Zustandsdiagrammen im einfachsten Fall den Zustand, bevor das Objekt existiert. Zweckmäßigerweise sollte immer nur eine ausgehende Kante modelliert werden. Die Notation des Startknotens ist ein kleiner, ausgefüllter Kreis.

final node, Endknoten

Ein Endknoten repräsentiert in einer einfachen Zustandsmaschine den Zustand, nach dem das Objekt zerstört wurde. Es ist möglich und auch üblich Zustandsmaschinen als endlose zyklische Automaten zu modellieren. In dem Falle wird das Zerstören des Objektes nicht modelliert und der Endknoten fehlt in der Darstellung. Die Notation des Endknotens ist ein kleiner ausgefüllter Kreis im Kreis.

Zustandsübergänge

transition, Zustandsübergang

Der Übergang von einem Zustand in den anderen bedeutet in jedem Fall Verhalten. Es passiert also etwas und der Übergang verbraucht auch Zeit. Es wird konkretes Verhalten ausgeführt und damit finden wir die Zustandsübergänge im Programmcode als eine entsprechende Codesequenz. Die Zustandsübergänge können durch Ereignisse und Bedingungen ausgelöst werden. Das Ereignis spezifiziert wann der Übergang stattfindet. Letztlich ist ein Ereignis im Quellcode eine Operation der Klasse des Objektes. In eingebetteten Systemen kann das auch eine dem Objekt zugeordnete Interrupserviceroutine (ISR) sein. Bedingungen (Guards) drücken aus unter welchen Konditionen ein Übergang zulässig ist. Die Notation von Zustandsübergängen erfolgt durch eine gerichtet Linie (Pfeil) mit Beschriftung (Ereignis [Bedingung] / Aktion).

Mit dem Zustandsdiagramm in SiSy programmieren

Die Modellierung von Zustandsdiagrammen wird in unserem Lehrbuch Software Engineering für Embedded Systems näher beschrieben. SiSy ist in der Lage, aus solchen Zustandsdiagrammen den kompletten Quellcode, der die Zustandsmaschine realisiert, zu generieren und in die zugehörige Klasse einzubetten.

Unsere kleine Anwendung soll folgende Anforderungen erfüllen:

  • nach dem Einschalten ist die rote LED aus
  • das System wartet auf einen Tastendruck zum Starten des Steuerzyklus
  • nach dem Tastendruck wird das System etwa 3 Sekunden vorbereitet
  • währen der Vorbereitung soll die rote LED flackern
  • nach der Vorbereitung schaltet das System 5 Sekunden
  • solange das System schaltet ist die rote LED an
  • danach geht das System wieder auf wartend
  • die rote LED ist währen des Wartens aus

Wir bereiten die Struktur des Systems vor. Das System benötigt als Mensch-Maschine-Schnittstelle eine Taste und eine LED. Die Taste schließen wir an Port D Bit 2 an und die LED an Port B Bit 0. Als Basis-Templates nutzen wir PecPinInterrupt und PecLed. Achten sie auf die korrekte Konfiguration des Interrupts Pins (LowAktiv, PullUp, INT0, fallende Flanke).

Der Zustandsautomat soll im Controller laufen. Da die zustandsorientierte Programmierung auch immer Ereignisorientiert ist sorgen wir zunächst in der Klasse Controller für die benötigten Ereignishandler und deren Sichtbarkeit im Zustandsdiagramm. Das kontinuierliche Ereignis onWork soll im Zustandsmodell als do erscheinen. Für den Tastendruck legen wir einen Ereignishandler mit dem Namen onStartTaste an. Das Sichtbarmachen im Zustandsdiagramm erfolgt mit der Zusicherung sm::eventName. Später wird der Codegenerator in diese Operationen die nötigen Codes für die funktionsfähige Zustandsmaschine generieren.

Für die Modellierung der Zustandsmaschine fügen wir ein spezielles Zusatndsattribut mit der Signatur #steuerzyklus:state_t in die Klasse Controller ein. Dieses Zustandsattribut wird tatsächlich später den Zustand im Code als Klassenattribut abbilden und dieses Attribut kann mit einem Zustandsdiagramm hinterlegt werden. Für das geforderte Timing legen wir uns einen Zähler an. Dieses Attribut timeout inkrementieren wir im Ereignis für eine Sekunden. Bitte überschreiben Sie den entsprechenden Ereignishandler im Controller.

das Klassenmodell sollte jetzt wie folgt aussehen. Bitte vergleichen sie den Stand ihres Modells mit der folgenden Abbildung. Ergänzen sie ggf. Ihr Modell.

Damit die Zustandsmaschine auch arbeiten kann reichen wir das Interrupt-Ereignis der Taste an den Controller weiter und sorgen dafür dass der Timeout-Zähler auch zählt. Ergänzen sie die folgenden Operationen:

Controller::onEvent1s

// timeout Sekunden runterzählen
if (timeout>=0) timeout--;

Taste::onPinInterrupt

// Ereignis weiter reichen
app.onStartTaste();

Jetzt kann es los gehen. In der Klasse Controller haben wir das Attribut #steuerzyklus:state_t angelegt. Auf diesem können Sie im Kontextmenü nach unten wählen und gelangen zum Zustandsdiagramm. Laden Sie folgende Vorlage aus dem LibStore.

Sie erhalten dann die Grundstruktur für einen Zusatndsautomat mit drei Zuständen. Diese Vorlage passen wir an die Aufgabenstellung an. Benennen Sie die Zustände und die Zusatndsaktionen, wie in der folgenden Darstellung gezeigt, um.

Der nächste Schritt betrifft die Zustandsübergänge. Diese müssen vom Programmierer explizit einem Ereignis zugewiesen werden. In der zugewiesenen Operation (Eventhandler) wird durch den Codegenerator der Code für den Zustandsübergang erzeugt. Dieser kann mit einer zusätzlichen Bedingung (Guard) und beim Übergang zusätzlich auszuführenden, benutzerspezifischem Code ergänzt werden. Weisen Sie die entsprechenden Ereignisse und Übergangsbedingungen den Zustandsübergängen zu.

Vergleichen Sie das Modell Ihres Zustandsautomaten mit der folgenden Darstellung. Ergänzen Sie ggf. das Modell.

Das konkrete, den Zuständen zuzuordnende Verhalten notieren wir in den Zustandsaktionen. Für die Aufgabenstellung reichen uns die Entry-Aktionen der Zustände. Ergänzen Sie diese wie folgt:

warten::entry/alles aus

roteLED.off();

vorbereiten::entry/flickern und Timer 3s starten

roteLED.flicker();
timeout=3;

vorbereiten::entry/anschalten und Timer 5s starten

roteLED.on();
timeout=5;

Jetzt kann die Zustandsmaschine getestet werden. Gehen Sie dazu zurück in das Klassendiagramm, erzeugen, übersetzen und übertragen Sie die Lösung auf den Mikrocontroller. Viel Spaß beim Testen und Erweitern der Zustandsmaschine.

Videozusammenfassung

Weiterführendes

Nächstes Thema

  • zustandsdiagramm.txt
  • Zuletzt geändert: 2021/01/26 17:12
  • von huwi