First OOP draft, Added readme
This commit is contained in:
parent
c4861d9793
commit
43497376cb
202
Seilbahn/README.md
Normal file
202
Seilbahn/README.md
Normal file
@ -0,0 +1,202 @@
|
||||
# Doppelmayr Modell-Seilbahn
|
||||
|
||||
Arduino-basierte Steuerung einer Doppelmayr Modell-Seilbahn. Die Steuerung bildet das Bedienpanel einer echten Anlage nach — mit Taster-LED-Kombinationen, Betriebsmodi und einer vollständigen Fahrtrichtungssteuerung.
|
||||
|
||||
## Hardware
|
||||
|
||||
**Mikrocontroller:** Arduino Mega 2560
|
||||
|
||||
**Bedienpanel:**
|
||||
|
||||
| Taster / LED | Funktion |
|
||||
|----------------------------|-------------------------------------------------------|
|
||||
| Anlage Ein/Aus | Anlage ein- und ausschalten |
|
||||
| Station Besetzt/Unbesetzt | Stationsstatus anzeigen |
|
||||
| Servicebetrieb | In den Servicemodus wechseln |
|
||||
| Fahrgastbetrieb | In den Fahrgastmodus wechseln |
|
||||
| Quittieren | Zustandswechsel bestätigen |
|
||||
| Start | Fahrt starten |
|
||||
| Halt | Anlage anhalten |
|
||||
| Nothalt | Anlage sofort stoppen |
|
||||
| Vorwärts | Fahrtrichtung Vorwärts wählen |
|
||||
| Rückwärts | Fahrtrichtung Rückwärts wählen |
|
||||
|
||||
**Ereignisanzeige (3-farbig, ohne Taster):**
|
||||
|
||||
| LED | Bedeutung |
|
||||
|-------|----------------------------------|
|
||||
| Rot | Servicebetrieb aktiv |
|
||||
| Gelb | Zustandswechsel wartet auf Quittierung |
|
||||
| Grün | Fahrgastbetrieb aktiv |
|
||||
|
||||
## Pinbelegung
|
||||
|
||||
| Signal | Pin |
|
||||
|-----------------------------|-----|
|
||||
| LED Anlage Ein/Aus | 2 |
|
||||
| Taster Anlage Ein/Aus | 3 |
|
||||
| LED Station | 4 |
|
||||
| Taster Station | 5 |
|
||||
| LED Servicebetrieb | 6 |
|
||||
| Taster Servicebetrieb | 7 |
|
||||
| LED Quittieren | 9 |
|
||||
| Taster Quittieren | 10 |
|
||||
| LED Grün Ereignisanzeige | 11 |
|
||||
| LED Gelb Ereignisanzeige | 12 |
|
||||
| LED Rot Ereignisanzeige | 13 |
|
||||
| LED Fahrgastbetrieb | 22 |
|
||||
| Taster Fahrgastbetrieb | 23 |
|
||||
| LED Vorwärts | 30 |
|
||||
| Taster Vorwärts | 31 |
|
||||
| LED Rückwärts | 32 |
|
||||
| Taster Rückwärts | 33 |
|
||||
| LED Start | 36 |
|
||||
| Taster Start | 37 |
|
||||
| LED Halt | 38 |
|
||||
| Taster Halt | 39 |
|
||||
| LED Nothalt | 40 |
|
||||
| Taster Nothalt | 41 |
|
||||
|
||||
## Software
|
||||
|
||||
### Architektur
|
||||
|
||||
```
|
||||
main.cpp
|
||||
└── CMainController
|
||||
├── CEventQueue (zentrale Event-Queue)
|
||||
├── CButton × 10 (je ein Objekt pro Taster/LED-Paar)
|
||||
└── Zustandsmaschinen (AnlagenZustand + FahrtRichtung)
|
||||
```
|
||||
|
||||
Die Steuerung basiert auf einer **Event-Queue**: Jeder `CButton` erkennt Tastendrücke per Flankenauswertung mit Entprellung und schreibt einen `SEvent` in die zentrale Queue. Der `CMainController` verarbeitet diese Events jeden Loop-Durchlauf und aktualisiert die Zustände sowie alle LEDs.
|
||||
|
||||
**Loop-Ablauf in `CMainController::work()`:**
|
||||
1. `pollButtons()` — alle relevanten Buttons abfragen, Events in Queue schreiben
|
||||
2. `processEvents()` — Events aus Queue lesen, Zustand ändern
|
||||
3. `updateLEDs()` — alle LEDs anhand des aktuellen Zustands setzen
|
||||
|
||||
### LED-Modi
|
||||
|
||||
LEDs können drei Zustände haben, die in `CButton` verwaltet werden:
|
||||
|
||||
| Modus | Verhalten |
|
||||
|----------------|------------------------------------|
|
||||
| `LEDMode::OFF` | Aus |
|
||||
| `LEDMode::ON` | Dauerhaft an |
|
||||
| `LEDMode::BLINK` | Blinkt (500 ms Intervall) |
|
||||
|
||||
Alle LEDs im `BLINK`-Modus blinken synchron, da der Blink-Timer als `static` Member in `CButton` für alle Instanzen geteilt wird.
|
||||
|
||||
### Zustandsmaschinen
|
||||
|
||||
#### AnlagenZustand
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> AUS
|
||||
|
||||
AUS --> SERVICE : BTN_ANLAGE_EIN_AUS
|
||||
|
||||
SERVICE --> AUS : BTN_ANLAGE_EIN_AUS
|
||||
SERVICE --> FAHRGAST_QUITTIEREN : BTN_FAHRGAST
|
||||
|
||||
FAHRGAST_QUITTIEREN --> AUS : BTN_ANLAGE_EIN_AUS
|
||||
FAHRGAST_QUITTIEREN --> FAHRGAST : BTN_QUIT
|
||||
|
||||
FAHRGAST --> AUS : BTN_ANLAGE_EIN_AUS
|
||||
FAHRGAST --> SERVICE_QUITTIEREN : BTN_SERVICE
|
||||
|
||||
SERVICE_QUITTIEREN --> AUS : BTN_ANLAGE_EIN_AUS
|
||||
SERVICE_QUITTIEREN --> SERVICE : BTN_QUIT
|
||||
```
|
||||
|
||||
#### FahrtRichtung
|
||||
|
||||
Aktiv wenn `AnlagenZustand == SERVICE` oder `AnlagenZustand == FAHRGAST`.
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> HALT
|
||||
|
||||
HALT --> VORWAERTS_QUITTIEREN : BTN_VORWAERTS
|
||||
HALT --> RUECKWAERTS_QUITTIEREN : BTN_RUECKWAERTS
|
||||
HALT --> WARTE_START_VORWAERTS : BTN_QUIT\n[vorherigeRichtung != RUECKWAERTS]
|
||||
HALT --> WARTE_START_RUECKWAERTS : BTN_QUIT\n[vorherigeRichtung == RUECKWAERTS]
|
||||
|
||||
NOTHALT --> VORWAERTS_QUITTIEREN : BTN_VORWAERTS
|
||||
NOTHALT --> RUECKWAERTS_QUITTIEREN : BTN_RUECKWAERTS
|
||||
NOTHALT --> WARTE_START_VORWAERTS : BTN_QUIT\n[vorherigeRichtung != RUECKWAERTS]
|
||||
NOTHALT --> WARTE_START_RUECKWAERTS : BTN_QUIT\n[vorherigeRichtung == RUECKWAERTS]
|
||||
|
||||
VORWAERTS_QUITTIEREN --> WARTE_START_VORWAERTS : BTN_QUIT
|
||||
VORWAERTS_QUITTIEREN --> RUECKWAERTS_QUITTIEREN : BTN_RUECKWAERTS
|
||||
VORWAERTS_QUITTIEREN --> HALT : BTN_HALT
|
||||
VORWAERTS_QUITTIEREN --> NOTHALT : BTN_NOTHALT
|
||||
|
||||
WARTE_START_VORWAERTS --> VORWAERTS : BTN_START
|
||||
|
||||
VORWAERTS --> HALT : BTN_HALT
|
||||
VORWAERTS --> NOTHALT : BTN_NOTHALT
|
||||
|
||||
RUECKWAERTS_QUITTIEREN --> WARTE_START_RUECKWAERTS : BTN_QUIT
|
||||
RUECKWAERTS_QUITTIEREN --> VORWAERTS_QUITTIEREN : BTN_VORWAERTS
|
||||
RUECKWAERTS_QUITTIEREN --> HALT : BTN_HALT
|
||||
RUECKWAERTS_QUITTIEREN --> NOTHALT : BTN_NOTHALT
|
||||
|
||||
WARTE_START_RUECKWAERTS --> RUECKWAERTS : BTN_START
|
||||
|
||||
RUECKWAERTS --> HALT : BTN_HALT
|
||||
RUECKWAERTS --> NOTHALT : BTN_NOTHALT
|
||||
```
|
||||
|
||||
## PlatformIO
|
||||
|
||||
Das Projekt verwendet [PlatformIO](https://platformio.org) als Build-System — eine Alternative zur Arduino IDE mit deutlich besserer Projekt- und Bibliotheksverwaltung.
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
- [VS Code](https://code.visualstudio.com/) mit der [PlatformIO-Extension](https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide)
|
||||
- oder PlatformIO Core (CLI) via `pip install platformio`
|
||||
|
||||
### Projekt bauen und flashen
|
||||
|
||||
```bash
|
||||
# Projekt kompilieren
|
||||
pio run
|
||||
|
||||
# Auf den Arduino flashen (USB)
|
||||
pio run --target upload
|
||||
|
||||
# Seriellen Monitor öffnen (9600 Baud)
|
||||
pio device monitor
|
||||
```
|
||||
|
||||
### Konfiguration (`platformio.ini`)
|
||||
|
||||
```ini
|
||||
[env:megaatmega2560]
|
||||
platform = atmelavr
|
||||
board = megaatmega2560
|
||||
framework = arduino
|
||||
lib_deps = mike-matera/ArduinoSTL@^1.3.3
|
||||
```
|
||||
|
||||
- **board:** Arduino Mega 2560
|
||||
- **lib_deps:** ArduinoSTL — stellt `std::vector` für die EventQueue bereit, da die Arduino-Standardbibliothek keine STL enthält
|
||||
|
||||
### Projektstruktur
|
||||
|
||||
```
|
||||
Seilbahn/
|
||||
├── platformio.ini # Board- und Bibliothekskonfiguration
|
||||
├── src/
|
||||
│ ├── main.cpp # setup() und loop()
|
||||
│ ├── CMainController # Hauptsteuerung, besitzt alle Objekte
|
||||
│ ├── CButton # Taster-LED-Abstraktion mit Entprellung
|
||||
│ ├── CEventQueue # FIFO-Queue für Button-Events
|
||||
│ └── SEvent # Event-Typ und -Struktur
|
||||
├── include/ # Globale Header (leer)
|
||||
├── lib/ # Projektlokale Bibliotheken (leer)
|
||||
└── test/ # Unit-Tests (PlatformIO-Testframework)
|
||||
```
|
||||
@ -12,3 +12,4 @@
|
||||
platform = atmelavr
|
||||
board = megaatmega2560
|
||||
framework = arduino
|
||||
lib_deps = mike-matera/ArduinoSTL@^1.3.3
|
||||
|
||||
@ -1,47 +1,83 @@
|
||||
#include "CButton.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
CButton::CButton(short btnPin, short ledPin)
|
||||
// Einmalige Definition der static-Member (Speicher wird hier reserviert)
|
||||
unsigned long CButton::s_lastBlinkTime = 0;
|
||||
bool CButton::s_blinkState = false;
|
||||
|
||||
CButton::CButton(short btnPin, short ledPin, EVENT_TYPE eventType, CEventQueue* queue)
|
||||
: m_btnPin(btnPin)
|
||||
, m_ledPin(ledPin)
|
||||
, m_eventType(eventType)
|
||||
, m_queue(queue)
|
||||
, m_currentButtonState(false)
|
||||
, m_buttonState(false)
|
||||
, m_ledMode(LEDMode::OFF)
|
||||
{
|
||||
m_btnPin = btnPin;
|
||||
m_ledPin = ledPin;
|
||||
m_currentButtonState = false;
|
||||
m_buttonState = false;
|
||||
}
|
||||
|
||||
bool CButton::getLED()
|
||||
void CButton::setup()
|
||||
{
|
||||
return digitalRead(m_ledPin);
|
||||
pinMode(m_btnPin, INPUT_PULLUP);
|
||||
pinMode(m_ledPin, OUTPUT);
|
||||
}
|
||||
|
||||
void CButton::setLED(bool status)
|
||||
void CButton::setLEDMode(LEDMode mode)
|
||||
{
|
||||
digitalWrite(m_ledPin, status);
|
||||
m_ledMode = mode;
|
||||
}
|
||||
|
||||
LEDMode CButton::getLEDMode()
|
||||
{
|
||||
return m_ledMode;
|
||||
}
|
||||
|
||||
void CButton::work()
|
||||
{
|
||||
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||
// ===== LED aktualisieren =====
|
||||
switch (m_ledMode)
|
||||
{
|
||||
case LEDMode::ON:
|
||||
digitalWrite(m_ledPin, HIGH);
|
||||
break;
|
||||
|
||||
case LEDMode::OFF:
|
||||
digitalWrite(m_ledPin, LOW);
|
||||
break;
|
||||
|
||||
case LEDMode::BLINK:
|
||||
// s_lastBlinkTime und s_blinkState sind static → werden von allen
|
||||
// Instanzen geteilt. Der erste Button der in diesem Loop work() aufruft
|
||||
// aktualisiert den Timer — alle anderen lesen denselben Zustand.
|
||||
// So blinken alle LEDs im BLINK-Modus exakt synchron.
|
||||
if (millis() - s_lastBlinkTime >= BLINK_INTERVAL_MS)
|
||||
{
|
||||
s_lastBlinkTime = millis();
|
||||
s_blinkState = !s_blinkState;
|
||||
}
|
||||
digitalWrite(m_ledPin, s_blinkState ? HIGH : LOW);
|
||||
break;
|
||||
}
|
||||
|
||||
// ===== Button abfragen =====
|
||||
m_currentButtonState = digitalRead(m_btnPin) == LOW;
|
||||
// Aktuellen Zustand mit vorherigem vergleichen
|
||||
|
||||
// Flankenauswertung: nur bei steigender Flanke reagieren (nicht gedrückt → gedrückt)
|
||||
if (m_currentButtonState && !m_buttonState)
|
||||
{
|
||||
// Warten zum entprellen
|
||||
// Entprellen
|
||||
delay(20);
|
||||
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||
m_currentButtonState = digitalRead(m_btnPin) == LOW;
|
||||
// Prüfen ob immernoch gedrückt
|
||||
if (m_currentButtonState == LOW)
|
||||
|
||||
if (m_currentButtonState)
|
||||
{
|
||||
// Knopf gedrückt => Code ausführen
|
||||
SEvent event;
|
||||
event.m_eventType = m_eventType;
|
||||
event.m_additionalInfo = 0;
|
||||
m_queue->pushEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
fahrtrichtung = HALT;
|
||||
// ============================================================
|
||||
|
||||
// Speichern des ButtonStates als Vergleichswert für den nächsten Durchlauf
|
||||
// Immer aktualisieren — so wird der Button nach dem Loslassen wieder erkannt
|
||||
m_buttonState = m_currentButtonState;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,24 +1,36 @@
|
||||
#ifndef CBUTTON_H_
|
||||
#define CBUTTON_H_
|
||||
|
||||
#include "SEvent.h"
|
||||
#include "CEventQueue.h"
|
||||
|
||||
enum class LEDMode { OFF, ON, BLINK };
|
||||
|
||||
class CButton
|
||||
{
|
||||
public:
|
||||
CButton(short btnPin, short ledPin);
|
||||
void connect(); // Button mit Controller "verbinden"
|
||||
void work(); // Button periodisch abfragen
|
||||
|
||||
bool getLED(); // LED status abfragen
|
||||
void setLED(bool status); // LED an/ausschalten
|
||||
CButton(short btnPin, short ledPin, EVENT_TYPE eventType, CEventQueue* queue);
|
||||
void setup(); // pinMode setzen (im setup() aufrufen)
|
||||
void work(); // Button abfragen + LED-Zustand aktualisieren
|
||||
|
||||
void setLEDMode(LEDMode mode);
|
||||
LEDMode getLEDMode();
|
||||
|
||||
private:
|
||||
short m_btnPin; // Pinnummer Button am Arduino
|
||||
short m_ledPin; // Pinnummer LED am Arduino
|
||||
short m_btnPin;
|
||||
short m_ledPin;
|
||||
EVENT_TYPE m_eventType;
|
||||
CEventQueue* m_queue;
|
||||
|
||||
bool m_currentButtonState; // Hilfsvariable für aktuellen Status
|
||||
bool m_buttonState; // Hilfsvariable für letzten Status
|
||||
bool m_currentButtonState;
|
||||
bool m_buttonState;
|
||||
|
||||
}
|
||||
LEDMode m_ledMode;
|
||||
|
||||
// static: einmal für alle CButton-Instanzen — sorgt für synchrones Blinken
|
||||
static unsigned long s_lastBlinkTime;
|
||||
static bool s_blinkState;
|
||||
static const int BLINK_INTERVAL_MS = 500;
|
||||
};
|
||||
|
||||
#endif /* CBUTTON_H_ */
|
||||
@ -0,0 +1,363 @@
|
||||
#include "CMainController.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
// Initialisierungsliste: m_queue wird zuerst gebaut (steht zuerst im Header),
|
||||
// danach die Buttons — jeder bekommt &m_queue, was zu diesem Zeitpunkt bereits
|
||||
// gültig ist.
|
||||
CMainController::CMainController()
|
||||
: m_queue()
|
||||
, m_btnAnlageEinAus (PIN_KNOPF_ANLAGE_EIN_AUS, PIN_LED_ANLAGE_EIN_AUS, BTN_ANLAGE_EIN_AUS, &m_queue)
|
||||
, m_btnStation (PIN_KNOPF_STATION, PIN_LED_STATION, BTN_STATION, &m_queue)
|
||||
, m_btnServicebetrieb(PIN_KNOPF_SERVICEBETRIEB, PIN_LED_SERVICEBETRIEB, BTN_SERVICE, &m_queue)
|
||||
, m_btnFahrgastbetrieb(PIN_KNOPF_FAHRGASTBETRIEB, PIN_LED_FAHRGASTBETRIEB, BTN_FAHRGAST, &m_queue)
|
||||
, m_btnQuitBetrieb (PIN_KNOPF_QUIT_BETRIEB, PIN_LED_QUIT_BETRIEB, BTN_QUIT, &m_queue)
|
||||
, m_btnStart (PIN_KNOPF_START_BETRIEB, PIN_LED_START_BETRIEB, BTN_START, &m_queue)
|
||||
, m_btnHalt (PIN_KNOPF_HALT, PIN_LED_HALT, BTN_HALT, &m_queue)
|
||||
, m_btnNothalt (PIN_KNOPF_NOTHALT, PIN_LED_NOTHALT, BTN_NOTHALT, &m_queue)
|
||||
, m_btnVorwaerts (PIN_KNOPF_VORWAERTS, PIN_LED_VORWAERTS, BTN_VORWAERTS, &m_queue)
|
||||
, m_btnRueckwaerts (PIN_KNOPF_RUECKWAERTS, PIN_LED_RUECKWAERTS, BTN_RUECKWAERTS, &m_queue)
|
||||
, m_anlagenzustand(AnlagenZustand::AUS)
|
||||
, m_fahrtrichtung(FahrtRichtung::HALT)
|
||||
, m_vorherigeRichtung(FahrtRichtung::HALT)
|
||||
{
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// setup(): einmalig beim Start aufrufen
|
||||
// ============================================================
|
||||
void CMainController::setup()
|
||||
{
|
||||
// Jeden Button mit setup() initialisieren (setzt pinMode für Taster + LED)
|
||||
m_btnAnlageEinAus.setup();
|
||||
m_btnStation.setup();
|
||||
m_btnServicebetrieb.setup();
|
||||
m_btnFahrgastbetrieb.setup();
|
||||
m_btnQuitBetrieb.setup();
|
||||
m_btnStart.setup();
|
||||
m_btnHalt.setup();
|
||||
m_btnNothalt.setup();
|
||||
m_btnVorwaerts.setup();
|
||||
m_btnRueckwaerts.setup();
|
||||
|
||||
// Die drei Ereignis-LEDs haben keinen Button → direkt hier initialisieren
|
||||
pinMode(PIN_LED_ROT_EREIGNISANZEIGE, OUTPUT);
|
||||
pinMode(PIN_LED_GELB_EREIGNISANZEIGE, OUTPUT);
|
||||
pinMode(PIN_LED_GRUEN_EREIGNISANZEIGE, OUTPUT);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// work(): jeden Loop-Durchlauf aufrufen
|
||||
// ============================================================
|
||||
void CMainController::work()
|
||||
{
|
||||
pollButtons(); // 1. Buttons abfragen → Events landen in der Queue
|
||||
processEvents(); // 2. Events verarbeiten → Zustand ändern
|
||||
updateLEDs(); // 3. LEDs anhand des neuen Zustands setzen
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// pollButtons(): work() aller Buttons aufrufen
|
||||
// ============================================================
|
||||
void CMainController::pollButtons()
|
||||
{
|
||||
// Welche Buttons abgefragt werden, hängt vom aktuellen Anlagenzustand ab.
|
||||
// So können z.B. im AUS-Zustand nur relevante Buttons Events erzeugen.
|
||||
switch (m_anlagenzustand)
|
||||
{
|
||||
case AnlagenZustand::AUS:
|
||||
m_btnAnlageEinAus.work();
|
||||
break;
|
||||
|
||||
case AnlagenZustand::SERVICE_QUITTIEREN:
|
||||
case AnlagenZustand::FAHRGAST_QUITTIEREN:
|
||||
m_btnAnlageEinAus.work();
|
||||
m_btnQuitBetrieb.work();
|
||||
break;
|
||||
|
||||
case AnlagenZustand::SERVICE:
|
||||
m_btnAnlageEinAus.work();
|
||||
m_btnFahrgastbetrieb.work();
|
||||
m_btnQuitBetrieb.work();
|
||||
m_btnStart.work();
|
||||
m_btnHalt.work();
|
||||
m_btnNothalt.work();
|
||||
m_btnVorwaerts.work();
|
||||
m_btnRueckwaerts.work();
|
||||
break;
|
||||
|
||||
case AnlagenZustand::FAHRGAST:
|
||||
m_btnAnlageEinAus.work();
|
||||
m_btnServicebetrieb.work();
|
||||
m_btnQuitBetrieb.work();
|
||||
m_btnStart.work();
|
||||
m_btnHalt.work();
|
||||
m_btnNothalt.work();
|
||||
m_btnVorwaerts.work();
|
||||
m_btnRueckwaerts.work();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// processEvents(): alle Events in der Queue verarbeiten
|
||||
// ============================================================
|
||||
void CMainController::processEvents()
|
||||
{
|
||||
bool valid;
|
||||
SEvent ev = m_queue.popEvent(&valid);
|
||||
|
||||
while (valid)
|
||||
{
|
||||
switch (m_anlagenzustand)
|
||||
{
|
||||
// ==================== AUS ====================
|
||||
case AnlagenZustand::AUS:
|
||||
if (ev.m_eventType == BTN_ANLAGE_EIN_AUS)
|
||||
m_anlagenzustand = AnlagenZustand::SERVICE;
|
||||
break;
|
||||
|
||||
// ==================== SERVICE_QUITTIEREN ====================
|
||||
// Zustandswechsel nach SERVICE oder FAHRGAST wurde ausgelöst,
|
||||
// Nutzer muss erst quittieren bevor es weitergeht.
|
||||
case AnlagenZustand::SERVICE_QUITTIEREN:
|
||||
if (ev.m_eventType == BTN_ANLAGE_EIN_AUS)
|
||||
m_anlagenzustand = AnlagenZustand::AUS;
|
||||
else if (ev.m_eventType == BTN_QUIT)
|
||||
m_anlagenzustand = AnlagenZustand::SERVICE;
|
||||
break;
|
||||
|
||||
// ==================== SERVICE ====================
|
||||
case AnlagenZustand::SERVICE:
|
||||
if (ev.m_eventType == BTN_ANLAGE_EIN_AUS)
|
||||
m_anlagenzustand = AnlagenZustand::AUS;
|
||||
else if (ev.m_eventType == BTN_FAHRGAST)
|
||||
m_anlagenzustand = AnlagenZustand::FAHRGAST_QUITTIEREN;
|
||||
else
|
||||
processFahrtrichtungEvent(ev); // Fahrtrichtungs-Events weiterleiten
|
||||
break;
|
||||
|
||||
// ==================== FAHRGAST_QUITTIEREN ====================
|
||||
case AnlagenZustand::FAHRGAST_QUITTIEREN:
|
||||
if (ev.m_eventType == BTN_ANLAGE_EIN_AUS)
|
||||
m_anlagenzustand = AnlagenZustand::AUS;
|
||||
else if (ev.m_eventType == BTN_QUIT)
|
||||
m_anlagenzustand = AnlagenZustand::FAHRGAST;
|
||||
break;
|
||||
|
||||
// ==================== FAHRGAST ====================
|
||||
case AnlagenZustand::FAHRGAST:
|
||||
if (ev.m_eventType == BTN_ANLAGE_EIN_AUS)
|
||||
m_anlagenzustand = AnlagenZustand::AUS;
|
||||
else if (ev.m_eventType == BTN_SERVICE)
|
||||
m_anlagenzustand = AnlagenZustand::SERVICE_QUITTIEREN;
|
||||
else
|
||||
processFahrtrichtungEvent(ev);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ev = m_queue.popEvent(&valid); // nächstes Event holen
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// processFahrtrichtungEvent(): Fahrtrichtungs-Statemachine
|
||||
// Wird von processEvents() aufgerufen wenn der Anlagenzustand
|
||||
// SERVICE oder FAHRGAST ist und kein Anlagen-Event vorliegt.
|
||||
// ============================================================
|
||||
void CMainController::processFahrtrichtungEvent(SEvent ev)
|
||||
{
|
||||
switch (m_fahrtrichtung)
|
||||
{
|
||||
// ===== Anlage steht (normal oder Nothalt) =====
|
||||
case FahrtRichtung::HALT:
|
||||
case FahrtRichtung::NOTHALT:
|
||||
if (ev.m_eventType == BTN_QUIT)
|
||||
{
|
||||
// Richtung von vor dem Halt wiederherstellen
|
||||
if (m_vorherigeRichtung == FahrtRichtung::RUECKWAERTS)
|
||||
m_fahrtrichtung = FahrtRichtung::WARTE_START_RUECKWAERTS;
|
||||
else
|
||||
m_fahrtrichtung = FahrtRichtung::WARTE_START_VORWAERTS;
|
||||
}
|
||||
else if (ev.m_eventType == BTN_VORWAERTS)
|
||||
m_fahrtrichtung = FahrtRichtung::VORWAERTS_QUITTIEREN;
|
||||
else if (ev.m_eventType == BTN_RUECKWAERTS)
|
||||
m_fahrtrichtung = FahrtRichtung::RUECKWAERTS_QUITTIEREN;
|
||||
break;
|
||||
|
||||
// ===== Vorwärts gewählt, wartet auf Quittieren =====
|
||||
case FahrtRichtung::VORWAERTS_QUITTIEREN:
|
||||
if (ev.m_eventType == BTN_QUIT)
|
||||
m_fahrtrichtung = FahrtRichtung::WARTE_START_VORWAERTS;
|
||||
else if (ev.m_eventType == BTN_HALT)
|
||||
m_fahrtrichtung = FahrtRichtung::HALT;
|
||||
else if (ev.m_eventType == BTN_NOTHALT)
|
||||
m_fahrtrichtung = FahrtRichtung::NOTHALT;
|
||||
else if (ev.m_eventType == BTN_RUECKWAERTS)
|
||||
m_fahrtrichtung = FahrtRichtung::RUECKWAERTS_QUITTIEREN;
|
||||
break;
|
||||
|
||||
// ===== Quittiert, wartet auf Start =====
|
||||
case FahrtRichtung::WARTE_START_VORWAERTS:
|
||||
if (ev.m_eventType == BTN_START)
|
||||
{
|
||||
m_fahrtrichtung = FahrtRichtung::VORWAERTS;
|
||||
m_vorherigeRichtung = FahrtRichtung::VORWAERTS;
|
||||
}
|
||||
break;
|
||||
|
||||
// ===== Anlage fährt vorwärts =====
|
||||
case FahrtRichtung::VORWAERTS:
|
||||
if (ev.m_eventType == BTN_HALT)
|
||||
m_fahrtrichtung = FahrtRichtung::HALT;
|
||||
else if (ev.m_eventType == BTN_NOTHALT)
|
||||
m_fahrtrichtung = FahrtRichtung::NOTHALT;
|
||||
break;
|
||||
|
||||
// ===== Rückwärts gewählt, wartet auf Quittieren =====
|
||||
case FahrtRichtung::RUECKWAERTS_QUITTIEREN:
|
||||
if (ev.m_eventType == BTN_QUIT)
|
||||
m_fahrtrichtung = FahrtRichtung::WARTE_START_RUECKWAERTS;
|
||||
else if (ev.m_eventType == BTN_HALT)
|
||||
m_fahrtrichtung = FahrtRichtung::HALT;
|
||||
else if (ev.m_eventType == BTN_NOTHALT)
|
||||
m_fahrtrichtung = FahrtRichtung::NOTHALT;
|
||||
else if (ev.m_eventType == BTN_VORWAERTS)
|
||||
m_fahrtrichtung = FahrtRichtung::VORWAERTS_QUITTIEREN;
|
||||
break;
|
||||
|
||||
// ===== Quittiert, wartet auf Start =====
|
||||
case FahrtRichtung::WARTE_START_RUECKWAERTS:
|
||||
if (ev.m_eventType == BTN_START)
|
||||
{
|
||||
m_fahrtrichtung = FahrtRichtung::RUECKWAERTS;
|
||||
m_vorherigeRichtung = FahrtRichtung::RUECKWAERTS;
|
||||
}
|
||||
break;
|
||||
|
||||
// ===== Anlage fährt rückwärts =====
|
||||
case FahrtRichtung::RUECKWAERTS:
|
||||
if (ev.m_eventType == BTN_HALT)
|
||||
m_fahrtrichtung = FahrtRichtung::HALT;
|
||||
else if (ev.m_eventType == BTN_NOTHALT)
|
||||
m_fahrtrichtung = FahrtRichtung::NOTHALT;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// updateLEDs(): alle LEDs anhand des aktuellen Zustands setzen
|
||||
// Wird jedes Loop aufgerufen → LEDs sind immer konsistent.
|
||||
// ============================================================
|
||||
void CMainController::updateLEDs()
|
||||
{
|
||||
// ===== Anlage Ein/Aus =====
|
||||
// LED leuchtet solange die Anlage eingeschaltet ist
|
||||
if (m_anlagenzustand != AnlagenZustand::AUS)
|
||||
m_btnAnlageEinAus.setLEDMode(LEDMode::ON);
|
||||
else
|
||||
m_btnAnlageEinAus.setLEDMode(LEDMode::OFF);
|
||||
|
||||
// ===== Station Besetzt/Unbesetzt =====
|
||||
// LED leuchtet solange die Anlage eingeschaltet ist
|
||||
if (m_anlagenzustand != AnlagenZustand::AUS)
|
||||
m_btnStation.setLEDMode(LEDMode::ON);
|
||||
else
|
||||
m_btnStation.setLEDMode(LEDMode::OFF);
|
||||
|
||||
// ===== Servicebetrieb =====
|
||||
// LED leuchtet im Servicezustand (auch während Quittieren)
|
||||
if (m_anlagenzustand == AnlagenZustand::SERVICE
|
||||
|| m_anlagenzustand == AnlagenZustand::SERVICE_QUITTIEREN)
|
||||
m_btnServicebetrieb.setLEDMode(LEDMode::ON);
|
||||
else
|
||||
m_btnServicebetrieb.setLEDMode(LEDMode::OFF);
|
||||
|
||||
// ===== Fahrgastbetrieb =====
|
||||
// LED leuchtet im Fahrgastzustand (auch während Quittieren)
|
||||
if (m_anlagenzustand == AnlagenZustand::FAHRGAST
|
||||
|| m_anlagenzustand == AnlagenZustand::FAHRGAST_QUITTIEREN)
|
||||
m_btnFahrgastbetrieb.setLEDMode(LEDMode::ON);
|
||||
else
|
||||
m_btnFahrgastbetrieb.setLEDMode(LEDMode::OFF);
|
||||
|
||||
// ===== Quittieren =====
|
||||
// LED blinkt wenn ein Zustandswechsel auf Quittierung wartet
|
||||
if (m_anlagenzustand == AnlagenZustand::SERVICE_QUITTIEREN
|
||||
|| m_anlagenzustand == AnlagenZustand::FAHRGAST_QUITTIEREN)
|
||||
m_btnQuitBetrieb.setLEDMode(LEDMode::BLINK);
|
||||
else
|
||||
m_btnQuitBetrieb.setLEDMode(LEDMode::OFF);
|
||||
|
||||
// ===== Ereignisanzeige (3-farbig) =====
|
||||
// Keine Buttons → direkt per digitalWrite gesetzt
|
||||
// Rot: Servicebetrieb aktiv
|
||||
if (m_anlagenzustand == AnlagenZustand::SERVICE)
|
||||
digitalWrite(PIN_LED_ROT_EREIGNISANZEIGE, HIGH);
|
||||
else
|
||||
digitalWrite(PIN_LED_ROT_EREIGNISANZEIGE, LOW);
|
||||
|
||||
// Gelb: Zustandswechsel wartet auf Quittierung
|
||||
if (m_anlagenzustand == AnlagenZustand::SERVICE_QUITTIEREN
|
||||
|| m_anlagenzustand == AnlagenZustand::FAHRGAST_QUITTIEREN)
|
||||
digitalWrite(PIN_LED_GELB_EREIGNISANZEIGE, HIGH);
|
||||
else
|
||||
digitalWrite(PIN_LED_GELB_EREIGNISANZEIGE, LOW);
|
||||
|
||||
// Grün: Fahrgastbetrieb aktiv
|
||||
if (m_anlagenzustand == AnlagenZustand::FAHRGAST)
|
||||
digitalWrite(PIN_LED_GRUEN_EREIGNISANZEIGE, HIGH);
|
||||
else
|
||||
digitalWrite(PIN_LED_GRUEN_EREIGNISANZEIGE, LOW);
|
||||
|
||||
// ===== Fahrtrichtungs-LEDs =====
|
||||
// Nur relevant wenn die Anlage eingeschaltet ist
|
||||
|
||||
// Halt: leuchtet wenn Anlage steht (normaler Halt)
|
||||
if (m_anlagenzustand != AnlagenZustand::AUS && m_fahrtrichtung == FahrtRichtung::HALT)
|
||||
m_btnHalt.setLEDMode(LEDMode::ON);
|
||||
else
|
||||
m_btnHalt.setLEDMode(LEDMode::OFF);
|
||||
|
||||
// Nothalt: leuchtet wenn Nothalt aktiv
|
||||
if (m_anlagenzustand != AnlagenZustand::AUS && m_fahrtrichtung == FahrtRichtung::NOTHALT)
|
||||
m_btnNothalt.setLEDMode(LEDMode::ON);
|
||||
else
|
||||
m_btnNothalt.setLEDMode(LEDMode::OFF);
|
||||
|
||||
// Start: blinkt wenn quittiert wurde und auf Start gewartet wird
|
||||
if (m_anlagenzustand != AnlagenZustand::AUS &&
|
||||
(m_fahrtrichtung == FahrtRichtung::WARTE_START_VORWAERTS || m_fahrtrichtung == FahrtRichtung::WARTE_START_RUECKWAERTS) )
|
||||
m_btnStart.setLEDMode(LEDMode::BLINK);
|
||||
else
|
||||
m_btnStart.setLEDMode(LEDMode::OFF);
|
||||
|
||||
// Vorwärts: leuchtet dauerhaft nur wenn Anlage tatsächlich vorwärts fährt,
|
||||
// blinkt während Quittieren und Warten auf Start
|
||||
if (m_anlagenzustand != AnlagenZustand::AUS && m_fahrtrichtung == FahrtRichtung::VORWAERTS)
|
||||
m_btnVorwaerts.setLEDMode(LEDMode::ON);
|
||||
else if (m_anlagenzustand != AnlagenZustand::AUS &&
|
||||
(m_fahrtrichtung == FahrtRichtung::VORWAERTS_QUITTIEREN || m_fahrtrichtung == FahrtRichtung::WARTE_START_VORWAERTS))
|
||||
m_btnVorwaerts.setLEDMode(LEDMode::BLINK);
|
||||
else
|
||||
m_btnVorwaerts.setLEDMode(LEDMode::OFF);
|
||||
|
||||
// Rückwärts: leuchtet dauerhaft nur wenn Anlage tatsächlich rückwärts fährt,
|
||||
// blinkt während Quittieren und Warten auf Start
|
||||
if (m_anlagenzustand != AnlagenZustand::AUS && m_fahrtrichtung == FahrtRichtung::RUECKWAERTS)
|
||||
m_btnRueckwaerts.setLEDMode(LEDMode::ON);
|
||||
else if (m_anlagenzustand != AnlagenZustand::AUS &&
|
||||
(m_fahrtrichtung == FahrtRichtung::RUECKWAERTS_QUITTIEREN || m_fahrtrichtung == FahrtRichtung::WARTE_START_RUECKWAERTS))
|
||||
m_btnRueckwaerts.setLEDMode(LEDMode::BLINK);
|
||||
else
|
||||
m_btnRueckwaerts.setLEDMode(LEDMode::OFF);
|
||||
}
|
||||
@ -1,13 +1,94 @@
|
||||
#ifndef CSEILMAINCONTROLLER_H_
|
||||
#define CSEILMAINCONTROLLER_H_
|
||||
|
||||
#include
|
||||
#include "CButton.h"
|
||||
#include "CEventQueue.h"
|
||||
#include "SEvent.h"
|
||||
|
||||
// enum class = scoped enum → Werte sind nicht global sichtbar, sondern nur als
|
||||
// AnlagenZustand::AUS, AnlagenZustand::SERVICE etc.
|
||||
// Das verhindert Namenskonflikte mit den gleichnamigen Werten in main.cpp.
|
||||
enum class AnlagenZustand
|
||||
{
|
||||
AUS,
|
||||
SERVICE_QUITTIEREN,
|
||||
SERVICE,
|
||||
FAHRGAST_QUITTIEREN,
|
||||
FAHRGAST,
|
||||
};
|
||||
|
||||
enum class FahrtRichtung
|
||||
{
|
||||
HALT,
|
||||
NOTHALT,
|
||||
VORWAERTS_QUITTIEREN,
|
||||
WARTE_START_VORWAERTS,
|
||||
VORWAERTS,
|
||||
RUECKWAERTS_QUITTIEREN,
|
||||
WARTE_START_RUECKWAERTS,
|
||||
RUECKWAERTS,
|
||||
};
|
||||
|
||||
class CMainController
|
||||
{
|
||||
public:
|
||||
CMainController();
|
||||
void setup(); // pinMode aller Buttons und LEDs setzen
|
||||
void work(); // Buttons abfragen, Events verarbeiten, LEDs aktualisieren
|
||||
|
||||
private:
|
||||
}
|
||||
// ===== Pin-Definitionen =====
|
||||
static const short PIN_LED_ANLAGE_EIN_AUS = 2;
|
||||
static const short PIN_KNOPF_ANLAGE_EIN_AUS = 3;
|
||||
static const short PIN_LED_STATION = 4;
|
||||
static const short PIN_KNOPF_STATION = 5;
|
||||
static const short PIN_LED_SERVICEBETRIEB = 6;
|
||||
static const short PIN_KNOPF_SERVICEBETRIEB = 7;
|
||||
static const short PIN_LED_FAHRGASTBETRIEB = 22;
|
||||
static const short PIN_KNOPF_FAHRGASTBETRIEB = 23;
|
||||
static const short PIN_LED_ROT_EREIGNISANZEIGE = 13;
|
||||
static const short PIN_LED_GELB_EREIGNISANZEIGE = 12;
|
||||
static const short PIN_LED_GRUEN_EREIGNISANZEIGE = 11;
|
||||
static const short PIN_LED_QUIT_BETRIEB = 9;
|
||||
static const short PIN_KNOPF_QUIT_BETRIEB = 10;
|
||||
static const short PIN_LED_START_BETRIEB = 36;
|
||||
static const short PIN_KNOPF_START_BETRIEB = 37;
|
||||
static const short PIN_LED_HALT = 38;
|
||||
static const short PIN_KNOPF_HALT = 39;
|
||||
static const short PIN_LED_NOTHALT = 40;
|
||||
static const short PIN_KNOPF_NOTHALT = 41;
|
||||
static const short PIN_LED_VORWAERTS = 30;
|
||||
static const short PIN_KNOPF_VORWAERTS = 31;
|
||||
static const short PIN_LED_RUECKWAERTS = 32;
|
||||
static const short PIN_KNOPF_RUECKWAERTS = 33;
|
||||
|
||||
#endif /* CSEILMAINCONTROLLER_H_ */
|
||||
// ===== EventQueue =====
|
||||
// Muss VOR den Buttons deklariert sein! Member werden in Deklarationsreihenfolge
|
||||
// initialisiert — die Buttons bekommen einen Zeiger auf diese Queue.
|
||||
CEventQueue m_queue;
|
||||
|
||||
// ===== Buttons =====
|
||||
CButton m_btnAnlageEinAus;
|
||||
CButton m_btnStation;
|
||||
CButton m_btnServicebetrieb;
|
||||
CButton m_btnFahrgastbetrieb;
|
||||
CButton m_btnQuitBetrieb;
|
||||
CButton m_btnStart;
|
||||
CButton m_btnHalt;
|
||||
CButton m_btnNothalt;
|
||||
CButton m_btnVorwaerts;
|
||||
CButton m_btnRueckwaerts;
|
||||
|
||||
// ===== Zustandsvariablen =====
|
||||
AnlagenZustand m_anlagenzustand;
|
||||
FahrtRichtung m_fahrtrichtung;
|
||||
FahrtRichtung m_vorherigeRichtung; // Merkt sich die letzte Fahrtrichtung für Quittieren nach HALT/NOTHALT
|
||||
|
||||
// ===== Private Hilfsmethoden =====
|
||||
void pollButtons(); // Alle work()-Methoden der Buttons aufrufen
|
||||
void processEvents(); // Events aus der Queue lesen und Zustand ändern
|
||||
void processFahrtrichtungEvent(SEvent ev); // Fahrtrichtungs-Statemachine
|
||||
void updateLEDs(); // Alle LEDs anhand des aktuellen Zustands setzen
|
||||
};
|
||||
|
||||
#endif /* CMAINCONTROLLER_H_ */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user