/*
Forum: https://forum.arduino.cc/t/kann-mir-jemand-sagen-warum-der-button-nicht-funktioniert/1446985/5
Wokwi: https://wokwi.com/projects/465920814099614721
ec2021
Ampel-Statemachine mit Fussgänger-Taste, die unabhängig von den Phasen abgefragt wird
beim Übergang von der Grün-Phase in die Gelb-Phase werden aller vorherigen
Tasteneingaben verworfen
Diese Version zeigt die Dauer der letzten Phase an.
Sie wurde um eine weitere Phase erweitert, die Fussgängern
erlaubt, nachdem sie Rot erhalten haben, den Übergang
zu verlassen (quasi der Ersatz für die fehlende Gelb-Phase für
Fussgänger)
Serielle Textausgabe und Led für Fahrzeuge und Fussgänger
*/
class SignalAnlage {
private:
byte rot;
byte gelb;
byte gruen;
byte fussRot;
byte fussGruen;
void RotGelbGruen(byte r, byte y, byte g) {
digitalWrite(rot, r);
digitalWrite(gelb, y);
digitalWrite(gruen, g);
}
public:
// Pinreihenfolge: Rot, Gelb, Gruen, Fussg_Rot, Fussg_Gruen
SignalAnlage(byte r, byte g, byte gr, byte fR, byte fG)
: rot(r), gelb(g), gruen(gr), fussRot(fR), fussGruen(fG) {};
void init() {
pinMode(rot, OUTPUT);
pinMode(gelb, OUTPUT);
pinMode(gruen, OUTPUT);
pinMode(fussRot, OUTPUT);
pinMode(fussGruen, OUTPUT);
}
// Rot, Gelb, Gruen
void Rot() {
RotGelbGruen(HIGH, LOW, LOW);
}
void RotGelb() {
RotGelbGruen(HIGH, HIGH, LOW);
}
void Gruen() {
RotGelbGruen(LOW, LOW, HIGH);
}
void Gelb() {
RotGelbGruen(LOW, HIGH, LOW);
}
void FussgaengerRot() {
digitalWrite(fussGruen, LOW);
digitalWrite(fussRot, HIGH);
}
void FussgaengerGruen() {
digitalWrite(fussGruen, HIGH);
digitalWrite(fussRot, LOW);
}
};
SignalAnlage ampel(5, 6, 7, 3, 4);
enum class Phase {ROT, RAEUMEN, ROT_GELB, GRUEN, GELB, UNBEKANNT};
constexpr unsigned long GruenStandard {10000};
constexpr unsigned long GruenVerkuerzt { 3000};
constexpr unsigned long GelbDauer { 3000};
constexpr unsigned long RotDauer { 5000};
constexpr unsigned long RaeumDauer { 3000};
constexpr unsigned long RotGelbDauer { 3000};
constexpr byte tasterPin {2};
Phase AmpelPhase = Phase::UNBEKANNT;
unsigned long phasenStart = 0;
boolean tasteGedrueckt = false;
void setup() {
Serial.begin(115200);
pinMode(tasterPin, INPUT_PULLUP);
ampel.init();
delay(100);
// StartBedingungen setzen:
phasenWechsel(Phase::ROT, "Rot");
ampel.Rot();
ampel.FussgaengerGruen();
}
void loop() {
TasterAbfrage();
AmpelMaschine();
}
void AmpelMaschine() {
switch (AmpelPhase) {
case Phase::ROT:
if (zeitAbgelaufen(RotDauer)) {
ampel.FussgaengerRot();
phasenWechsel(Phase::RAEUMEN, "Räumen");
}
break;
case Phase::RAEUMEN:
if (zeitAbgelaufen(RaeumDauer)) {
ampel.RotGelb();
phasenWechsel(Phase::ROT_GELB, "RotGelb");
}
break;
case Phase::ROT_GELB:
if (zeitAbgelaufen(RotGelbDauer)) {
ampel.Gruen();
phasenWechsel(Phase::GRUEN, "Grün");
}
break;
case Phase::GRUEN:
if (zeitAbgelaufen((tasteGedrueckt) ? GruenVerkuerzt : GruenStandard)) {
// Hier wird der Tasten-Status zurückgesetzt, unabhängig davon, ob die
// nun folgende Phase aus Zeit- oder aus Tastengründen eingeleitet wurde.
// Damit verfallen hier alle vor und während der Grünphase getätigten
// Tasteneingaben
tasteGedrueckt = false;
ampel.Gelb();
phasenWechsel(Phase::GELB, "Gelb");
}
break;
case Phase::GELB:
if (zeitAbgelaufen(GelbDauer)) {
ampel.Rot();
ampel.FussgaengerGruen();
phasenWechsel(Phase::ROT, "Rot");
}
break;
}
}
void TasterAbfrage() {
if (digitalRead(tasterPin) == LOW) {
tasteGedrueckt = true;
delay(30); // Einfaches "Debouncen", 30 ms sind hier zu verkraften ;-)
}
}
void phasenWechsel(Phase naechstePhase, char * txt) {
if (AmpelPhase != Phase::UNBEKANNT) {
if (AmpelPhase == Phase::ROT_GELB) {
Serial.print(": ");
} else {
Serial.print(":\t ");
};
Serial.print((millis() - phasenStart) / 1000);
Serial.println(" s");
}
AmpelPhase = naechstePhase;
Serial.print(txt);
phasenStart = millis();
}
boolean zeitAbgelaufen(unsigned long intervall) {
return (millis() - phasenStart > intervall);
}