1 | // Verbesserter Fahrradblinker für ESP32
|
2 | // - 3 Taster (INPUT_PULLUP, Taster nach GND)
|
3 | // - 2 LED-Ausgänge (linker/rechter Blinker)
|
4 | // - pro-Taster Debounce
|
5 | // - Serielle Debug-Ausgabe
|
6 |
|
7 | // Pin-Konfiguration (anpassbar)
|
8 | const int buttonLeftPin = 14;
|
9 | const int buttonRightPin = 27;
|
10 | const int buttonWarnPin = 26;
|
11 |
|
12 | const int ledLeftPin = 12;
|
13 | const int ledRightPin = 13;
|
14 |
|
15 | // Blink-Einstellung (ms)
|
16 | unsigned long blinkInterval = 400UL;
|
17 |
|
18 | // --- interne Variablen für Blinken ---
|
19 | unsigned long lastBlinkTime = 0;
|
20 | bool blinkState = false;
|
21 |
|
22 | // --- Zustände ---
|
23 | enum BlinkerState { OFF, LEFT, RIGHT, WARN };
|
24 | BlinkerState currentState = OFF;
|
25 |
|
26 | // --- Debounce pro Taster ---
|
27 | struct Button {
|
28 | int pin;
|
29 | bool stableState; // aktuell entprellter Zustand (true = gedrückt)
|
30 | bool lastRead; // letzte gelesene Roh-Bit (LOW/HIGH als bool)
|
31 | unsigned long lastChangeMillis;
|
32 | unsigned long debounceMillis;
|
33 | };
|
34 |
|
35 | Button btnLeft = { buttonLeftPin, false, HIGH, 0UL, 50UL };
|
36 | Button btnRight = { buttonRightPin, false, HIGH, 0UL, 50UL };
|
37 | Button btnWarn = { buttonWarnPin, false, HIGH, 0UL, 50UL };
|
38 |
|
39 | // Hilfsfunktion: liest einen Button und aktualisiert Debounce
|
40 | bool readButton(Button &b) {
|
41 | bool raw = digitalRead(b.pin); // HIGH wenn nicht gedrückt (INPUT_PULLUP)
|
42 | unsigned long now = millis();
|
43 |
|
44 | if (raw != b.lastRead) {
|
45 | // Signal hat sich geändert -> setze Zeitstempel
|
46 | b.lastChangeMillis = now;
|
47 | b.lastRead = raw;
|
48 | } else {
|
49 | // Wenn das Signal stabil ist länger als debounceMillis, übernehme es
|
50 | if (now - b.lastChangeMillis >= b.debounceMillis) {
|
51 | bool pressed = (raw == LOW); // LOW = gedrückt bei INPUT_PULLUP
|
52 | if (pressed != b.stableState) {
|
53 | b.stableState = pressed;
|
54 | // Rückgabe true bedeutet: Zustand hat sich geändert (Edge)
|
55 | return true;
|
56 | }
|
57 | }
|
58 | }
|
59 | return false;
|
60 | }
|
61 |
|
62 | // Aufruf bei erkannten Tasterereignissen (Edge)
|
63 | void handlePress(BlinkerState pressed) {
|
64 | // Wenn gleicher Modus -> aus, sonst neuen Modus
|
65 | if (currentState == pressed) currentState = OFF;
|
66 | else currentState = pressed;
|
67 |
|
68 | // Reset Blink-Phase damit beim Umschalten sofort sichtbar
|
69 | blinkState = false;
|
70 | lastBlinkTime = millis();
|
71 |
|
72 | Serial.print("Mode -> ");
|
73 | switch(currentState) {
|
74 | case OFF: Serial.println("OFF"); break;
|
75 | case LEFT: Serial.println("LEFT"); break;
|
76 | case RIGHT: Serial.println("RIGHT"); break;
|
77 | case WARN: Serial.println("WARN"); break;
|
78 | }
|
79 | }
|
80 |
|
81 | void setup() {
|
82 | Serial.begin(115200);
|
83 | delay(10);
|
84 | Serial.println("ESP32 Fahrradblinker - Start");
|
85 |
|
86 | // Buttons
|
87 | pinMode(btnLeft.pin, INPUT_PULLUP);
|
88 | pinMode(btnRight.pin, INPUT_PULLUP);
|
89 | pinMode(btnWarn.pin, INPUT_PULLUP);
|
90 |
|
91 | // LEDs
|
92 | pinMode(ledLeftPin, OUTPUT);
|
93 | pinMode(ledRightPin, OUTPUT);
|
94 | digitalWrite(ledLeftPin, LOW);
|
95 | digitalWrite(ledRightPin, LOW);
|
96 |
|
97 | // Initial lesen
|
98 | btnLeft.lastRead = digitalRead(btnLeft.pin);
|
99 | btnRight.lastRead = digitalRead(btnRight.pin);
|
100 | btnWarn.lastRead = digitalRead(btnWarn.pin);
|
101 | btnLeft.stableState = (btnLeft.lastRead == LOW);
|
102 | btnRight.stableState = (btnRight.lastRead == LOW);
|
103 | btnWarn.stableState = (btnWarn.lastRead == LOW);
|
104 | }
|
105 |
|
106 | void loop() {
|
107 | unsigned long now = millis();
|
108 |
|
109 | // --- Buttons prüfen (Debounce) ---
|
110 | // readButton liefert true wenn sich der entprellte Zustand geändert hat
|
111 | if (readButton(btnLeft) && btnLeft.stableState) {
|
112 | // btnLeft.stableState == true bedeutet: gerade gedrückt geworden
|
113 | handlePress(LEFT);
|
114 | }
|
115 | if (readButton(btnRight) && btnRight.stableState) {
|
116 | handlePress(RIGHT);
|
117 | }
|
118 | if (readButton(btnWarn) && btnWarn.stableState) {
|
119 | handlePress(WARN);
|
120 | }
|
121 |
|
122 | // --- Blink-Logik ---
|
123 | if (currentState != OFF) {
|
124 | if (now - lastBlinkTime >= blinkInterval) {
|
125 | blinkState = !blinkState;
|
126 | lastBlinkTime = now;
|
127 | }
|
128 | } else {
|
129 | // Wenn OFF, LEDs aus
|
130 | blinkState = false;
|
131 | }
|
132 |
|
133 | // --- LEDs setzen gemäß Modus ---
|
134 | switch (currentState) {
|
135 | case LEFT:
|
136 | digitalWrite(ledLeftPin, blinkState ? HIGH : LOW);
|
137 | digitalWrite(ledRightPin, LOW);
|
138 | break;
|
139 | case RIGHT:
|
140 | digitalWrite(ledLeftPin, LOW);
|
141 | digitalWrite(ledRightPin, blinkState ? HIGH : LOW);
|
142 | break;
|
143 | case WARN:
|
144 | digitalWrite(ledLeftPin, blinkState ? HIGH : LOW);
|
145 | digitalWrite(ledRightPin, blinkState ? HIGH : LOW);
|
146 | break;
|
147 | case OFF:
|
148 | default:
|
149 | digitalWrite(ledLeftPin, LOW);
|
150 | digitalWrite(ledRightPin, LOW);
|
151 | break;
|
152 | }
|
153 |
|
154 | // Optional: weniger Serielle Ausgabe (nur zum Debug, kann auskommentiert werden)
|
155 | // Serial.print("BlinkState: ");
|
156 | // Serial.println(blinkState);
|
157 | }
|