Compare commits
6 Commits
7187c2aa53
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| f1e5a758c2 | |||
| 43497376cb | |||
| c4861d9793 | |||
| 73c0795e50 | |||
| 3268d094b8 | |||
| 107ad934a4 |
@@ -0,0 +1,5 @@
|
|||||||
|
.pio
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/ipch
|
||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
|
// for the documentation about the extensions.json format
|
||||||
|
"recommendations": [
|
||||||
|
"platformio.platformio-ide"
|
||||||
|
],
|
||||||
|
"unwantedRecommendations": [
|
||||||
|
"ms-vscode.cpptools-extension-pack"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
```
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the convention is to give header files names that end with `.h'.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into the executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a separate directory
|
||||||
|
("lib/your_library_name/[Code]").
|
||||||
|
|
||||||
|
For example, see the structure of the following example libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
Example contents of `src/main.c` using Foo and Bar:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries by scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:megaatmega2560]
|
||||||
|
platform = atmelavr
|
||||||
|
board = megaatmega2560
|
||||||
|
framework = arduino
|
||||||
|
lib_deps = mike-matera/ArduinoSTL@^1.3.3
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#include "CButton.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CButton::setup()
|
||||||
|
{
|
||||||
|
pinMode(m_btnPin, INPUT_PULLUP);
|
||||||
|
pinMode(m_ledPin, OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CButton::setLEDMode(LEDMode mode)
|
||||||
|
{
|
||||||
|
m_ledMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
LEDMode CButton::getLEDMode()
|
||||||
|
{
|
||||||
|
return m_ledMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CButton::work()
|
||||||
|
{
|
||||||
|
// ===== 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;
|
||||||
|
|
||||||
|
// Flankenauswertung: nur bei steigender Flanke reagieren (nicht gedrückt → gedrückt)
|
||||||
|
if (m_currentButtonState && !m_buttonState)
|
||||||
|
{
|
||||||
|
// Entprellen
|
||||||
|
delay(20);
|
||||||
|
m_currentButtonState = digitalRead(m_btnPin) == LOW;
|
||||||
|
|
||||||
|
if (m_currentButtonState)
|
||||||
|
{
|
||||||
|
SEvent event;
|
||||||
|
event.m_eventType = m_eventType;
|
||||||
|
event.m_additionalInfo = 0;
|
||||||
|
m_queue->pushEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Immer aktualisieren — so wird der Button nach dem Loslassen wieder erkannt
|
||||||
|
m_buttonState = m_currentButtonState;
|
||||||
|
}
|
||||||
@@ -0,0 +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, 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;
|
||||||
|
short m_ledPin;
|
||||||
|
EVENT_TYPE m_eventType;
|
||||||
|
CEventQueue* m_queue;
|
||||||
|
|
||||||
|
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,94 @@
|
|||||||
|
#include "CEventQueue.h"
|
||||||
|
|
||||||
|
/*! \fn std::vector<SEvent> CEventQueue::popEvents(EVENT_TYPE eventType)
|
||||||
|
\brief Liefert einen chronologisch geordneten Vektor (FIFO) der aufgelaufenen
|
||||||
|
Events in dieser Queue zurueck. Diese werden daraufhin aus der Queue geloescht
|
||||||
|
\param eventType Falls nicht UNDEFINED, werden nur Events des angegebenen Typs
|
||||||
|
zurueckgegeben und aus der Queue geloescht, andernfalls alle
|
||||||
|
\return Chronologisch sortierter Vektor der Events (aelteste zuerst)
|
||||||
|
*/
|
||||||
|
std::vector<SEvent> CEventQueue::popEvents(EVENT_TYPE eventType)
|
||||||
|
{
|
||||||
|
std::vector<SEvent> ret;
|
||||||
|
|
||||||
|
switch(eventType)
|
||||||
|
{
|
||||||
|
case UNDEFINED:
|
||||||
|
ret = m_events;
|
||||||
|
m_events.clear();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
std::vector<SEvent> without;
|
||||||
|
for(std::vector<SEvent>::iterator it=m_events.begin(); it!=m_events.end(); it++)
|
||||||
|
{
|
||||||
|
if(it->m_eventType==eventType)
|
||||||
|
{
|
||||||
|
ret.push_back(*it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
without.push_back(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_events = without;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \fn SEvent CEventQueue::popEvent(bool* pValid)
|
||||||
|
\brief Liefert das chronologisch letzte (neueste) Event in der Queue zurueck
|
||||||
|
\param pValid true, falls ein Event aus der Queue zurueckgegeben wird,
|
||||||
|
false andernfalls (dann war die Queue naemlich leer)
|
||||||
|
\return Das chronologisch letzte (neueste) Event in der Queue
|
||||||
|
*/
|
||||||
|
SEvent CEventQueue::popEvent(bool* pValid)
|
||||||
|
{
|
||||||
|
return popEvent(m_events.size()-1, pValid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \fn SEvent CEventQueue::popEvent(unsigned short eventNumber,
|
||||||
|
* bool* pValid)
|
||||||
|
\brief Liefert das Event mit dem angegebenen Index in der Queue der gespeicherten
|
||||||
|
Events zurueck. Das Event wird daraufhin aus der Queue geloescht
|
||||||
|
\param eventNumber Index des zurueckzuliefernden Events in der Queue
|
||||||
|
\param pValid true, falls ein Event aus der Queue zurueckgegeben wird,
|
||||||
|
false andernfalls (dann existiert kein Event mit dem angegebenen Index)
|
||||||
|
\return Falls eventNumber nicht INVALID_EVENT_NUMBER, das Event mit dem
|
||||||
|
angegebenen Index in der Queue, das chronologisch erste (aelteste) Event
|
||||||
|
andernfalls
|
||||||
|
*/
|
||||||
|
SEvent CEventQueue::popEvent(unsigned short eventNumber, bool* pValid)
|
||||||
|
{
|
||||||
|
if(eventNumber<m_events.size())
|
||||||
|
{
|
||||||
|
*pValid=true;
|
||||||
|
std::vector<SEvent>::iterator it;
|
||||||
|
SEvent ret;
|
||||||
|
it=(m_events.begin() + eventNumber);
|
||||||
|
ret=*it;
|
||||||
|
m_events.erase(it);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*pValid=false;
|
||||||
|
SEvent e;
|
||||||
|
e.m_eventType=UNDEFINED;
|
||||||
|
e.m_additionalInfo=0;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \fn void CEventQueue::pushEvent(SEvent event)
|
||||||
|
\brief Fuegt der Queue ein Event hinzu. Sensoren und Aktoren
|
||||||
|
rufen diese Methode auf, um ueber ein Event zu informieren
|
||||||
|
\param event Hinzuzufuegendes Event
|
||||||
|
*/
|
||||||
|
void CEventQueue::pushEvent(SEvent event)
|
||||||
|
{
|
||||||
|
m_events.push_back(event);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef CEVENTQUEUE_H_
|
||||||
|
#define CEVENTQUEUE_H_
|
||||||
|
|
||||||
|
#include "SEvent.h"
|
||||||
|
#include "ArduinoSTL.h"
|
||||||
|
|
||||||
|
class CEventQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<SEvent> popEvents(EVENT_TYPE eventtype=UNDEFINED);
|
||||||
|
SEvent popEvent(bool* pValid);
|
||||||
|
SEvent popEvent(unsigned short eventNumber, bool* pValid);
|
||||||
|
void pushEvent(SEvent event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<SEvent> m_events;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CEVENTQUEUE_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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
#ifndef CSEILMAINCONTROLLER_H_
|
||||||
|
#define CSEILMAINCONTROLLER_H_
|
||||||
|
|
||||||
|
#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;
|
||||||
|
|
||||||
|
// ===== 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_ */
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#include "SEvent.h"
|
||||||
|
|
||||||
|
const char* evToStr(SEvent ev)
|
||||||
|
{
|
||||||
|
switch(ev.m_eventType)
|
||||||
|
{
|
||||||
|
case BTN_ANLAGE_EIN_AUS: return "BTN_ANLAGE_EIN_AUS";
|
||||||
|
case BTN_STATION: return "BTN_STATION";
|
||||||
|
case BTN_SERVICE: return "BTN_SERVICE";
|
||||||
|
case BTN_FAHRGAST: return "BTN_FAHRGAST";
|
||||||
|
case BTN_QUIT: return "BTN_QUIT";
|
||||||
|
case BTN_START: return "BTN_START";
|
||||||
|
case BTN_HALT: return "BTN_HALT";
|
||||||
|
case BTN_NOTHALT: return "BTN_NOTHALT";
|
||||||
|
case BTN_VORWAERTS: return "BTN_VORWAERTS";
|
||||||
|
case BTN_RUECKWAERTS: return "BTN_RUECKWAERTS";
|
||||||
|
default: return "UNDEFINED";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printEvent(SEvent event, void* who)
|
||||||
|
{
|
||||||
|
// TBD if needed
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef SEVENT_H_
|
||||||
|
#define SEVENT_H_
|
||||||
|
|
||||||
|
enum EVENT_TYPE
|
||||||
|
{
|
||||||
|
BTN_ANLAGE_EIN_AUS, // Button Anlage Ein/Aus wurde gedrückt
|
||||||
|
BTN_STATION, // Button Station Besetzt/Unbesetzt wurde gedrückt
|
||||||
|
BTN_SERVICE, // Button Servicebetrieb wurde gedrückt
|
||||||
|
BTN_FAHRGAST, // Button Fahrgastbetrieb wurde gedrückt
|
||||||
|
BTN_QUIT, // Button Quittieren wurde gedrückt
|
||||||
|
BTN_START, // Button Start wurde gedrückt
|
||||||
|
BTN_HALT, // Button Halt wurde gedrückt
|
||||||
|
BTN_NOTHALT, // Button Nothalt wurde gedrückt
|
||||||
|
BTN_VORWAERTS, // Button Vorwaerts wurde gedrückt
|
||||||
|
BTN_RUECKWAERTS, // Button Rueckwaerts wurde gedrückt
|
||||||
|
UNDEFINED=999,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SEvent
|
||||||
|
{
|
||||||
|
EVENT_TYPE m_eventType;
|
||||||
|
unsigned int m_additionalInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* evToStr(SEvent ev);
|
||||||
|
void printEvent(SEvent event, void* who);
|
||||||
|
|
||||||
|
#endif /* SEVENT_H_ */
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include "CMainController.h"
|
||||||
|
|
||||||
|
CMainController controller;
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(9600);
|
||||||
|
controller.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
controller.work();
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
This directory is intended for PlatformIO Test Runner and project tests.
|
||||||
|
|
||||||
|
Unit Testing is a software testing method by which individual units of
|
||||||
|
source code, sets of one or more MCU program modules together with associated
|
||||||
|
control data, usage procedures, and operating procedures, are tested to
|
||||||
|
determine whether they are fit for use. Unit testing finds problems early
|
||||||
|
in the development cycle.
|
||||||
|
|
||||||
|
More information about PlatformIO Unit Testing:
|
||||||
|
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
||||||
@@ -18,6 +18,20 @@
|
|||||||
#define LED_QUIT_BETRIEB 9
|
#define LED_QUIT_BETRIEB 9
|
||||||
#define KNOPF_QUIT_BETRIEB 10
|
#define KNOPF_QUIT_BETRIEB 10
|
||||||
|
|
||||||
|
#define LED_START_BETRIEB 36
|
||||||
|
#define KNOPF_START_BETRIEB 37
|
||||||
|
|
||||||
|
#define LED_HALT 38
|
||||||
|
#define KNOPF_HALT 39
|
||||||
|
|
||||||
|
#define LED_NOTHALT 40
|
||||||
|
#define KNOPF_NOTHALT 41
|
||||||
|
|
||||||
|
#define LED_VORWAERTS 30
|
||||||
|
#define KNOPF_VORWAERTS 31
|
||||||
|
|
||||||
|
#define LED_RUECKWAERTS 32
|
||||||
|
#define KNOPF_RUECKWAERTS 33
|
||||||
|
|
||||||
// Hilfsvariablen zum merken des Zustands
|
// Hilfsvariablen zum merken des Zustands
|
||||||
bool buttonStateAnlageEinAus = false;
|
bool buttonStateAnlageEinAus = false;
|
||||||
@@ -35,6 +49,21 @@ bool currentButtonStateFahrgastbetrieb = false;
|
|||||||
bool buttonStateQuitBetrieb = false;
|
bool buttonStateQuitBetrieb = false;
|
||||||
bool currentButtonStateQuitBetrieb = false;
|
bool currentButtonStateQuitBetrieb = false;
|
||||||
|
|
||||||
|
bool buttonStateStart = false;
|
||||||
|
bool currentButtonStateStart = false;
|
||||||
|
|
||||||
|
bool buttonStateHalt = false;
|
||||||
|
bool currentButtonStateHalt = false;
|
||||||
|
|
||||||
|
bool buttonStateNothalt = false;
|
||||||
|
bool currentButtonStateNothalt = false;
|
||||||
|
|
||||||
|
bool buttonStateVorwaerts = false;
|
||||||
|
bool currentButtonStateVorwaerts = false;
|
||||||
|
|
||||||
|
bool buttonStateRueckwaerts = false;
|
||||||
|
bool currentButtonStateRueckwaerts = false;
|
||||||
|
|
||||||
// Anlagenzustände
|
// Anlagenzustände
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -48,79 +77,203 @@ enum
|
|||||||
// Fahrtrichtungen
|
// Fahrtrichtungen
|
||||||
enum Fahrtrichtung
|
enum Fahrtrichtung
|
||||||
{
|
{
|
||||||
HALT,
|
HALT, // Anlage steht
|
||||||
NOTHALT,
|
NOTHALT, // Anlage steht (Notstop)
|
||||||
WARTE_START,
|
VORWAERTS_QUITTIEREN, // Richtungsknopf vorwärts gedrückt, warte auf quittieren
|
||||||
VORWAERTS_QUITTIEREN,
|
WARTE_START_VORWAERTS, // Anlage steht und wartet auf starten (in die entsprechende Richtung)
|
||||||
VORWAERTS,
|
VORWAERTS, // Anlage fährt vorwärts
|
||||||
RUECKWAERTS_QUITTIEREN,
|
RUECKWAERTS_QUITTIEREN, // Richtungsknopf rückwärts gedrückt, warte auf quittieren
|
||||||
RUECKWAERTS,
|
WARTE_START_RUECKWAERTS, // Anlage steht und wartet auf starten (in die entsprechende Richtung)
|
||||||
|
RUECKWAERTS, // Anlage fährt rückwärts
|
||||||
} fahrtrichtung;
|
} fahrtrichtung;
|
||||||
|
|
||||||
Fahrtrichtung vorherigerichtung = HALT;
|
Fahrtrichtung vorherigeRichtung = HALT;
|
||||||
|
|
||||||
void quittierenButtonAbfragen()
|
void quittierenButtonAbfragen()
|
||||||
{
|
{
|
||||||
// Button Code [...]
|
// ========== Quittieren Button abfragen
|
||||||
if(fahrtrichtung == NOTHALT || fahrtrichtung == HALT)
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
|
currentButtonStateQuitBetrieb = digitalRead(KNOPF_QUIT_BETRIEB) == LOW;
|
||||||
|
// Aktuellen Zustand mit vorherigem vergleichen
|
||||||
|
if (currentButtonStateQuitBetrieb && !buttonStateQuitBetrieb)
|
||||||
|
{
|
||||||
|
// Warten zum entprellen
|
||||||
|
delay(20);
|
||||||
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
|
currentButtonStateQuitBetrieb = digitalRead(KNOPF_QUIT_BETRIEB) == LOW;
|
||||||
|
// Prüfen ob immernoch gedrückt
|
||||||
|
if (currentButtonStateQuitBetrieb == LOW)
|
||||||
{
|
{
|
||||||
fahrtrichtung = WARTE_START;
|
// Knopf gedrückt => Code ausführen
|
||||||
}
|
// ============================================================
|
||||||
else if(fahrtrichtung == VORWAERTS_QUITTIEREN)
|
switch(fahrtrichtung)
|
||||||
{
|
{
|
||||||
fahrtrichtung = WARTE_START;
|
case HALT:
|
||||||
}
|
case NOTHALT:
|
||||||
else if(fahrtrichtung == RUECKWAERTS_QUITTIEREN)
|
if(vorherigeRichtung == RUECKWAERTS)
|
||||||
{
|
{
|
||||||
fahrtrichtung = WARTE_START;
|
fahrtrichtung = WARTE_START_RUECKWAERTS;
|
||||||
}
|
}
|
||||||
// Button Code [...]
|
else
|
||||||
|
{
|
||||||
|
fahrtrichtung = WARTE_START_VORWAERTS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VORWAERTS_QUITTIEREN:
|
||||||
|
fahrtrichtung = WARTE_START_VORWAERTS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RUECKWAERTS_QUITTIEREN:
|
||||||
|
fahrtrichtung = WARTE_START_RUECKWAERTS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// ============================================================
|
||||||
|
// Speichern des ButtonStates als Vergleichswert für den nächsten Durchlauf
|
||||||
|
buttonStateQuitBetrieb = currentButtonStateQuitBetrieb;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void startButtonAbfragen()
|
void startButtonAbfragen()
|
||||||
{
|
{
|
||||||
// Button Code [...]
|
// ========== Start Button abfragen
|
||||||
if(vorherigerichtung == VORWAERTS)
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
|
currentButtonStateStart = digitalRead(KNOPF_START_BETRIEB) == LOW;
|
||||||
|
// Aktuellen Zustand mit vorherigem vergleichen
|
||||||
|
if (currentButtonStateStart && !buttonStateStart)
|
||||||
|
{
|
||||||
|
// Warten zum entprellen
|
||||||
|
delay(20);
|
||||||
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
|
currentButtonStateStart = digitalRead(KNOPF_START_BETRIEB) == LOW;
|
||||||
|
// Prüfen ob immernoch gedrückt
|
||||||
|
if (currentButtonStateStart == LOW)
|
||||||
{
|
{
|
||||||
fahrtrichtung = RUECKWAERTS;
|
// Knopf gedrückt => Code ausführen
|
||||||
}
|
// ============================================================
|
||||||
else if(vorherigerichtung == RUECKWAERTS)
|
switch(fahrtrichtung)
|
||||||
{
|
{
|
||||||
fahrtrichtung = VORWAERTS;
|
case WARTE_START_VORWAERTS:
|
||||||
}
|
fahrtrichtung = VORWAERTS;
|
||||||
else
|
vorherigeRichtung = VORWAERTS;
|
||||||
{
|
break;
|
||||||
fahrtrichtung = VORWAERTS;
|
|
||||||
}
|
case WARTE_START_RUECKWAERTS:
|
||||||
// Button Code [...]
|
fahrtrichtung = RUECKWAERTS;
|
||||||
|
vorherigeRichtung = RUECKWAERTS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// ============================================================
|
||||||
|
// Speichern des ButtonStates als Vergleichswert für den nächsten Durchlauf
|
||||||
|
buttonStateStart = currentButtonStateStart;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FERTIG
|
||||||
void haltButtonAbfragen()
|
void haltButtonAbfragen()
|
||||||
{
|
{
|
||||||
// Button Code [...]
|
// ========== Start Button abfragen
|
||||||
fahrtrichtung = HALT;
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
// Button Code [...]
|
currentButtonStateHalt = digitalRead(KNOPF_START_BETRIEB) == LOW;
|
||||||
|
// Aktuellen Zustand mit vorherigem vergleichen
|
||||||
|
if (currentButtonStateHalt && !buttonStateHalt)
|
||||||
|
{
|
||||||
|
// Warten zum entprellen
|
||||||
|
delay(20);
|
||||||
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
|
currentButtonStateHalt = digitalRead(KNOPF_START_BETRIEB) == LOW;
|
||||||
|
// Prüfen ob immernoch gedrückt
|
||||||
|
if (currentButtonStateHalt == LOW)
|
||||||
|
{
|
||||||
|
// Knopf gedrückt => Code ausführen
|
||||||
|
// ============================================================
|
||||||
|
fahrtrichtung = HALT;
|
||||||
|
// ============================================================
|
||||||
|
// Speichern des ButtonStates als Vergleichswert für den nächsten Durchlauf
|
||||||
|
buttonStateHalt = currentButtonStateHalt;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//FERTIG
|
||||||
void nothaltButtonAbfragen()
|
void nothaltButtonAbfragen()
|
||||||
{
|
{
|
||||||
// Button Code [...]
|
// ========== Start Button abfragen
|
||||||
fahrtrichtung = NOTHALT;
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
// Button Code [...]
|
currentButtonStateNothalt = digitalRead(KNOPF_START_BETRIEB) == LOW;
|
||||||
|
// Aktuellen Zustand mit vorherigem vergleichen
|
||||||
|
if (currentButtonStateNothalt && !buttonStateNothalt)
|
||||||
|
{
|
||||||
|
// Warten zum entprellen
|
||||||
|
delay(20);
|
||||||
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
|
currentButtonStateNothalt = digitalRead(KNOPF_START_BETRIEB) == LOW;
|
||||||
|
// Prüfen ob immernoch gedrückt
|
||||||
|
if (currentButtonStateNothalt == LOW)
|
||||||
|
{
|
||||||
|
// Knopf gedrückt => Code ausführen
|
||||||
|
// ============================================================
|
||||||
|
fahrtrichtung = NOTHALT;
|
||||||
|
// ============================================================
|
||||||
|
// Speichern des ButtonStates als Vergleichswert für den nächsten Durchlauf
|
||||||
|
buttonStateNothalt = currentButtonStateNothalt;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//FERTIG
|
||||||
void vorwaertsButtonAbfragen()
|
void vorwaertsButtonAbfragen()
|
||||||
{
|
{
|
||||||
// Button Code [...]
|
// ========== Start Button abfragen
|
||||||
fahrtrichtung = VORWAERTS_QUITTIEREN;
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
// Button Code [...]
|
currentButtonStateVorwaerts = digitalRead(KNOPF_START_BETRIEB) == LOW;
|
||||||
|
// Aktuellen Zustand mit vorherigem vergleichen
|
||||||
|
if (currentButtonStateVorwaerts && !buttonStateVorwaerts)
|
||||||
|
{
|
||||||
|
// Warten zum entprellen
|
||||||
|
delay(20);
|
||||||
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
|
currentButtonStateVorwaerts = digitalRead(KNOPF_START_BETRIEB) == LOW;
|
||||||
|
// Prüfen ob immernoch gedrückt
|
||||||
|
if (currentButtonStateVorwaerts == LOW)
|
||||||
|
{
|
||||||
|
// Knopf gedrückt => Code ausführen
|
||||||
|
// ============================================================
|
||||||
|
// In jeder beliebigen Fahrtrichtung, Fahrtrichtung Ändern (HALT, NOTHALT, RUECKWAERTS_QUITTIEREN, )
|
||||||
|
fahrtrichtung = VORWAERTS_QUITTIEREN;
|
||||||
|
// ============================================================
|
||||||
|
// Speichern des ButtonStates als Vergleichswert für den nächsten Durchlauf
|
||||||
|
buttonStateVorwaerts = currentButtonStateVorwaerts;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//FERTIG
|
||||||
void rueckwaertsButtonAbfragen()
|
void rueckwaertsButtonAbfragen()
|
||||||
{
|
{
|
||||||
// Button Code [...]
|
// ========== Start Button abfragen
|
||||||
fahrtrichtung = RUECKWAERTS_QUITTIEREN;
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
// Button Code [...]
|
currentButtonStateRueckwaerts = digitalRead(KNOPF_START_BETRIEB) == LOW;
|
||||||
|
// Aktuellen Zustand mit vorherigem vergleichen
|
||||||
|
if (currentButtonStateRueckwaerts && !buttonStateRueckwaerts)
|
||||||
|
{
|
||||||
|
// Warten zum entprellen
|
||||||
|
delay(20);
|
||||||
|
// Taster abfragen und aktuellen Zustand zwischenspeichern
|
||||||
|
currentButtonStateRueckwaerts = digitalRead(KNOPF_START_BETRIEB) == LOW;
|
||||||
|
// Prüfen ob immernoch gedrückt
|
||||||
|
if (currentButtonStateRueckwaerts == LOW)
|
||||||
|
{
|
||||||
|
// Knopf gedrückt => Code ausführen
|
||||||
|
// ============================================================
|
||||||
|
fahrtrichtung = RUECKWAERTS_QUITTIEREN;
|
||||||
|
// ============================================================
|
||||||
|
// Speichern des ButtonStates als Vergleichswert für den nächsten Durchlauf
|
||||||
|
buttonStateRueckwaerts = currentButtonStateRueckwaerts;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
@@ -240,7 +393,6 @@ void loop() {
|
|||||||
buttonStateQuitBetrieb = currentButtonStateQuitBetrieb;
|
buttonStateQuitBetrieb = currentButtonStateQuitBetrieb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,48 +412,64 @@ void loop() {
|
|||||||
// Anlage steht
|
// Anlage steht
|
||||||
case HALT:
|
case HALT:
|
||||||
{
|
{
|
||||||
quittierenButtonAbfragen();
|
quittierenButtonAbfragen(); // => "WARTE_START" Anhand Richtung
|
||||||
vorwaertsButtonAbfragen();
|
vorwaertsButtonAbfragen(); // => "VORWAERTS_QUITTIEREN"
|
||||||
rueckwaertsButtonAbfragen();
|
rueckwaertsButtonAbfragen(); // => "RUECKWAERTS_QUITTIEREN"
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Anlage steht
|
// Anlage steht
|
||||||
case NOTHALT:
|
case NOTHALT:
|
||||||
{
|
{
|
||||||
quittierenButtonAbfragen();
|
quittierenButtonAbfragen(); // => "WARTE_START"
|
||||||
vorwaertsButtonAbfragen();
|
vorwaertsButtonAbfragen(); // => "VORWAERTS_QUITTIEREN"
|
||||||
rueckwaertsButtonAbfragen();
|
rueckwaertsButtonAbfragen(); // => "RUECKWAERTS_QUITTIEREN"
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Anlage steht
|
// Anlage steht
|
||||||
case WARTE_START:
|
|
||||||
{
|
|
||||||
startButtonAbfragen();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Anlage fährt vorwärts
|
// Anlage fährt vorwärts
|
||||||
case VORWAERTS_QUITTIEREN:
|
case VORWAERTS_QUITTIEREN:
|
||||||
{
|
{
|
||||||
|
quittierenButtonAbfragen(); // => "WARTE_START_VORWAERTS"
|
||||||
|
haltButtonAbfragen(); // => "HALT"
|
||||||
|
nothaltButtonAbfragen(); // => "NOTHALT"
|
||||||
|
rueckwaertsButtonAbfragen(); // => "RUECKWAERTS_QUITTIEREN"
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WARTE_START_VORWAERTS:
|
||||||
|
{
|
||||||
|
startButtonAbfragen(); // => "VORWAERTS"
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Anlage fährt vorwärts
|
// Anlage fährt vorwärts
|
||||||
case VORWAERTS:
|
case VORWAERTS:
|
||||||
{
|
{
|
||||||
haltButtonAbfragen();
|
haltButtonAbfragen(); // => "HALT"
|
||||||
nothaltButtonAbfragen();
|
nothaltButtonAbfragen(); // => "NOTHALT"
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Anlage fährt rückwärts
|
// Anlage fährt rückwärts
|
||||||
case RUECKWAERTS_QUITTIEREN:
|
case RUECKWAERTS_QUITTIEREN:
|
||||||
{
|
{
|
||||||
|
quittierenButtonAbfragen(); // => "WARTE_START_RUECKWAERTS"
|
||||||
|
haltButtonAbfragen(); // => "HALT"
|
||||||
|
nothaltButtonAbfragen(); // => "NOTHALT"
|
||||||
|
vorwaertsButtonAbfragen(); // => "VORWAERTS_QUITTIEREN"
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WARTE_START_RUECKWAERTS:
|
||||||
|
{
|
||||||
|
startButtonAbfragen(); // => "RUECKWAERTS"
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Anlage fährt rückwärts
|
// Anlage fährt rückwärts
|
||||||
case RUECKWAERTS:
|
case RUECKWAERTS:
|
||||||
{
|
{
|
||||||
haltButtonAbfragen();
|
haltButtonAbfragen(); // => "HALT"
|
||||||
nothaltButtonAbfragen();
|
nothaltButtonAbfragen(); // => "NOTHALT"
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -425,13 +593,13 @@ void loop() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Anlage fährt vorwärts
|
// Anlage fährt vorwärts
|
||||||
case VORWÄRTS:
|
case VORWAERTS:
|
||||||
{
|
{
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Anlage fährt rückwärts
|
// Anlage fährt rückwärts
|
||||||
case RÜCKWÄRTS:
|
case RUECKWAERTS:
|
||||||
{
|
{
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user