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 |
}
|