Statemachine Tutorial

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • Was ist eine Statemachine, wozu benötigt man eine und wie kann man eine solche in Bascom realisieren.
    Diese Programmiertechnik ermöglicht es, komplexere Steuerungen zu programmieren, die übersichtlich bleiben und damit servicefreundlich sind.
    Einführung

    Eine Statemachine (Zustandsautomat) ist im Prinzip nichts anderes als ein Stück Code, mit einer bestimmten Struktur.
    Die Aufgabe einer Statemachine ist es, komplexere Abläufe und Steuerungen zu realisieren.
    Hierbei arbeitet die Statemachine in verschiedenen Zuständen (States), die der Programmierer definiert.
    Diese Zustände werden in einer Variablen gespeichert und sind zentraler Bestandteil der Statemachine.
    Die Struktur einer Statemachine besteht also darin, eine Aufgabe in Zustände zu zerlegen, die in einer Variablen gespeichert werden.
    Abhängig vom Inhalt der Variablen wird Code ausgeführt.
    Schauen wir uns mal das Grundgerüst einer Statemachine an:

    BASCOM Source Code: FSM_Grundgerüst_1

    1. ' Grundgerüst Statemachine
    2. $Regfile = "m8def.dat"
    3. $Crystal = 1000000
    4. $HWStack = 24
    5. $SWStack = 24
    6. $Framesize = 24
    7. ' Variable für Zustand
    8. Dim State as Byte
    9. ' Zustände des Automaten mit sinnvollen Bezeichnungen
    10. Const ZUSTAND_A = 0
    11. Const ZUSTAND_B = 1
    12. Const ZUSTAND_C = 2
    13. Const ZUSTAND_D = 3
    14. Do
    15. Select Case State
    16. Case ZUSTAND_A
    17. Case ZUSTAND_B
    18. Case ZUSTAND_C
    19. Case ZUSTAND_D
    20. End Select
    21. Loop
    Display All

    Die Struktur, wie eben beschrieben, ist hier deutlich zu sehen.
    In Zeile 11 ist eine Variable definiert, die den Zustand der Statemachine aufnimmt.
    Darunter, in Zeile 14 bis 17, sind zur Veranschaulichung die Zustände definiert.
    In den Zeilen 21 bis 31 wird geprüft, in welchem Zustand sich die Statemachine gerade befindet. Abhängig davon wird unterschiedlicher Code ausgeführt.
    Die Unterscheidung der Zustände wird hier mit Select Case erreicht. Das Prüfen der States muss regelmäßig erfolgen, damit auf Ereignisse reagiert werden kann.
    Im einfachsten Fall kann diese Select Case-Struktur in der Hauptschleife angelegt werden.

    Natürlich kann man die Unterscheidung des aktuellen Zustands auch mit If-Abfragen umsetzen, ich finde jedoch, dass die Select Case in Punkto Übersicht überzeugt.

    Das obige Grundgerüst zeigt den grundlegenden Aufbau, ist allerdings noch nicht ganz komplett.
    Hier fehlen die sogenannten Ereignisse, die zu einem Zustandswechsel führen.

    Um die Zustände zu ändern, abzufragen und die Handhabung zu vereinfachen, legen wir eine kleine Include-Datei an, welche die folgenden Funktionen bereitstellt.
    1. SetState(), zum Setzen eines neuen Zustands (Zustandswechsel)
    2. GetState(), zum Abfragen des aktuellen Zustands in der Select Case-Anweisung
    3. IsStateChanged(), zum Abfragen innerhalb einer Case-Anweisung, ob sich der Zustand geändert hat.
    Die Include-Datei kann immer wieder verwendet werden und sieht dann folgendermaßen aus.

    BASCOM Source Code: Statemachine.inc

    1. ' Include-Datei für Statemachine
    2. Dim _FSM_State as Byte ' Zustands-Variable des Automaten
    3. Dim _FSM_Flags as Byte ' Interne Flags des Automaten
    4. Const FLAG_CHANGED = 0 ' Gesetzt, wenn sich der Zustand geändert hat
    5. Declare Sub SetState(Byval state as Byte)
    6. Declare Function GetState() as Byte
    7. Declare Function IsStateChanged() as Byte
    8. ' --------------------------------------------------------
    9. Goto Modul_Statemachine_Exit
    10. ' --------------------------------------------------------
    11. ' Setzen eines neuen Zustandes und markieren als geänderten Zustand
    12. Sub SetState(Byval state as Byte)
    13. _FSM_State = state ' Neuer Zustand setzen
    14. Set _FSM_Flags.FLAG_CHANGED ' Flag Zustand hat sich geändert
    15. End Sub
    16. ' Aktueller Zustand ermitteln
    17. Function GetState() as Byte
    18. GetState = _FSM_State ' aktuellen Zustand an Aufrufer
    19. End Function
    20. ' Prüft, ob Zustand sich geändert hat und löscht FLAG_CHANGED
    21. Function IsStateChanged() as Byte
    22. If _FSM_Flags.FLAG_CHANGED = 1 then
    23. Reset _FSM_Flags.FLAG_CHANGED ' Flag geändert nach 1. Abfrage löschen
    24. IsStateChanged = TRUE ' Zustand geändert an Aufrufer
    25. Else
    26. IsStateChanged = FALSE ' Zustand nicht geändert an Aufrufer
    27. End If
    28. End Function
    29. ' --------------------------------------------------------
    30. Modul_Statemachine_Exit:
    31. ' --------------------------------------------------------
    Display All
    Aufmerksamen Lesern ist bestimmt aufgefallen, dass die Zustands-Variable (_FSM_State) jetzt in der Include-Datei integriert ist.
    Das ist nicht zwingend erforderlich, macht aber das Hauptprogramm zunächst mal übersichtlicher.

    Aufgrund der Include-Datei ändert sich natürlich das Hauptprogramm und sieht nun wie folgt aus:. Die Variable State entfällt logischerweise, dafür muss die Include-Datei eingebunden werden.

    BASCOM Source Code: FSM_Grundgeruest_2

    1. ' Grundgerüst Statemachine 2
    2. $Regfile = "m8def.dat"
    3. $Crystal = 1000000
    4. $HWStack = 24
    5. $SWStack = 24
    6. $Framesize = 24
    7. Const TRUE = 1 ' Konstanten für True, False
    8. Const FALSE = 0
    9. $Include "Statemachine.inc" ' Routinen Statemachine einbilden
    10. ' Zustände des Automaten mit sinnvollen Bezeichnungen
    11. Const ZUSTAND_A = 0
    12. Const ZUSTAND_B = 1
    13. Const ZUSTAND_C = 2
    14. Const ZUSTAND_D = 3
    15. Call SetState(ZUSTAND_A) ' Festlegen des Anfangs-Zustands
    16. Do
    17. Select Case GetState() ' aktuellen Zustand abfragen
    18. ' -----------------------------------------------------
    19. Case ZUSTAND_A
    20. ' -----------------------------------------------------
    21. If IsStateChanged() = TRUE then ' Code wird 1x ausgeführt nach Zustandswechsel
    22. End If
    23. ' Hier Code, der immer ausgeführt wird
    24. ' ..
    25. ' Exitbedingungen (Ereignisse), die einen Zustandswechsel verursachen
    26. ' ..
    27. ' -----------------------------------------------------
    28. Case ZUSTAND_B
    29. ' -----------------------------------------------------
    30. If IsStateChanged() = TRUE then ' Code wird 1x ausgeführt nach Zustandswechsel
    31. End If
    32. ' Hier Code, der immer ausgeführt wird
    33. ' ..
    34. ' Exitbedingungen (Ereignisse), die einen Zustandswechsel verursachen
    35. ' ..
    36. ' -----------------------------------------------------
    37. Case ZUSTAND_C
    38. ' -----------------------------------------------------
    39. If IsStateChanged() = TRUE then ' Code wird 1x ausgeführt nach Zustandswechsel
    40. End If
    41. ' Hier Code, der immer ausgeführt wird
    42. ' ..
    43. ' Exitbedingungen (Ereignisse), die einen Zustandswechsel verursachen
    44. ' ..
    45. ' -----------------------------------------------------
    46. Case ZUSTAND_D
    47. ' -----------------------------------------------------
    48. If IsStateChanged() = TRUE then ' Code wird 1x ausgeführt nach Zustandswechsel
    49. End If
    50. ' Hier Code, der immer ausgeführt wird
    51. ' ..
    52. ' Exitbedingungen (Ereignisse), die einen Zustandswechsel verursachen
    53. ' ..
    54. End Select
    55. Loop
    Display All
    Hinzu kam ebenfalls die Zeile 20, in der ein Anfangszustand festgelegt wird, in dem die Statemachine beginnen soll.
    In diesem Grundgerüst werden bereits alle Routinen aus der Include-Datei verwendet.

    Zur Erklärung des obigen Codes.
    Die Variable, die den aktuellen Zustand der Statemachine enthält, ist in die Include-Datei verlegt worden.
    Dort wird auf die Variable mit SetState() und GetState() zugegriffen.

    In der Include-Datei wurde zusätzlich noch eine Flag-Variable angelegt, in der weitere Informationen zur Statemachine gespeichert werden können.
    Im obigen Fall wurde das FLAG_CHANGED angelegt, das immer gesetzt wird, wenn sich der Zustand durch SetState() ändert.

    Das Flag FLAG_CHANGED wird mit der Funktion IsStateChanged() abgefragt und im gleichen Aufwasch gelöscht. Das hat einen Vorteil.

    Im Hauptprogramm, in den Case-Fällen (Zuständen) kann nun abgefragt werden, ob der Zustand neu ist (FLAG_CHANGED gesetzt), damit hat man die Möglichkeit einmalige Aktionen auszuführen.
    Das ist sehr nützlich z.B. für Display-Ausgaben (vermeidet Flackern) und auch die Aktion selbst. In einem späteren Beispiel wird das noch deutlicher.

    In den Case-Fällen der verschiedenen Zustände ist noch per Kommentar angedeutet, dass Code, der immer im jeweiligen Zustand ausgeführt werden soll, eingetragen werden kann.
    Dort gehören auch die Exit-Bedingungen (Ereignisse) rein, die zu einen Zustandswechsel führen sollen, sofern gewünscht.

    So, nun haben wir eigentlich alles, was wir brauchen, um etwas mit einer Statemachine zu steuern.
    Das was bisher gezeigt wurde ist in Grunde die Statemachine.

    Das FSM_Grundgerüst der Statemachine gibt's zum Download am Ende des Beitrags.


    Praktischer Teil

    Im praktischen Teil soll an einem kleinen Beispiel gezeigt werden, wie man vorgeht.
    Also, in dem folgenden Fall-Beispiel werden wird notwendige Zustände und Ereignisse definieren, den Programmablauf bestimmen und dann den Code entsprechend schreiben.

    Beispiel 1 (LED-Steuerung)


    Ein wirklich einfaches Beispiel für eine Statemachine wäre eine LED, die man mit einem Taster einschaltet und mit einem anderen Taster wieder aus macht.
    Klar kann man jetzt sagen, das geht doch einfach mit 2 If-Abfragen, das stimmt. Aber es geht hier darum zu erklären, wie man die Aufgabe mittels Statemachine lösen kann.
    Denn wenn die Aufgaben kompliziert werden, wird es nach altem Schema immer schwieriger den Überblick zu behalten.

    Zurück zum Beispiel mit der LED-Steuerung.
    Stellt sich nun die Frage, welches sind die Ereignisse, auf die die Statemachine reagieren soll, und was sind die erforderlichen Zustände und die Aktionen, um die Aufgabe zu erfüllen.

    Ereignisse definieren
    Beginnen wir mit den Ereignissen. Ereignisse sind immer Vorgänge, die einen Zustandswechsel nach sich ziehen. Also was bewirkt einen Zustandswechsel?
    Die Frage ist recht einfach zu beantworten. Im Beispiel kommen nur die die zwei Taster in Frage, die Einfluss auf die LED haben. Also sind die Ereignisse entsprechend die Betätigung der Taster.
    Genauer ist eine Ereignis die Betätigung des Taster 1, den wir mal Taster_AN nennen, und das andere
    Ereignis die Betätigung des Taster 2, den wir mal Taster_AUS nennen wollen.

    Zustände definieren
    Welche Zustände kennt die Steuerung?
    Auch diese Frage ist einfach zu beantworten. Die Steuerung soll die LED entweder AN oder AUS schalten. Dazwischen gibt es nichts. Dimmen ist nicht vorgesehen.
    Es gibt somit in unserem Beispiel nur 2 Zustände für den Automat.
    • ZUSTAND_LED_AN und
    • ZUSTAND_LED_AUS


    Programm-Ablauf
    Wie bereits beschrieben, soll die Steuerung bei Taste_AN die LED einschalten und bei Taste_AUS die LED ausschalten. Das ist aber gelinde gesagt recht lapidar ausgedrückt,
    und reicht allenfalls als Umschreibung für die Steuerung aus.
    Wir müssen das Verhalten der Steuerung präzisieren, denn ein Programm soll zuverlässig und ohne Seiteneffekte funktionieren. Daher muss man sich immer die folgenden Fragen stellen.
    1. In welchen Zustand soll die Steuerung beginnen?
    2. Auf welche Ereignisse ist in den einzelnen Zuständen wie zu reagieren?
    3. Welche Aktionen sind in den einzelnen Zuständen auszulösen?
    Wir legen also fest, dass die Steuerung in dem Zustand ZUSTAND_LED_AUS beginnen soll und präzisieren das Verhalten der Steuerung:

    Befindet sich die Steuerung im Zustand LED_AUS, soll sie nur auf die Taste_AN reagieren und den ZUSTAND_LED_AN aktivieren. Die andere Taste hat keine Funktion.
    Bedindet sich die Steuerung im ZUSTAND_AN, soll sie nur auf die Taste_AUS reagieren und den ZUSTAND_LED_AUS aktivieren. Die andere Taste hat keine Funktion.
    Die jeweilige Aktion wird in dem Zustand erledigt, der als neuer Zustand definiert wird.

    Es muss also für jeden möglichen Zustand definiert sein, wie die Steuerung zu reagieren hat.
    Die Aktion, die durchgeführt werden soll, also Led ein- oder ausschalten, wird in dem Codeabschnitt untergebracht, der nur 1x ausgeführt wird.

    Es bietet sich in diesem Zusammenhang oft an, die Zustände, Ereignisse und Aktionen in einer Tabelle festzuhalten. Bei Änderungen der Steuerung kann dadurch die Funktion der Steuerung recht schnell nachvollzogen werden. Eine Tabelle ist auch hilfreich bei Dokumentationen. Ich lege hierfür in der Tabelle die Zustände in Zeilen und die Ereignisse in Spalten an, eine zusätzliche Spalte für Aktion bzw. Kommentare. Das ganze kann dann etwa so aussehen:

    Tabelle der Zustände
    ZuständeTaster_ANTaster_AusBemerkung, Aktion
    ZUSTAND_LED_AUSWechsel in
    ZUSTAND_LED_AN
    keine FunktionLed ausschalten
    ZUSTAND_LED_ANkeine FunktionWechsel in
    ZUSTAND_LED_AUS
    Led einschalten

    Damit können wir den Code für die Steuerung angehen, der dann wie folgt aussieht:

    BASCOM Source Code: FSM_Led-Steuerung

    1. ' LED-Steuerung als Automat
    2. $Regfile = "m8def.dat"
    3. $Crystal = 1000000
    4. $HWStack = 24
    5. $SWStack = 24
    6. $Framesize = 24
    7. Const TRUE = 1 ' Konstanten für True, False
    8. Const FALSE = 0
    9. ' Ausgang für LED festlegen
    10. LED Alias PortB.1 : Config LED = Output
    11. ' Eingänge für Taster (Low-Aktiv)
    12. Taster_AN Alias PinC.4 : Set PinC.4 ' Taster mit internen PullUps
    13. Taster_AUS Alias PinC.5 : Set PinC.5
    14. $Include "Statemachine.inc" ' Routinen Statemachine einbilden
    15. ' Zustände des Automaten mit sinnvollen Bezeichnungen
    16. Const ZUSTAND_LED_AUS = 0
    17. Const ZUSTAND_LED_AN = 1
    18. Call SetState(ZUSTAND_LED_AUS) ' Festlegen des Start-Zustands
    19. Do
    20. Select Case GetState() ' aktuellen Zustand abfragen
    21. ' -----------------------------------------------------
    22. Case ZUSTAND_LED_AUS
    23. ' -----------------------------------------------------
    24. If IsStateChanged() = TRUE then ' Code wird 1x ausgeführt nach Zustandswechsel
    25. Reset Led ' Led ausschalten
    26. End If
    27. ' Hier Code, der immer ausgeführt wird
    28. ' .. ist nicht erforderlich
    29. ' Exitbedingungen (Ereignisse), die einen Zustandswechsel verursachen
    30. If Taster_AN = 0 then ' Taste an betätigt
    31. SetState(ZUSTAND_LED_AN)
    32. End If
    33. ' -----------------------------------------------------
    34. Case ZUSTAND_LED_AN
    35. ' -----------------------------------------------------
    36. If IsStateChanged() = TRUE then ' Code wird 1x ausgeführt nach Zustandswechsel
    37. Set Led ' LDE einschalten
    38. End If
    39. ' Hier Code, der immer ausgeführt wird
    40. ' .. ist nicht erforderlich
    41. ' Exitbedingungen (Ereignisse), die einen Zustandswechsel verursachen
    42. If Taster_AUS = 0 then ' Taste-Aus betätigt
    43. SetState(ZUSTAND_LED_AUS)
    44. End If
    45. End Select
    46. Loop
    Display All
    Das Programm FSM_Led-Steuerung kann am Ende des Beitrags herunter geladen werden.
    Man erkennt deutlich die wiederkehrende Struktur, die eingangs erwähnt wurde. Nach diesem Schema lassen sich viele Programme als Statemachine ausführen.

    Beispiel 2 (Notbeleuchtung)

    Das obige Beispiel ist zugegebener weise sehr einfach. Deshalb möchte ich die Statemachine mit einem 2. Beispiel gerne vertiefen.

    Wir wollen eine Notbeleuchtung bauen. Sie soll im Falle eines Stromausfalls einen Flur beleuchten.

    Wie soll die Notbeleuchtung funktionieren?
    Die Notbeleuchtung ist am Netz (Via Steckernetzteil) angeschlossen. Die Netz-Spannung wird verwendet, um festzustellen, ob der Strom ausgefallen ist. Solange der Strom da ist, wird die Netzspannung genutzt, um den Akku zu laden bzw. die Akkuladung zu erhalten. Setzt die Netzspannung aus (Stromausfall), so soll die Notbeleuchtung angehen. Allerdings nur, wenn es ausreichend dunkel ist. Bedeutet, bei ausreichender Helligkeit bleibt bei Stromausfall die Notbeleuchtung aus (die LED_Netz geht jedoch aus).

    Weiterhin soll die Notbeleuchtung den Status des Akkus und der Netzspannung per LED anzeigen.
    • Netzspannung da, grüne LED (LED_Netz) leuchtet.
    • Akku wird geladen, rote LED (LED_Batt_Charge) leuchtet.
    • Akku voll, Ladung wird erhalten, grüne LED (LED_Batt_Full)
    Um den Akku zu schützen, soll bei Stromausfall die Notbeleuchtung abgeschaltet werden, bevor der Akku tiefentladen wird und damit Schaden nehmen kann.

    Die Notbeleuchtung soll noch Tasten erhalten mit folgenden Funktionen.

    • Taste Test simuliert einen Stromausfall. Der Controller erkennt Stromausfall und verhält sich so, solange die Taste gedrückt bleibt. Taster ist ein Öffner und unterbricht die Spannung zum Eingang (Pin_Power), der feststellt ob Netz (Spannung vom Steckernetzteil) da ist oder nicht.
    • Taste Set (Schließer) ermöglicht die Einstellung der Helligkeit, bei der die Notbeleuchtung einschaltet.
    • Taste Akkupflege (Schließer), der Akku wird einmal komplett entladen und dann neu geladen. Damit soll ein Memory-Effekt des Akkus verhindert werden. Tritt während der Akkupflege ein Stromausfall ein, so soll die Notbeleuchtung wie oben beschrieben aktiv werden.


    Ich denke an dieser Stelle ist recht klar, wie die Notbeleuchtung funktioniert. Zu erwähnen ist noch, dass ein LDR mit PullDown-Widerstand zur Helligkeitsmessung, und ein Poti zur Helligkeits-Einstellung verwendet werden soll.

    Welche Zustände kennt die Notbeleuchtung?

    Um zu ermitteln, welche Zustände die Steuerung benötigt, kann man auch fragen: In welchen Zuständen verharrt die Steuerung, bis ein Ereignis eintritt?

    Nun, beim Einschalten muss man erst mal prüfen, wie die aktuelle Lage ist. Haben wir Netzspannung, wie ist die Akkuspannung, und daraufhin wird entschieden, mit welchem Zustand die Steuerung fortfährt. Die Feststellung der Lage kann also bereits als ein Zustand angesehen werden und kann auch diverse Initialisierungen darin vornehmen. Man kann ihn z.B. benennen als ZUSTAND_DEFAULT oder ZUSTAND_START. Da wir aber etwas schreibfaul sind verwenden wir anstelle ZUSTAND nur ST für State. So können sich folgende Zustände für die Steuerung ergeben.

    • ST_START: In diesem Zustand startet die Statemachine, hier wird ermittelt, welche Spannung der Akku hat, und ob Netzspannung vorhanden ist. Entsprechend wird der Zustand der Statemachine eingestellt.
    • ST_BATT_CHARGING: In diesem Zustand wird der Akku geladen, bis die Ladeschlussspannung erreicht ist. In Diesem Zustand wird die Netzversorgung überwacht, aber auch die Taster Test und Set. Anwahl der Akkupflege ist in diesem Zustand nicht erlaubt.
    • ST_BATT_FULL: In diesem Zustand ist der Akku vollgeladen, die Ladung wird nur noch erhalten. In diesem Zustand wird die Netzspannung überwacht, aber auch die Tasten Test, Set und Akkupflege.
    • ST_BATT_UNCHARGING: In diesem Zustand wird der Akku aufgrund der Benutzereingabe „Akkupflege“ entladen. Bei Stromausfall wird der Zustand natürlich beendet. Taste Test beendet den Zustand logischerweise ebenfalls, denn sie simuliert den Stromausfall.
    • ST_POWER_FAILURE: In diesem Zustand dauert der Stomausfall an. Die Notbeleuchtung ist an, wenn der eingestellte Helligkeitswert unterschritten ist.
    • ST_SET: In diesem Zustand kann mit dem Poti der Schwellwert eingestellt werden, bei dem die Notbeleuchtung eingeschaltet wird. Es wird also direkt der Poti-Wert mit dem LDR-Wert verglichen und entsprechend die Notbeleuchtung ein- oder ausgeschaltet. Bei erneutem Drücken der Set-Taste, wird der Poti-Wert im EEProm gespeichert und als Helligkeitswert im Falle des Stromausfalls als Grenzwert verwendet. Um anzuzeigen, dass der Einstellmode aktiv ist, soll die LED_Netz im Sekundentakt blinken.
    • ST_BATT_CRITICAL: In diesem Zustand ist die Akkuspannung unter einem kritischen Wert. Die Notbeleuchtung wird abgeschaltet, LED’s alle aus, bis auf LED_Charge, diese soll blinken, um den kritischen Zustand anzuzeigen.
    Das Ganze ist etwas unübersichtlich, daher verwenden wir wieder unsere Zustandstabelle. Zustände in die Zeilen, Ereignisse (Sensorwerte, Tasten) in die Spalten eintragen. An den Schnittpunkten werden die Zustände eingetragen, in die gewechselt wird, wenn das entsprechende Ereignis auftritt.

    ZustandNetzspannung
    (Pin_Power)
    Akkuzustand



    (ADC0)
    Taster



    Test
    Taster



    Akkupflege
    Taster



    Set
    Bemerkung/Aktion
    ST_STARTAusfall -> ST_POWER_FAILUREWenn kein Netzausfall:



    Akku Nicht voll ->
    ST_BATT_CHARCHING

    Akku Voll ->
    ST_BATT_FULL
    ---Überprüfen der Netzspannung Kein Netzausfall, dann wechsel in à ST_BATT_FULL oder à ST_BATT_CHARGING
    ST_BATT_CHARGINGAusfall ->
    ST_POWER_FAILURE
    Akku Voll ->
    ST_BATT_FULL
    ->
    ST_POWER_FAILURE
    -->
    ST_SET
    Akku laden.
    Ladeelektronik aktivieren, LED-Status anzeigen
    ST_BATT_FULLAusfall ->
    ST_POWER_FAILURE
    Akku Nicht voll ->
    ST_BATT_CHARGING
    ->
    ST_POWER_FAILURE
    ->
    ST_BATT_UNCHARGE
    ->
    ST_SET
    Akku ist voll.
    Umschaltung in Erhaltungsladen.
    ST_BATT_UNCHARGINGAusfall -> ST_POWER_FAILUREAkku kritisch -> ST_BATT_CHARGING->
    ST_POWER_FAILURE
    --Akku entladen.
    Umschalten in Akku entladen und LED-Status aktualisieren
    ST_SET----->
    ST_START
    Einstellung der Helligkeit
    Led_Netz blinkt
    ST_BATT_CRITICALNetz da -> ST_BATT_CHARGING----Akkuzustand kritisch. Alles ausschalten, Led_Charge blinkt
    ST_POWER_FAILURENetz da -> ST_BATT_CHARGINGKritisch à ST_BATT_CRITICAL---Stromausfall.
    Notbeleuchtung aktivieren, LED-Status aktialisieren



    Die obige Zustandstabelle zeigt an, was der Automat (Notbeleuchtung) in welchem Zustand macht und auf welche Ereignisse er reagiert. Auf diese weise kann man keine Ereignisse vergessen, auf die reagiert werden muss, da in jedem Feld etwas stehen muss.
    Vielleicht ist die Tabelle für den einen oder anderen noch etwas unklar zu verstehen, daher ein greife ich zur Erklärung einen Zustand heraus.
    Angenommen die Notbeleuchtung befindet sich gerade im Zustand ST_BATT_CHARGING. Das bedeutet, der Akku soll geladen werden. Dies ist auch in der Spalte Bemerkung/Aktion zu sehen. Nun können in diesem Zustand verschiedene Ereignisse eintreten. In den Spalten sind alle Ereignisse (siehe 1. Zeile) aufgeführt, die eintreten können. Nun steht in dem Feld in dem sich der Zustand mit dem Ereignis kreuzt der resultierenden Zustand. in den gewechselt werden soll. Tritt also im Zustand ST_BATT_CHARGING (Zeile 3) ein Ausfall der Netzspannung ein (Spalte Netzspannung), wird in den Zustand -> ST_POWER_FAILURE gewechselt. In Spalte Akkupflege steht z.B. ein Strich. Bedeutet, bei diesem Ereignis wird kein Zustandswechsel stattfinden. In Spalte Taster Set steht "-> ST_SET", das bedeutet, dass wenn Taste Set gedrückt wird immer in den Zustand ST_SET gewechselt wird.

    Das Zeichen "->" deutet nur an, dass ein Zustandswechsel erfolgt. Davor kann eine Bedingung stehen. Nach dem Zeichen "->" steht der Ziel-Zustand, in den gewechselt wird.
    Man könnte das auch kurz etwa so notieren: [Bedingung] -> Ziel-Zustand

    Bedingung ist optional (deshalb in eckigen Klammern) und macht oft Sinn, eine anzugeben.

    Was noch fehlt ist der Code, wie man die Notbeleuchtung in Code umsetzt.

    BASCOM Source Code: FSM_Notbeleuchtung

    1. ' Notbeleuchtung als Statemachine (Beispiel)
    2. ' Der Code ist nicht getestet, er kann somit noch Fehler enthalten
    3. ' und ist bei Verwendung anzupassen (z.B. GetBattState())
    4. $Regfile = "m8Adef.dat"
    5. $HWStack = 32
    6. $SWStack = 64
    7. $Framesize = 32
    8. $Crystal = 8000000
    9. Const TRUE = 1
    10. Const FALSE = 0
    11. ' --------------------------------------------------------
    12. ' Zustände des Automaten definieren
    13. Const ST_START = 0 ' Start-Zustand des Automaten
    14. Const ST_BATT_CHARGING = 1 ' Zustand Akku wird geladen
    15. Const ST_BATT_FULL = 2 ' Zustand Akku ist voll
    16. Const ST_BATT_UNCHARGING = 3 ' Zustand Akku wird entladen (Akkupflege)
    17. Const ST_BATT_CRITICAL = 4 ' Zustand Akkuspannung ist kritisch
    18. Const ST_SET = 5 ' Zustand Einstellung der Helligkeits-Schwelle
    19. Const ST_POWER_FAILURE = 6 ' Zustand Netzfall
    20. ' --------------------------------------------------------
    21. ' Mögliche Lade-Zustände des Akkus
    22. Const BATT_UNKNOWN = 0 ' Akkuzustand noch nicht ermittelt
    23. Const BATT_CRITICAL = 1 ' Akkuzustand kritisch (Leer)
    24. Const BATT_NOT_FULL = 2 ' Akkuzustand zwischen Kritisch und Voll
    25. Const BATT_FULL = 3 ' Akkuzustand voll
    26. ' --------------------------------------------------------
    27. ' Definition der ADC-Eingänge
    28. Const ADC_BATT = 0 ' ADC0, Akku wird am ADC0 gemessen
    29. Const ADC_LUMINANCE = 1 ' ADC1, Helligkeit von LDR
    30. Const ADC_POTI = 2 ' ADC2, Poti Helligkeitseinstellung
    31. ' --------------------------------------------------------
    32. ' Eingänge
    33. Pin_Power Alias PinB.0 ' High-Pegel -> Netzspannung da
    34. Taste_Set Alias PinD.3 : Set Taste_Set ' Einstellung der Helligkeitsschwelle
    35. Taste_Akkupflege Alias PinD.5 : Set Taste_Akkupflege ' Akkupflege starten
    36. ' --------------------------------------------------------
    37. ' Ausgänge
    38. Pin_Light Alias PortB.1 : Config Pin_Light = Output ' Anschluss Beleuchtung
    39. Pin_Charge Alias PortB.2 : Config Pin_Charge = Output ' Anschluss Laden aktivieren
    40. Pin_ChargeHold Alias PortB.3 : Config Pin_ChargeHold = Output ' Anschluss Ladeerhaltung
    41. Led_Charge Alias PortD.0 : Config Led_Charge = Output ' Lade-LED
    42. Led_Netz Alias PortD.1 : Config Led_Netz = Output ' Netz vorhanden LED
    43. Led_Batt_Full Alias PortD.2 : Config Led_Batt_Full = Output ' Akku Voll Led
    44. ' --------------------------------------------------------
    45. ' Include-Dateien
    46. $Include "Statemachine.inc" ' Routinen Statemachine einbinden
    47. ' --------------------------------------------------------
    48. ' Deklarationen Routinen Hauptprogramm
    49. Declare Function IsPowerOK() as Byte
    50. Declare Function GetBattState() as Byte
    51. Declare Function GetLuminanceState() as Byte
    52. Declare Sub ISR_Timer1() ' Timer1-Interrupt-Routine
    53. ' --------------------------------------------------------
    54. ' verwendete Variablen
    55. Dim Luminance as Word ' Helligheit
    56. Dim Luminance_Limit as Word ' Helligkeits-Schwellwert
    57. Dim eeLuminance_Limit as ERAM Word ' EEProm Wert des Luminamce_Limit
    58. Dim FlagTick as Byte ' Wird alle 0,5s von ISR-Routine auf True gesetzt
    59. ' --------------------------------------------------------
    60. ' Hardware konfigurieren
    61. ' --------------------------------------------------------
    62. ' --------------------------------------------------------
    63. ' Timer für blinkende LED
    64. Config Timer1 = Timer , Prescale = 256 , Clear Timer = 1
    65. Compare1A = 15525 - 1 ' Frequenz einstellen auf 2 Hz
    66. On Timer1 ISR_Timer1 ' ISR-Routine definieren
    67. Enable Timer1 ' Overflow-Interrupt zulassen
    68. ' --------------------------------------------------------
    69. ' ADC-Converter konfigurieren
    70. Config ADC = Single , Prescaler = Auto , Reference = Internal_2.56 ' Interne Referenz-Spannung 2.56V
    71. ' ----------------------------------------------------------------------------
    72. ' Hauptschleife
    73. ' ----------------------------------------------------------------------------
    74. Call SetState(ST_START) ' Startzustand festlegen
    75. Do
    76. Select Case GetState()
    77. ' --------------------------------------------------
    78. Case ST_START
    79. ' --------------------------------------------------
    80. If IsPowerOK() = FALSE then ' Netzausfall?
    81. Call SetState(ST_POWER_FAILURE)
    82. Else
    83. Select Case GetBattState() ' Akkuzustand ermitteln
    84. Case BATT_NOT_FULL
    85. Call SetState(ST_BATT_CHARGING)
    86. Case BATT_FULL
    87. Call SetState(ST_BATT_FULL)
    88. End Select
    89. End If
    90. ' Initialisieren des Helligkeits-Schwellwrtes
    91. If eeLuminance_Limit = &hFFFF then ' Limit noch nicht festgelegt?
    92. eeLuminance_Limit = 512 ' Halber ADC-Wert festlegen
    93. End If
    94. Luminance_Limit = eeLuminance_Limit ' Schwellwert aus EEProm laden
    95. ' --------------------------------------------------
    96. Case ST_BATT_CHARGING ' Akku wird geladen
    97. ' --------------------------------------------------
    98. If IsStateChanged() = TRUE then ' Einmalige Aktion
    99. Set Pin_Charge ' Ladeelektronik aktivieren
    100. Reset Pin_ChargeHold ' Ladeerhaltung deaktivieren
    101. Set Led_Charge ' Akkustatus Laden anzeigen
    102. Reset Led_Batt_Full ' Led Akku Voll aus
    103. Set Led_Netz ' Netz anzeigen
    104. End If
    105. ' Exitbedingungen (Ereignisse)
    106. If IsPowerOK() = FALSE then ' Netzausfall/Simulation Netzausfall
    107. Call SetState(ST_POWER_FAILURE)
    108. ElseIf GetBattState() = BATT_FULL then ' Akku ist voll
    109. Call SetState(ST_BATT_FULL)
    110. ElseIf Taste_Set = 0 then ' Helligkeitsschwelle einstellen
    111. Call SetState(ST_SET)
    112. End If
    113. ' --------------------------------------------------
    114. Case ST_BATT_FULL ' Akku ist voll
    115. ' --------------------------------------------------
    116. If IsStateChanged() = TRUE then ' Einmalige Aktion
    117. Reset Pin_Charge ' Ladeelektronik deaktivieren
    118. Set Pin_ChargeHold ' Ladeerhaltung aktivieren
    119. Set LED_Batt_Full ' LED Batt Full ein
    120. Reset LED_Charge ' LED Charge aus
    121. Set Led_Netz ' Netz anzeigen
    122. End If
    123. ' Exitbedingungen (Ereignisse)
    124. If IsPowerOK() = FALSE then ' Netzausfall/Simulation Netzausfall
    125. Call SetState(ST_POWER_FAILURE)
    126. ElseIf GetBattState() = BATT_NOT_FULL then ' Muss Akku nachgeladen werden?
    127. Call SetState(ST_BATT_CHARGING)
    128. ElseIf Taste_Set = 0 then ' Helligkeitsschwelle einstellen
    129. Call SetState(ST_SET)
    130. End If
    131. ' --------------------------------------------------
    132. Case ST_BATT_UNCHARGING ' Akku wird entladen
    133. ' --------------------------------------------------
    134. If IsStateChanged() = TRUE then ' Einmalige Aktion
    135. Reset Pin_Charge ' Ladeelektronik deaktivieren
    136. Reset Pin_ChargeHold ' Ladeerhaltung deaktivieren
    137. Reset Pin_Charge ' Ladeelektronik deaktivieren
    138. Reset Pin_ChargeHold ' Ladeerhaltung deaktivieren
    139. End If
    140. ' Wiederkehrende Aktion / Exitbedingungen (Ereignisse)
    141. Select Case GetBattState()
    142. Case BATT_FULL
    143. Set Led_Batt_Full ' Akkustatus Voll anzeigen
    144. Case BATT_NOT_FULL
    145. Reset Led_Batt_Full ' Akkustatus Voll ausschalten
    146. Case BATT_CRITICAL ' Akku leer, Exitbedingung
    147. Call SetState(ST_BATT_CHARGING)
    148. End Select
    149. If IsPowerOK() = FALSE then ' Stromausfall
    150. Call SetState(ST_POWER_FAILURE)
    151. End If
    152. Led_Netz = Pin_Power ' Netz-Status anzeigen
    153. ' --------------------------------------------------
    154. Case ST_BATT_CRITICAL ' Akkuspannung kritisch
    155. ' --------------------------------------------------
    156. If IsStateChanged() = TRUE then ' Einmalige Aktion
    157. Reset Led_Batt_Full
    158. Reset Led_Charge
    159. End If
    160. ' Wiederkehrende Aktionen
    161. Led_Netz = Pin_Power ' Netzstatus anzeigen
    162. ' Exitbedingungen (Ereignisse)
    163. If IsPowerOK() = TRUE then
    164. Call SetState(ST_BATT_CHARGING)
    165. ElseIf FlagTick = TRUE then ' Led-Charge soll blinken
    166. Toggle Led_Charge
    167. FlagTick = FALSE
    168. End If
    169. ' --------------------------------------------------
    170. Case ST_SET ' Schwellwert der Helligkeit einstellen
    171. ' --------------------------------------------------
    172. If IsStateChanged() = TRUE then ' Einmalige Aktion
    173. Bitwait Taste_Set , Set ' Warten, bis Taste losgelassen wird
    174. End If
    175. Luminance = GetAdc(ADC_LUMINANCE) ' Helligkeit messen
    176. Luminance_Limit = GetAdc(ADC_POTI) ' Poti-Stellung lesen
    177. If Luminance >= Luminance_Limit then
    178. Reset Pin_Light ' Notbeleuchtung aus
    179. Else
    180. Set Pin_Light ' Notbeleuchtung an
    181. End If
    182. If Taste_Set = 0 then ' Wert übernehmen
    183. eeLuminance_Limit = Luminance ' Neuer Wert ins EEProm
    184. Bitwait Taste_Set , Set ' Warten, bis Taste Losgelassen wird
    185. Call SetState(ST_START)
    186. ElseIf FlagTick = TRUE then
    187. Toggle Led_Netz
    188. FlagTick = FALSE
    189. End If
    190. ' --------------------------------------------------
    191. Case ST_POWER_FAILURE ' Stromausfall aktiv
    192. ' --------------------------------------------------
    193. If IsStateChanged() = TRUE then ' Einmalige Aktion
    194. Reset Led_Netz ' Netzausfall anzeigen
    195. If GetLuminanceState() = True then ' Notbeleuchtung einschalten?
    196. Set Pin_Light
    197. End If
    198. End If
    199. ' Wiederkehrende Aktionen
    200. Select Case GetBattState() ' Akkuanzeige aktualisieren
    201. Case BATT_FULL
    202. Set LED_Batt_Full ' Akkuzustand anzeigen
    203. Case BATT_NOT_FULL
    204. Reset LED_Batt_Full ' Akkuzustand anzeigen
    205. End Select
    206. ' Exitbedingungen (Ereignisse)
    207. If IsPowerOK() = TRUE then ' Netz wieder da?
    208. Call SetState(ST_BATT_CHARGING)
    209. ElseIf GetBattState() = BATT_CRITICAL then ' Akku leer?
    210. Call SetState(ST_BATT_CRITICAL)
    211. End If
    212. End Select
    213. Loop
    214. ' ----------------------------------------------------------------------------
    215. ' Unter-Routinen / Hilfsroutinen
    216. ' ----------------------------------------------------------------------------
    217. ' --------------------------------------------------------
    218. ' Pin abfragen, ob Netzspannung verfügbar ist
    219. ' --------------------------------------------------------
    220. Function IsPowerOK() as Byte
    221. If Pin_Power = 1 then
    222. IsPowerOK = TRUE
    223. Else
    224. IsPowerOK = FALSE
    225. End If
    226. End Function
    227. ' --------------------------------------------------------
    228. ' Gibt Akku-Zustand zurück
    229. ' Die Schwellwerte müssen in der Schaltung ermittelt und angepasst werden
    230. ' --------------------------------------------------------
    231. Function GetBattState() as Byte
    232. local tmp as Word
    233. tmp = Getadc(ADC_BATT)
    234. Select Case tmp
    235. Case Is >= 1000 ' Akku voll
    236. Case Is >= 500 ' Akku nicht voll
    237. Case Is < 430 ' Akku kritisch
    238. End Select
    239. End Function
    240. ' --------------------------------------------------------
    241. ' Gibt zurück, ob aktuelle Helligkeit kleiner dem Helligkeits-Limit ist.
    242. ' Also liefert TRUE, wenn Notbeleuchtung eingeschaltet werden soll, sonst FALSE
    243. ' --------------------------------------------------------
    244. Function GetLuminanceState() as Byte
    245. local tmp as Word
    246. tmp = GetAdc(ADC_LUMINANCE)
    247. If tmp < Luminance_Limit then
    248. GetLuminanceState = TRUE
    249. Else
    250. GetLuminanceState = FALSE
    251. End If
    252. End Function
    253. ' --------------------------------------------------------
    254. ' ISR_Routine Timer1 Overflow
    255. ' Wird alle 0,5s aufgerufen (2Hz)
    256. ' --------------------------------------------------------
    257. Sub ISR_Timer1()
    258. FlagTick = True
    259. End Sub
    Display All


    Der Code des Automaten ist jetzt schon deutlich komplexer geworden.
    Ladet den einfach unten herunter und öffnet den Source in die Bascom-IDE. Es sieht schlimmer aus als es ist.

    Fakt ist, dass man im Code schon unterteilt die Zustände erkennt (Hauptschleife), in denen auch die Aktionen und die Ereignisse behandelt werden.
    Man sollte sofort erkennen, dass ein so programmierter Code sehr Übersichtlich ist. Man erkennt auch deutlich, wie die Statetabelle und die Code-Struktur korreliert.

    Der Code wurde übrigens nicht mit Hardware getestet und ist eigentlich nur für die Einführung in die Statemachine als etwas komplexeres Beispiel gedacht.
    Wer es dennoch real ausprobieren möchte, muss auch mit Programmierfehlern rechnen. Die zu beheben sollte jedoch aufgrund der State-Tabelle und ausreichend kommentiertem Code nicht schwer fallen. Auch Anpassungen sollten keine größeren Schwierigkeiten bereiten.

    Die Eingangs gestellt Frage, was eine Statemachine ist und wie man die in Bascom einbindet, dürfte damit geklärt sein. Bleibt noch die Frage, wozu man das braucht.
    Nun, es erleichtert die Programmierung und auch die Dokumentation. Es lassen sich komplexe Steuerung und Abläufe realisieren, die immer noch übersichtlich bleiben. Wer mal versucht die obige Steuerung herkömmlich zu programmieren, also ohne Statemachine, wird schnell merken wo die Vorteile der Statemachine liegen. Der Code bleibt wartbar.

    Viel Spaß damit.

    Übungsaufgaben

    Wer jetzt Blut geleckt hat und es mal selbst versuchen möchte, kann sich mal Gedanken zu folgenden Aufgaben machen und versuchen eine State-Tabelle anzulegen oder den Code umzusetzen.


    Übung 1: Akkuwächter für 12V Akkus.
    Die Spannung einer Autobatterie soll überwacht werden. LED's sollen den Zustand anzeigen. Ist die Spannung <11,5V soll eine rote LED den niedrigen Batteriezustand signalisieren. Eine gelbe LED signalisiert Spannungen über 13,8V. Eine grüne LED zeigt korrekte Akkuspannung an. Die Akkuspannung soll mittels ADC gemessen werden.

    Übung 2: Torsteuerung
    Ein elektrisch betriebenes Firmentor soll manuell gesteuert werden. Hierfür sind 3 Bedienknöpfe (Taster Auf, Zu, Stop) vorgesehen. Wenn das Tor geschlossen ist (Endschalter Tor zu aktiv) ist, kann nur die Taste Auf betätigt werden. Wenn das Tor geschlossen ist (Endschalter Tor zu aktiv), kann nur die Taste Auf bedient werden. Während das Tot auf- bzw. zu fährt kann das Tor (Taste Stop) vorzeitig gestoppt werden. Ist keiner der Endschalter aktiv, soll mit Taster Auf bzw. Taster Zu das Tor wieder in Bewegung versetzt werden können. Der Antrieb für das Tor wird durch 2 Ausgänge gesteuert. Ein Pin für Richtung (Tor Öffnen = HIGH, Tor Schließen = Low) und ein Pin für Motor an (An = High).

    Torsteuerung: Ampel-Erweiterung

    Wenn ihr die Steuerung bis hierhin geschafft habt, könnt ihr mal die Ampel-Erweiterung einbauen.
    Nach einer gewissen Zeit möchte der Auftraggeber, dass eine Ampel (Rot/Grün) nachgerüstet wird. Sie soll anzeigen, ob man hineinfahren darf oder nicht. Ist das Tor vollständig geöffnet (Endschalter aktiv), soll die Ampel grün leuchten. Während sich das Tor bewegt oder wenn es vorzeitig gestoppt wurde, soll die Ampel rot zeigen. Ist das Tor geschlossen, geht die Ampel aus, um Energie zu sparen.

    Torsteuerung: Aufprallschutz-Erweiterung
    Wenn ihr es bis hier her geschafft habt, könnt ihr noch eine Erweiterung nachrüsten.
    Der Auftraggeber hat festgestellt, dass es eine Gefahr darstellt, wenn das Tor zu fährt und sich noch etwas im Weg befindet wie eine Person oder ein Fahrzeug. Um Verletzungen und Schäden zu vermeiden, soll ein Aufprallschutz am Tor angebracht werden. Dieser besteht aus einem Taster, der betätigt wird, wenn das Tor beim Schließen auf ein Hindernis trifft. In dem Fall soll das Tor sofort stoppen. Die Manuelle Bedienung lässt dann nur die Taste Auf als Bedientaste zu.

    Torsteuerung: Überwachung Torbewegung
    Der Auftraggeber möchte, dass die Torbewegung überwacht werden soll. Hierfür soll ein Timeout erkennen, ob das Tor ordnungsgemäß schließt oder öffnet. Die Funktion sieht folgendermaßen aus.
    Wenn das Taste Tor Zu betätigt wird, dauert es eine gewisse Zeit, bis das Tor den Endschalter ZU erreicht. Ist die Zeit deutlich länger, kann man davon ausgehen, dass ein Fehler am Antrieb vor liegt. Der Auftraggeber sagt, dass das Tor nie länger als 60 Sekunden zum Öffnen bzw. Schließen benötigt. Sollte nach 90 Sekunden der Endschalter nicht erreicht sein, kann man von einem Fehler ausgehen. In diesem Fall soll der Antrieb auf jeden Fall abgeschaltet werden. Und um den Fehler anzuzeigen, soll die rote Ampel im Sekundentakt blinken.

    Schlussbemerkung
    Eine Statemachine kann sehr unterschiedliche Anforderungen erfüllen und ist damit situationsbedingt sehr flexibel.
    So kann es unter Umständen gewünscht sein, dass bestimmte Zustände auf keinerlei Ereignisse reagieren sollen. Das könnte z.B. Im Fehlerfall bei einer Notabschaltung der Fall sein, um größeren Schaden zu vermeiden. In der Regel sind aber in jedem Zustand Ereignisse notwendig, um den Zustandswechsel zu initiieren.

    In meinen Beispielen habe ich die Aktion, die bei einem Zustandswechsel ausgeführt werden soll, stets in den Ziel-Zustand im Bereich der Bedingung "If IsStateChanged() = TRUE" eingefügt. Das hat einen einfachen Grund. Man muss die Aktion nur 1x ausführen und zwar in dem Zustand, in den gewechselt wird.

    Zustandsautomaten sind nicht nur für Steuerungen (Hardware) einsetzbar, sondern können auch bei Regelungen eingesetzt werden. Ein weiterer Einsatzbereich ist neben der Hardwaresteuerung auch die Software-Steuerung. Hierbei ändert der Automat seinen Zustand abhängig von den Daten, die er verarbeitet. Dies kann z.B. beim dekodieren von seriellen Signalen der Fall sein (Serielle Schnittstelle, Netzwerk-Datenverkehr). Auch ein Interpreter ist im Grunde eine Statemachine. Denn sie interpretiert die geschriebenen Befehle und führt dann die entsprechende Aktion aus. Compiler sind im Grunde auch nichts anderes. Sie interpretieren Text und erzeugen abhängig davon einen Binärcode, den der Prozessor versteht.

    Die hier vorgestellte Möglichkeit einer Statemachine kann ein einzelnen Zustandsautomat (Objekt) verwalten.
    Es gibt Situationen, da reicht ein einzelner Automat nicht aus. Möchte man mehrere Automaten quasi parallel laufen lassen, ist das möglich, wenn die Include-Datei angepasst wird, so dass mehrere Zustände unabhängig voneinander verwaltet werden können. Ein typische Beispiel für parallelle Automaten sind beispielsweise Computer-Spiele.

    Jeder kennt Spiele in denen man gegen den Computer spielt. Der Computer-Spieler ist in dem Fall ein Automat. Manche Spiele lassen es zu, den Computer gegen sich selbst spielen zu lassen. In dem Fall spielt allerdings ein weiterer Automat den 2. Spieler. Es spielt also Automat 1 gegen Automat 2. Jeder Automat kann hier als eigenständiges Objekt betrachtet werden das unabhängig vom anderen Objekt ist. Sie verwenden möglicherweise die gleichen Konstanten als Zustände, jeder Automat kann sich trotzdem in einem anderen Zustand befinden.

    Man mag es kaum glauben, aber fast alles kann man, sofern man das möchte, als Automat betrachten.
    Man verzeihe mir den Vergleich mit Babette, aber auch sie ist ein Automat. Babette ist entweder am schlafen, sie ist sauer oder gar eingeschnappt. Oder sie ist gelangweilt und erzählt einen Witz. Das alles sind Zustände.

    In diesem Sinne frohes Gelingen!

    Mitch
    Files

    676 times viewed