Fußgängerampel Erweiterung

Bitte Code Tags verwenden. Sonst ist das nicht lesbar.

Hier sind wir wieder mal beim Thema endliche Zustandsautomaten (finite state machine). Mit delay() wird das nichts. Du musst verschiedene Zustände anlegen. Und dann zeitgesteuert zwischen den Zuständen wechseln. Die Zeitsteuerung muss nicht-blockierend mit millis() erfolgen damit man zwischendurch was anderes erledigen kann, z.B. Taster, Serial oder Ethernet abfragen.

Hallo und willkommen im Forum!

Ich habe eine Anleitung Endlicher Automat mit millis() verfaßt, die Dir (im Forum ist diese Anrede üblich) möglicherweise helfen könnte. Am gewählten Thema kann man erkennen, daß ich von der Modellbahn mit LEDs als Hausbeleuchtung zum Arduino gekommen bin.

schlier: Könnte mir jemand behilflich sein?

Anbei ein Sketch den man eventuell umbauen könnte

In Sachen "Finite State Machine" (FSM, Zustandsautomat) stimme ich meinem Vorredner voll zu. Eine Ampelsteuerung ist ein klassischer Fall für einen Zustandsautomaten mit verschiedenen Zuständen, aus denen heraus in andere Zustände umgeschaltet wird.

Weiterhin darf ein Programm, das interaktiv reagieren soll, z.B. auf die Bettelknopf-Grünanforderung, niemals mit "delay()" blockiert werden.

Und "Interrupts" haben in so einem Programm und bei einer Tasterabfrage schon gar nichts verloren.

Deine Programmvorlage dürfte daher für Dein Vorhaben ziemlich unbrauchbar sein.

In Sachen FSM kann ich Dir diese Library empfehlen: http://playground.arduino.cc/Code/SMlib

Lade Dir diese mal herunter, installiere sie und arbeite die Beispiele durch.

Die Arbeitsweise ist wie folgt: Für jeden verschiedenen Zustand kannst Du zwei parameterlose Funktionen definieren: - eine Funktion, die einmalig läuft, wenn der Zustand aktiv wird - eine Funktion, die ständig läuft und abhängig von Deinen Bedingungen in einen anderen Zustand umschaltet

Du kannst Dich dann vollständig darauf konzentrieren, - was muß ausgeführt werden, wenn dieser Zustand aktiv wird? - unter welchen Bedingungen muß aus diesem in einen anderen Zustand geschaltet werden?

Alle Zustände fein säuberlich voneinander getrennt, zwei Funktionen für jeden Zustand.

Und um die richtigen Funktionsaufrufe kümmert sich die Library automatisch, wenn Du den aktiven Zustand in einen anderen umschaltest. Nur Deine Programmlogik mußt Du natürlich selbst in sich konsistent halten. Also dass beispielsweise kein Zustand existiert, aus dem heraus niemals wieder ein anderer Zustand aktiviert wird.

Wenn Du Probleme damit hast, sag Bescheid wo es klemmt.

Edit/Nachtrag: Gerade mal in die Library reingeschaut, das "example_3" ist quasi das, worauf Du aufbauen kannst.

--edit-- Beitrag vom Vorposter entfernt

Das mit den Millis glaub ich verstanden zu haben. Nur in Sachen FSM, Zustandsautomat mit dem Beispiel 3 blicke ich nicht durch

Aus meinem Beispiel habe ich jetzt eine reine Fußgängerampel gemacht, wo die Aotofahrer so lange Grün haben, bis der Anforderungstaster betätigt wird:

// Ampel Belegung der Ausgaenge
const byte RotPin = 2;
const byte GelbPin = 3;
const byte GruenPin = 4;
const byte FGAnfPin = 5;  // Rueckmeldung "Gruen kommt"
const byte FGRotPin = 6;
const byte FGGruenPin = 7;
const byte FGTasterPin = 8;  // Anforderungstaster

//
const boolean ein = HIGH;
const boolean aus = LOW;
//
const int ZEITROTPHASE = 3000;
const int ZEITGELBPHASE = 1000;
const int ZEITMINGRUENPHASE = 2000;
unsigned long ampelMillis;
unsigned long ampelIntervall;
//
enum ZUSTAENDE {ROT, ROTGELB, GRUEN, GRUEN_WARTEN, GELB};
byte zustand = ROT;

void setup() {
  // Definiert die Pins als Ausgang
  pinMode(RotPin, OUTPUT);
  pinMode(GelbPin, OUTPUT);
  pinMode(GruenPin, OUTPUT);
  pinMode(FGAnfPin, OUTPUT);
  pinMode(FGRotPin, OUTPUT);
  pinMode(FGGruenPin, OUTPUT);
  pinMode(FGTasterPin, INPUT_PULLUP);
}

void loop() {
  //
  // Ampelschaltung
  if (digitalRead(FGTasterPin) == LOW && (zustand == GRUEN || zustand == GRUEN_WARTEN)) {
    digitalWrite(FGAnfPin, HIGH);
  }
  if (millis() - ampelMillis >= ampelIntervall) {
    switch (zustand) {
      case ROT:
        digitalWrite(RotPin, HIGH);
        digitalWrite(GelbPin, LOW);
        digitalWrite(GruenPin, LOW);
        digitalWrite(FGRotPin, LOW);
        digitalWrite(FGGruenPin, HIGH);
        digitalWrite(FGAnfPin, LOW);
        zustand = ROTGELB;
        ampelMillis = millis();
        ampelIntervall = ZEITROTPHASE;
        break;
      case ROTGELB:
        digitalWrite(RotPin, HIGH);
        digitalWrite(GelbPin, HIGH);
        digitalWrite(GruenPin, LOW);
        digitalWrite(FGRotPin, HIGH);
        digitalWrite(FGGruenPin, LOW);
        zustand = GRUEN;
        ampelMillis = millis();
        ampelIntervall = ZEITGELBPHASE;
        break;
      case GRUEN:                        // Minimale Gruenphase
        digitalWrite(RotPin, LOW);
        digitalWrite(GelbPin, LOW);
        digitalWrite(GruenPin, HIGH);
        digitalWrite(FGRotPin, HIGH);
        digitalWrite(FGGruenPin, LOW);
        zustand = GRUEN_WARTEN;
        ampelMillis = millis();
        ampelIntervall = ZEITMINGRUENPHASE;
        break;
      case GRUEN_WARTEN:                 // Warten auf Anforderung
        digitalWrite(RotPin, LOW);
        digitalWrite(GelbPin, LOW);
        digitalWrite(GruenPin, HIGH);
        digitalWrite(FGRotPin, HIGH);
        digitalWrite(FGGruenPin, LOW);
        if (digitalRead(FGAnfPin) == HIGH) {
          zustand = GELB;
        }
        ampelMillis = millis();
        ampelIntervall = 0;
        break;
      case GELB:
        digitalWrite(RotPin, LOW);
        digitalWrite(GelbPin, HIGH);
        digitalWrite(GruenPin, LOW);
        digitalWrite(FGRotPin, HIGH);
        digitalWrite(FGGruenPin, LOW);
        zustand = ROT;
        ampelMillis = millis();
        ampelIntervall = ZEITGELBPHASE;
        break;
    }
  }
}

Möglicherweise hilft es Dir ja irgendwie beim Verständnis.

schlier: Nur in Sachen FSM, Zustandsautomat mit dem Beispiel 3 blicke ich nicht durch

Ich habe Dir einen Beispielcode für eine Fußgänger-Bettelampel mit dieser FSM-Library gemacht, das Du bei Bedarf weiter ausbauen kannst:

#include 

SM Ampel(FahrbahnGruenInit, FahrbahnGruen); //Anfangsstatus setzen

byte fahrGruenPin=2;
byte fahrGelbPin=3;
byte fahrRotPin=4;
byte fussGruenPin=5;
byte fussRotPin=6;
byte anforderungPin=10;

#define buttonMode INPUT_PULLUP // INPUT_PULLUP oder INPUT

void setAmpel(boolean fahrGruen, boolean fahrGelb, boolean fahrRot, boolean fussGruen, boolean fussRot)
{ // diese Funktion setzt den Zustand aller Ampel-LEDs 
  digitalWrite(fahrGruenPin, fahrGruen);
  if (fahrGruen) Serial.print("A-Gruen\t");
  digitalWrite(fahrGelbPin, fahrGelb);
  if (fahrGelb) Serial.print("A-Gelb\t");
  digitalWrite(fahrRotPin, fahrRot);
  if (fahrRot) Serial.print("A-Rot\t");
  digitalWrite(fussGruenPin, fussGruen);
  if (fussGruen) Serial.print("F-Gruen\t");
  digitalWrite(fussRotPin, fussRot);
  if (fussRot) Serial.print("F-Rot\t");
  Serial.println();
}

State FahrbahnGruenInit()
{
  Serial.println("Fahrbahn gruen");
  setAmpel(true, false, false, false, true);
}

State FahrbahnGruen()
{ // Fahrbahn Grünzeit: Bis zur Bettelanforderung
  byte anforderung=digitalRead(anforderungPin);
  if (buttonMode==INPUT_PULLUP) anforderung=!anforderung;
  if (anforderung) Ampel.Set(FahrbahnAnforderungInit,FahrbahnAnforderung);
}

State FahrbahnAnforderungInit()
{
  Serial.println("Bettelampel-Anforderung registriert");
}

State FahrbahnAnforderung()
{ // 10 Sekunden nach der Bettelanforderung bekommt die Fahrbahn gelb
  if(Ampel.Timeout(10000)) Ampel.Set(FahrbahnGelbInit, FahrbahnGelb);
}

State FahrbahnGelbInit()
{
  Serial.println("Fahrbahn gelb");
  setAmpel(false, true, false, false, true);
}

State FahrbahnGelb()
{ // 2 Sekunden Gelbphase
  if(Ampel.Timeout(2000)) Ampel.Set(FahrbahnRotInit, FahrbahnRot);
}

State FahrbahnRotInit()
{
  Serial.println("Fahrbahn rot");
  setAmpel(false, false, true, false, true);
}

State FahrbahnRot()
{ // Rotphase 2 Sekunden für Auto und Fussgänger gleichzeitig
  if(Ampel.Timeout(2000)) Ampel.Set(FussgaengerGruenInit, FussgaengerGruen);
}

State FussgaengerGruenInit()
{
  Serial.println("Fussgaenger gruen");
  setAmpel(false, false, true, true, false);
}

State FussgaengerGruen()
{ // Grünphase der Fussgängerampel: 12 Sekunden
  if(Ampel.Timeout(12000)) Ampel.Set(FussgaengerRotInit, FussgaengerRot);
}

State FussgaengerRotInit()
{
  Serial.println("Fussgaenger rot");
  setAmpel(false, false, true, false, true);
}

State FussgaengerRot()
{ // Räumzeit des Fussgängerstreifens bei rot: 8 Sekunden
  if(Ampel.Timeout(8000)) Ampel.Set(FahrbahnGruenInit, FahrbahnGruen);
}

void setup()
{
  Serial.begin(9600);
  pinMode(fahrGruenPin, OUTPUT);
  pinMode(fahrGelbPin, OUTPUT);
  pinMode(fahrRotPin, OUTPUT);
  pinMode(fussGruenPin, OUTPUT);
  pinMode(fussRotPin, OUTPUT);
  pinMode(anforderungPin, buttonMode);
}//setup()

void loop()
{
  EXEC(Ampel); // Finite State Machine rennt endlos
}//loop()

Alle Zustandsänderungen werden zur Kontrolle auch auf Serial ausgegeben.

Die Programmlogik ist wie folgt: Auto-Grünphase: unendlich lange, bis der Bettelknopf vom Fußgänger gedrückt wird Auto-Grünphase nach Bettelanforderung: weitere 10 Sekunden Auto-Gelbphase: 2 Sekunden Doppel-Rotphase für Auto und Fußgänger: 2 Sekunden Grünphase für Fußgänger: 12 Sekunden Doppel-Rotphase für Auto und Fußgänger: 8 Sekunden und dann wieder alles auf Anfang

Bei Button bin ich davon ausgegangen, dass Du nur den Button ohne Pull-Widerstand anschließt. Falls Du einen Button mit PullDown-Widerstand in Deiner Hardwareschaltung verwendest, den "buttonMode" im Programm auf INPUT statt INPUT_PULLUP umstellen!

Edit/Nachtrag: Die Erweiterung dieses Beispiels um ein "Anforderungslicht" nach dem Drücken des Buttons und um einen "Standby-Betrieb" ist extrem einfach, bei Bedarf könnte ich auch eine Version posten, die bei Fahrbahn-Grün und 60 Sekunden Nicht-Anforderung die Schaltung in "Standby" schickt (alle Lichter aus), und die aus dem Standby-Betrieb dann beim Drücken des Anforderung-Buttons dann gleich direkt in den Zustand "FahrbahnAnforderung" springt.

@jurs: Schöner Vergleich von meinem Anfänger- und Deinem Proficode! Ich hatte im Stillen gehofft, daß Du mal wieder etwas Deines Könnens zeigst. 8) Gruß in den Norden!

switch/case ist völlig legitimer Weg für Zustandsautomaten. Ja, das ist ein Einstiegsmuster für die Implementierung für FSMs. Das macht es aber nicht zwangsläufig schlecht. Für einfache Anwendungen reicht das. Das Problem damit ist, dass der Code unübersichtlich wird wenn man mehr Zustände hat und diese komplexer werden. Hier ist das aber ok.

@jurs Wow was für ein Code, davon bin ich noch weit entfernt. Ich werde die Tage einmal damit rum spielen. Da ich ja nur eine Fußgängerampel habe, werde ich versuchen es so zu definieren das die Fußgängerampel immer zwischen rot und Grün hin und her schaltet, wobei lange Phase Rot. Wenn man dann Anfordert soll sie zügig umspringen. Den Standby will ich nach x Phasen ohne Drücken eines Tasters einleiten.

Hättest Du auch eine Idee wie das mit den verschiebenden Programm Modi machen könnte?

Vielen vielen Dank, bin begeistert

schlier: Hättest Du auch eine Idee wie das mit den verschiebenden Programm Modi machen könnte?

Verstehe erst mal wie ein Zustandsautomat allgemein funktioniert. Dann verstehst du da auch wie man da zwischen verschiedenen Programmteilen umschalten kann. Egal was die machen.

Siehe auch der Code von agmue. Da wird es vielleicht deutlicher. Man hat eine Variable einem sagt in welcher Phase man sich befindet und je nachdem macht man was anderes.

Hier sind andere Varianten wie man das realisieren kann: http://forum.arduino.cc/index.php?topic=332907.0 Die zweite Version ist zu kompliziert für dich, aber die erste könnte noch verständlich sein. Dabei lässt man einfach jede Funktionen einen Zeiger auf die nachfolgende Funktion zurück geben. Wenn sich nichts ändert ist das ein Zeiger auf die aktuelle Funktion. Aber man kann auch einen Taster abfragen und in eine andere Funktion springen (so ähnlich funktioniert auch die Library die jurs verwendet intern).

Hallo,

habe ein wenig gespielt und lasse nun die Ampel selber auch die Fußgängerampel grün schalten. Nur bei Anforderung geht noch eine LED an und die Ampel schaltet schneller auf grün. Die Zeiten habe ich noch nicht richtig angepasst.

Wie kann ich denn die Anforderungspin blinken lassen ohne Delay?

#include 

SM Ampel(FahrbahnGruenInit, FahrbahnGruen); //Anfangsstatus setzen

byte fahrGruenPin=11;
byte fahrGelbPin=12;
byte fahrRotPin=13;
byte fussGruenPin=10;
byte fussRotPin=9;
byte anforderungSignalPin=8;
byte anforderungPin=2;

#define buttonMode INPUT_PULLUP // INPUT_PULLUP oder INPUT

void setAmpel(boolean fahrGruen, boolean fahrGelb, boolean fahrRot, boolean fussGruen, boolean fussRot, boolean anforderungSignal)
{ // diese Funktion setzt den Zustand aller Ampel-LEDs 
  digitalWrite(fahrGruenPin, fahrGruen);
  if (fahrGruen) Serial.print("A-Gruen\t");
  digitalWrite(fahrGelbPin, fahrGelb);
  if (fahrGelb) Serial.print("A-Gelb\t");
  digitalWrite(fahrRotPin, fahrRot);
  if (fahrRot) Serial.print("A-Rot\t");
  digitalWrite(fussGruenPin, fussGruen);
  if (fussGruen) Serial.print("F-Gruen\t");
  digitalWrite(fussRotPin, fussRot);
  if (fussRot) Serial.print("F-Rot\t");
  digitalWrite(anforderungSignalPin, anforderungSignal);
  if (anforderungSignal) Serial.print("anforderungSignal\t");
  Serial.println();
}

State FahrbahnGruenInit()
{
  Serial.println("Fahrbahn gruen");
  setAmpel(true, false, false, false, true, false);
}

State FahrbahnGruen()
{ // Fahrbahn Grünzeit: Bis zur Bettelanforderung
  byte anforderung=digitalRead(anforderungPin);
  if (buttonMode==INPUT_PULLUP) anforderung=!anforderung;
  if (anforderung) Ampel.Set(FahrbahnAnforderungInit,FahrbahnAnforderung);
  if (Ampel.Timeout(10000)) Ampel.Set(FahrbahnGelbInit, FahrbahnGelb);
}

State FahrbahnAnforderungInit()
{
  Serial.println("Bettelampel-Anforderung registriert");
  setAmpel(true, false, false, false, true, true);
}

State FahrbahnAnforderung()
{ // 5 Sekunden nach der Bettelanforderung bekommt die Fahrbahn gelb
  if(Ampel.Timeout(5000)) Ampel.Set(FahrbahnGelbInit, FahrbahnGelb);
}

State FahrbahnGelbInit()
{
  Serial.println("Fahrbahn gelb");
  setAmpel(false, true, false, false, true, false);
}

State FahrbahnGelb()
{ // 2 Sekunden Gelbphase
  if(Ampel.Timeout(2000)) Ampel.Set(FahrbahnRotInit, FahrbahnRot);
}

State FahrbahnRotInit()
{
  Serial.println("Fahrbahn rot");
  setAmpel(false, false, true, false, true, false);
}

State FahrbahnRot()
{ // Rotphase 2 Sekunden für Auto und Fussgänger gleichzeitig
  if(Ampel.Timeout(2000)) Ampel.Set(FussgaengerGruenInit, FussgaengerGruen);
}

State FussgaengerGruenInit()
{
  Serial.println("Fussgaenger gruen");
  setAmpel(false, false, true, true, false, false);
}

State FussgaengerGruen()
{ // Grünphase der Fussgängerampel: 10 Sekunden
  if(Ampel.Timeout(10000)) Ampel.Set(FussgaengerRotInit, FussgaengerRot);
}

State FussgaengerRotInit()
{
  Serial.println("Fussgaenger rot");
  setAmpel(false, false, true, false, true, false);
}

State FussgaengerRot()
{ // Räumzeit des Fussgängerstreifens bei rot: 8 Sekunden
  if(Ampel.Timeout(8000)) Ampel.Set(FahrbahnRotGelbInit, FahrbahnRotGelb);
}
State FahrbahnRotGelbInit()
{
  Serial.println("Fahrbahn rot gelb");
  setAmpel(false, true, true, false, true, false);
}
State FahrbahnRotGelb()
{ // Rotgelb 2 Sekunden für Auto
  if(Ampel.Timeout(2000)) Ampel.Set(FahrbahnGruenInit, FahrbahnGruen);
}


void setup()
{
  Serial.begin(9600);
  pinMode(fahrGruenPin, OUTPUT);
  pinMode(fahrGelbPin, OUTPUT);
  pinMode(fahrRotPin, OUTPUT);
  pinMode(fussGruenPin, OUTPUT);
  pinMode(fussRotPin, OUTPUT);
  pinMode(anforderungSignalPin, OUTPUT);
  pinMode(anforderungPin, buttonMode);
}//setup()

void loop()
{
  EXEC(Ampel); // Finite State Machine rennt endlos
}//loop()

So z.B.:

void blink(byte pin, unsigned long interval)
{
  static unsigned long previousMillis;

  if (millis() - previousMillis > interval)
  {
    previousMillis = millis();
    digitalWrite(pin, !digitalRead(pin));
  }
}

und wie füge ich dies nun ein?

Aktuell steuere ich die LED ja so an

void setAmpel(boolean fahrGruen, boolean fahrGelb, boolean fahrRot, boolean fussGruen, boolean fussRot, boolean anforderungSignal)


State FahrbahnAnforderungInit()
{
 Serial.println("Bettelampel-Anforderung registriert");
 setAmpel(true, false, false, false, true, true);
}

State FahrbahnAnforderung()
{ // 5 Sekunden nach der Bettelanforderung bekommt die Fahrbahn gelb
 if(Ampel.Timeout(5000)) Ampel.Set(FahrbahnGelbInit, FahrbahnGelb);
}

Die Funktion musst du ständig aufrufen solange du blinken willst.

aber wie füge ich das in den state ein?
Hat jemand eine Idee wie folgende Dinge noch löse?

// to do: Blinken von Anforderungssignal, aktuell leuchtet es nur
// Anforderungssignal muss auch noch in der A-GELB und A-Rot Phase leuchten bis F-Grün ist
// Anforderung soll auch funktionieren wenn Ampel bei A-Rot oder bei A-ROT/Gelb ist, aktuell reagiert die Bettelampel-Anforderung nur bei A-Grün

void setAmpel(boolean fahrGruen, boolean fahrGelb, boolean fahrRot, boolean fussGruen, boolean fussRot, boolean anforderungSignal)


State FahrbahnAnforderungInit()
{
 Serial.println("Bettelampel-Anforderung registriert");
 setAmpel(true, false, false, false, true, true);

Hier void blink aufrufen? aber wie?

}

State FahrbahnAnforderung()
{ // 5 Sekunden nach der Bettelanforderung bekommt die Fahrbahn gelb
 if(Ampel.Timeout(5000)) Ampel.Set(FahrbahnGelbInit, FahrbahnGelb);
}
// to do: Blinken von Anforderungssignal, aktuell leuchtet es nur
// Anforderungssignal muss auch noch in der GELB und Rot Phase leuchten bis F Grün ist
// Anforderung soll auch funktionieren wenn Ampel bei Rot oder Ampel bei ROT/Gelb

#include <SM.h>

SM Ampel(FahrbahnGruenInit, FahrbahnGruen); //Anfangsstatus setzen

byte fahrGruenPin=11;
byte fahrGelbPin=12;
byte fahrRotPin=13;
byte fussGruenPin=10;
byte fussRotPin=9;
byte anforderungSignalPin=8;
byte anforderungPin=2;

#define buttonMode INPUT_PULLUP // INPUT_PULLUP oder INPUT

void setAmpel(boolean fahrGruen, boolean fahrGelb, boolean fahrRot, boolean fussGruen, boolean fussRot, boolean anforderungSignal)
{ // diese Funktion setzt den Zustand aller Ampel-LEDs 
  digitalWrite(fahrGruenPin, fahrGruen);
  if (fahrGruen) Serial.print("A-Gruen\t");
  digitalWrite(fahrGelbPin, fahrGelb);
  if (fahrGelb) Serial.print("A-Gelb\t");
  digitalWrite(fahrRotPin, fahrRot);
  if (fahrRot) Serial.print("A-Rot\t");
  digitalWrite(fussGruenPin, fussGruen);
  if (fussGruen) Serial.print("F-Gruen\t");
  digitalWrite(fussRotPin, fussRot);
  if (fussRot) Serial.print("F-Rot\t");
  digitalWrite(anforderungSignalPin, anforderungSignal);
  if (anforderungSignal) Serial.print("anforderungSignal\t");
  Serial.println();
}

State FahrbahnGruenInit()
{
  Serial.println("Fahrbahn gruen");
  setAmpel(true, false, false, false, true, false);
}

State FahrbahnGruen()
{ // Fahrbahn Grünzeit: Bis zur Bettelanforderung
  byte anforderung=digitalRead(anforderungPin);
  if (buttonMode==INPUT_PULLUP) anforderung=!anforderung;
  if (anforderung) Ampel.Set(FahrbahnAnforderungInit,FahrbahnAnforderung);
  if (Ampel.Timeout(10000)) Ampel.Set(FahrbahnGelbInit, FahrbahnGelb);
}

State FahrbahnAnforderungInit()
{
  Serial.println("Bettelampel-Anforderung registriert");
  setAmpel(true, false, false, false, true, true);
}

State FahrbahnAnforderung()
{ // 5 Sekunden nach der Bettelanforderung bekommt die Fahrbahn gelb
  if(Ampel.Timeout(5000)) Ampel.Set(FahrbahnGelbInit, FahrbahnGelb);
}

State FahrbahnGelbInit()
{
  Serial.println("Fahrbahn gelb");
  setAmpel(false, true, false, false, true, false);
}

State FahrbahnGelb()
{ // 2 Sekunden Gelbphase
  if(Ampel.Timeout(2000)) Ampel.Set(FahrbahnRotInit, FahrbahnRot);
}

State FahrbahnRotInit()
{
  Serial.println("Fahrbahn rot");
  setAmpel(false, false, true, false, true, false);
}

State FahrbahnRot()
{ // Rotphase 2 Sekunden für Auto und Fussgänger gleichzeitig
  if(Ampel.Timeout(2000)) Ampel.Set(FussgaengerGruenInit, FussgaengerGruen);
}

State FussgaengerGruenInit()
{
  Serial.println("Fussgaenger gruen");
  setAmpel(false, false, true, true, false, false);
}

State FussgaengerGruen()
{ // Grünphase der Fussgängerampel: 10 Sekunden
  if(Ampel.Timeout(10000)) Ampel.Set(FussgaengerRotInit, FussgaengerRot);
}

State FussgaengerRotInit()
{
  Serial.println("Fussgaenger rot");
  setAmpel(false, false, true, false, true, false);
}

State FussgaengerRot()
{ // Räumzeit des Fussgängerstreifens bei rot: 8 Sekunden
  if(Ampel.Timeout(8000)) Ampel.Set(FahrbahnRotGelbInit, FahrbahnRotGelb);
}
State FahrbahnRotGelbInit()
{
  Serial.println("Fahrbahn rot gelb");
  setAmpel(false, true, true, false, true, false);
}
State FahrbahnRotGelb()
{ // Rotgelb 2 Sekunden für Auto
  if(Ampel.Timeout(2000)) Ampel.Set(FahrbahnGruenInit, FahrbahnGruen);
}


void setup()
{
  Serial.begin(9600);
  pinMode(fahrGruenPin, OUTPUT);
  pinMode(fahrGelbPin, OUTPUT);
  pinMode(fahrRotPin, OUTPUT);
  pinMode(fussGruenPin, OUTPUT);
  pinMode(fussRotPin, OUTPUT);
  pinMode(anforderungSignalPin, OUTPUT);
  pinMode(anforderungPin, buttonMode);
}//setup()

void loop()
{
  EXEC(Ampel); // Finite State Machine rennt endlos
}//loop()

schlier: und wie füge ich dies nun ein?

Aktuell steuere ich die LED ja so an

Das Blinken steuerst Du natürlich in der Funktion an, die ständig aufgerufen wird, wenn dieser State gesetzt ist, also in der Funktion "FahrbahnAnforderung()".

Dazu stellt Dir die SM-Library eine Funktion "Statetime()" bereit, mit der Du jederzeit abfragen kannst, wie lange dieser State bereits gesetzt ist, und darüber mußt Du entscheiden, ob der Blinker ein oder aus ist und ihn entsprechend steuern.

So geht's (nur ein Beispiel, kann man natürlich auch anders machen):

boolean blinkOn= !((Ampel.Statetime()/500)%2);

Dabei ist: "Ampel.Statetime()" die Zeit in Millisekunden, wie lange der State bereits läuft "(Ampel.Statetime()/500)" ist ein Zähler, der alle 500ms um eins hochzählt "(Ampel.Statetime()/500)%2" ist der Modulo-Divisionsrest dieses Zählers beim Dividieren durch 2 D.h. dieser Wert schwankt immer jede halbe Sekunde zwischen 0 (false) und 1 (true). Der Anfangswert wäre 0. Für einen anfangs eingeschalteten Blinkstate das Ergebnis mit '!' negieren, dann startet das Blinken mit ein:

State FahrbahnAnforderung()
{
  // Blinkstatus berechnen 
  boolean blinkOn= !((Ampel.Statetime()/500)%2);
  // Blinkstatus setzen
  setAmpel(true, false, false, false, true, blinkOn);
  // 10 Sekunden nach der Bettelanforderung bekommt die Fahrbahn gelb
  if(Ampel.Timeout(10000)) Ampel.Set(FahrbahnGelbInit, FahrbahnGelb);
}

(ungetestet)

Immer dran denken: Diese Funktion wird pro Sekunde viele tausend mal aufgerufen, solange dieser Status gesetzt ist. Und durch eine Bedingung, in diesem Fall nach Ablauf der Timeout-Zeit, wird ein anderer Zustand gesetzt, wonach dann andere Funktionen aufgerufen werden.

P.S.: Wenn es in anderen Zuständen auch blinken soll, müssen ähnliche Blinkfunktionsaufrufe auch in anderen Zuständen eingebaut werden.

Habe es eingefügt und es funktioniert auch,

nur wird serielle Schnittstelle hierdurch vollgemüllt

setAmpel(true, false, false, false, true, blinkOn);

Bettelampel-Anforderung registriert
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   Anforderung Signal  
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot   
A-Gruen F-Rot

Die seriellen Ausgaben kannst du komplett entfernen. Wenn deine LEDs gehen brauchst du die gar nicht.

könnte ich

boolean blinkOn= !((Ampel.Statetime()/500)%2);

nicht auch schon zentral definieren und dann in jedem state aufrufen?