ich habe mal wieder etwas Zeit gefunden, nach dem Nachwuchs, mich hinzusetzen und ich würde gerne eine Blinkersteuerung über Taster realisieren.
Folgende Vorstellungen habe ich zu diesem Projekt:
3 Verschiedene Modi:
kurzer Tastendruck ca. 0.8 Sekunden (Überholblinken 5 Sekunden, dann Blinker aus)
mittlerer Tastendruck ca. 0.8-1,5 Sekunden (Abbiegeblinken 30 Sekunden an, oder aus, wenn Taster erneut betätigt wird)
langer Tastendruck über 1.5 Sekunden (dauerhaft an, außer wenn Taster erneut gedrückt wird)
Ich habe mich hierzu auch schon mit Blinkenohne Delay vertraut gemacht und brauche ja die Millis auch, um die Tastendrucklänge zu überwachen.
So nun zu meinem Problem, ich habe schon begonnen, doch komme ich leider nicht weiter, hier der Code.
Würdet ihr die Modi anders machen, gibt es vielleicht eine Art die einfacher zu machen?
int ledState = LOW; // LED-Status
int TasterValue = HIGH; // Taster-Status
bool BlinkValue = false; // Blink-Status
unsigned long previousMillis = 0;
uint8_t status = 0; //Tasterstatus
const byte TasterPin = 2; // Taster an Pin 2 und GND
const long interval = 800; // Blinkintervall
const long WartezeitBlinken1 = 4000;
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // LED Pin 13
pinMode(TasterPin, INPUT_PULLUP); // Taster mit Pullup
Serial.begin(9600); // Serielle Kommunikation starten
}
void loop() {
if (TasterValue == LOW) { // Taster wurde gedrückt
unsigned long buttonPressStart = millis(); // Zeitpunkt des Tastendrucks speichern
Serial.println("Taster gedrückt");
while (digitalRead(TasterPin) == LOW) {
// Warten bis der Taster losgelassen wird oder bis zur maximalen Wartezeit
if (millis() - buttonPressStart >= 1500) {
// Modus 3: Taster länger als 1,5 Sekunden gedrückt halten
Serial.println("Modus 3 aktiviert");
BlinkValue = true; // LED blinkt, bis der Taster erneut gedrückt wird
while (digitalRead(TasterPin) == LOW) {
// Warten bis der Taster erneut kurz gedrückt wird
}
Serial.println("Modus 3 deaktiviert");
BlinkValue = false;
}
}
// Modus 1: Taster kurz gedrückt
if (millis() - buttonPressStart < 800) {
Serial.println("Modus 1 aktiviert");
BlinkValue =! BlinkValue;
}
Serial.println("Modus 1 deaktiviert");
}
// Modus 2: Taster zwischen 0,8 und 1,5 Sekunden gedrückt
if (millis() - buttonPressStart >= 800 && millis() - buttonPressStart < 1500) {
Serial.println("Modus 2 aktiviert");
BlinkValue = true;
while (digitalRead(TasterPin) == HIGH) {
// Warten bis der Taster erneut kurz gedrückt wird oder bis zur maximalen Wartezeit
if (millis() - buttonPressStart >= 40000) {
Serial.println("Modus 2 deaktiviert (Timeout)");
break;
}
}
Serial.println("Modus 2 deaktiviert");
BlinkValue = 1;
}
}
// Tasterstatus aktualisieren
TasterValue = digitalRead(TasterPin);
unsigned long currentMillis = millis();
if (BlinkValue == true) {
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(LED_BUILTIN, ledState);
}
} else {
digitalWrite(LED_BUILTIN, LOW);
}
// Ende BlinkWithoutDelay....
}
Nicht wirklich.
Dein while passt nicht zum withoutDelay-Konzept.
Führt mindestens dazu dass der Blinker frühestens startet, wenn der Taster wieder losgelassen wurde. Und ob fehlendes Taster-Entprellen stört, muss ich mir noch überlegen.
Ausserdem brauchst du eine Flankenerkennung, wann der Tastendruck gestartet und wann er beendet wurde.
Und was passiert, wenn du dir überlegst, das 30sec-Blinken abzustellen, aber den Taster drückst, wenn deine Automatik das gerade selbst gemacht hat? Dann startet das Blinken wieder und es blinkt 5 sec länger als du wolltest.
Ob du 1,3 oder 1,6 sec gedrückt hast, merkst du --wenn überhaupt-- erst nach ca 30 sec
Kürzer als 5 sec Blinken geht übrigens garnicht.
Eine Verriegelung Blinker links/rechts vermisse ich auch.
Keine Ahnung, wie du das zugelassen kriegst.
Der Arduino-Sketch ist sicher das einfachste an der Sache.
Ich werde mich jetzt mal in das Thema State Maschine einlesen, der Link vom Vorredner sieht sehr vielversprechend aus.
Oder gibt es Einwände, von deiner Seite, dass es keinen Sinn macht?
Libs sind immer einfacher. Wenn man es lernen will, sollte man es ohne Lib versuchen. Vorallem, wenn blinken und Tastenerkennung gleichzeitig laufen müssen
Für die Fallunterscheidenungen würde ich ein Switch/Case verwerden. Für das Entprellen und für den schlauen Timer bietet es sich an das BWOD Beispiel aus dem Idee aufzubohren.
Ich habe genau das versucht so umzusetzen, das Problem ist nur, dass wenn ich in einem case bin, dass ich wenn ich den Taster zum "beenden" drücke, komm blinkt es 4 Sekunden weiter, da ich ja in den Modus "Überholblinken" komme. Gibt es eine Möglichkeit, dies zu vermeiden, wie könnte die einfach aussehen?
Code:
const int buttonPin = 2; // Pin, an dem der Taster angeschlossen ist
const int ledPin = 13; // Pin, an dem die LED angeschlossen ist
unsigned long startTime = 0; // Zeitstempel für Tastendruck
unsigned long duration = 0; // Gemessene Zeitdauer
int currentState = 0; // Der aktuelle Zustand der Zustandsmaschine
unsigned long actionStartTime = 0; // Zeitstempel für den Start der aktuellen Aktion
const unsigned long overtakeDuration = 5000; // Dauer des Überholblinkens (5 Sekunden)
const unsigned long turnDuration = 30000; // Dauer des Abbiegeblinkens (30 Sekunden)
void setup() {
pinMode(buttonPin, INPUT_PULLUP); // Taster-Pin als Eingang mit Pull-Up-Widerstand
pinMode(ledPin, OUTPUT); // LED-Pin als Ausgang
digitalWrite(ledPin, LOW); // LED ausschalten
Serial.begin(9600); // Serielle Kommunikation starten (zur Debugging-Zwecken)
}
void loop() {
int buttonState = digitalRead(buttonPin);
switch (currentState) {
case 0: // Warten auf Tastendruck
if (buttonState == LOW) { // Taster wurde gedrückt
startTime = millis(); // Aktuelle Zeit speichern
digitalWrite(ledPin, HIGH); // LED einschalten
currentState = 1; // Zustand wechseln
Serial.println("Taster gedrückt, LED eingeschaltet");
}
break;
case 1: // Warten auf Loslassen des Tasters
if (buttonState == HIGH) { // Taster wurde losgelassen
duration = millis() - startTime; // Zeitdauer berechnen
currentState = 2; // Zustand wechseln
Serial.print("Taster losgelassen, Zeitdauer: ");
Serial.println(duration);
}
break;
case 2: // Bewertung der Zeitdauer und Vormerkung der Aktion
if (duration >= 0 && duration < 800) {
// Aktion für Überholblinken
actionStartTime = millis();
currentState = 3; // Zustand wechseln
Serial.println("Überholblinken gestartet");
} else if (duration >= 800 && duration < 1500) {
// Aktion für Abbiegeblinken
actionStartTime = millis();
currentState = 4; // Zustand wechseln
Serial.println("Abbiegeblinken gestartet");
} else {
// Aktion für dauerhaftes Blinken
actionStartTime = millis();
currentState = 5; // Zustand wechseln
Serial.println("Dauerhaftes Blinken gestartet");
}
break;
case 3: // Überholblinken
if (millis() - actionStartTime >= overtakeDuration) {
digitalWrite(ledPin, LOW); // LED ausschalten
currentState = 0; // Zurück zum Anfangszustand
Serial.println("Überholblinken beendet");
}
break;
case 4: // Abbiegeblinken
if (buttonState == LOW) { // Taster erneut betätigt
digitalWrite(ledPin, LOW); // LED ausschalten
currentState = 0; // Zurück zum Anfangszustand
Serial.println("Abbiegeblinken abgebrochen");
} else if (millis() - actionStartTime >= turnDuration) {
// Aktion für Abbiegeblinken beenden
digitalWrite(ledPin, LOW); // LED ausschalten
currentState = 0; // Zurück zum Anfangszustand
Serial.println("Abbiegeblinken beendet");
}
break;
case 5: // Dauerhaftes Blinken
if (buttonState == LOW) { // Taster erneut betätigt
digitalWrite(ledPin, LOW); // LED ausschalten
currentState = 0; // Zurück zum Anfangszustand
Serial.println("Dauerhaftes Blinken abgebrochen");
}
// Keine Zeitbegrenzung für dauerhaftes Blinken
break;
}
}
Ich hätte bei dem Rezept nur einen kleinen Einwand: Es fängt erst an zu blinken wenn der Taster losgelassen wird.
Das entspricht nicht meiner Erfahrung mit dem Blinkerhebel beim Auto. Mangels Führerschein Klasse A und Moped kann ich natürlich die Situation beim Zweirad nicht beurteilen.
Als Inhaber der alten Führerscheinklassen 1 und 2 (BRD) kann ich Dir mitteilen, beim Motorrad ist es nicht anders als beim Automobil. Bei Bimetallblinkern kann die erste Leuchtzeit allerdings etwas länger dauern, da das Metall erst erwärmt werden muß. Bei meinem 6 V Käfer war das im Winter merklich.
Die Römer verfuhren nach dem Prinzip "divide et impera" "teile und herrsche", auch beim Programmieren kann eine Aufteilung in kleine Aufgaben hilfreich sein.
So verwende ich eine Funktion zum Tasterentprellen, die ein sauberes logisches Signal liefert. Außerdem läßt eine andere Funktion die LED blinken oder schaltet sie aus.
In der Schleife dann die Schrittkette, wie Du sie vergleichbar auch verwendest hast.
Die LED habe ich auf einen anderen Pin verlegt, weil 13 beim Starten immer mitblinkt, das irritiert mich.
Programm getestet mit UNO
const int buttonPin = 2; // Pin, an dem der Taster angeschlossen ist
const int ledPin = 8; // Pin, an dem die LED angeschlossen ist
const uint32_t UEBERHOLZEIT = 5000; // Überholblinken
const uint32_t ABBIEGEZEIT = 30000; // Abbiegeblinken
void setup()
{
pinMode(buttonPin, INPUT_PULLUP); // Taster-Pin als Eingang mit Pull-Up-Widerstand
pinMode(ledPin, OUTPUT); // LED-Pin als Ausgang
digitalWrite(ledPin, LOW); // LED ausschalten
}
//
void loop()
{
uint32_t jetzt = millis();
static uint32_t startZeit = jetzt;
static uint32_t blinkzeit = UEBERHOLZEIT;
static bool blinkAnforderung = false;
bool tasterStatusAkt = entprellen();
static uint8_t schritt = 0;
switch (schritt)
{
case 0: // Warten auf Tastendruck
if (tasterStatusAkt)
{
blinkAnforderung = true;
startZeit = jetzt;
schritt++;
}
break;
case 1: // Warten auf Loslassen des Tasters
if (!tasterStatusAkt)
{
blinkzeit = UEBERHOLZEIT; // Überholblinken
if (jetzt - startZeit > 800) blinkzeit = ABBIEGEZEIT; // Abbiegeblinken
if (jetzt - startZeit > 1500) blinkzeit = 0; // Dauerblinken
schritt++;
}
break;
case 2: // Festlegen der Blinkzeit
if (tasterStatusAkt)
{
blinkAnforderung = false;
schritt++;
}
if (blinkzeit > 0)
{
if (jetzt - startZeit >= blinkzeit)
{
blinkAnforderung = false;
schritt++;
}
}
break;
case 3:
if (!tasterStatusAkt)
{
schritt = 0;
}
break;
default:
schritt = 0;
break;
}
blinken(blinkAnforderung);
}
//
void blinken(bool merker)
{
static uint32_t vorhin = millis();
const uint32_t blinkIntervall = 200;
if (merker)
{
if (millis() - vorhin >= blinkIntervall)
{
vorhin = millis();
digitalWrite(ledPin, !digitalRead(ledPin));
}
} else {
digitalWrite(ledPin, LOW);
}
}
//
bool entprellen()
{
bool neu = !digitalRead(buttonPin);
static bool alt = neu;
static uint32_t vorhin = millis();
const uint32_t entprellzeit = 50;
static bool rueckgabe = LOW;
if (millis() - vorhin >= entprellzeit)
{
if (neu != !alt)
{
rueckgabe = neu;
vorhin = millis();
}
}
alt = neu;
return rueckgabe;
}
@wwerner & @agmue es klappt und zwar mit beiden codes! und wenn man schon bei Römer sind, viele Wege führen nach Rom. Vielen Dank euch.
Ich werde aber noch ändern, dass die LED erst blinkt, wenn der Taster wieder losgelassen wurde, da es wirklich ein bisschen irritierend ist wenn man den Taster drückt und die LED schon angeht. Aber jetzt der aktuelle Code:
const int buttonPin = 2; // Pin, an dem der Taster angeschlossen ist
const int ledPin = 13; // Pin, an dem die LED angeschlossen ist
unsigned long startTime = 0; // Zeitstempel für Tastendruck
unsigned long currentTime = 0; // Zeitstempel für Tastendruck
unsigned long duration = 0; // Gemessene Zeitdauer
int currentStateTaster = 0; // Der aktuelle Zustand der TasterZustandsmaschine
int currentStateBlinker = 0; // Der aktuelle Zustand der TasterZustandsmaschine
int currentStateBlinkerArt = 0; // Der aktuelle Zustand der TasterZustandsmaschine
unsigned long actionStartTime = 0; // Zeitstempel für den Start der aktuellen Aktion
unsigned long blinkStartTime = 0; // Zeitstempel für den Start der aktuellen Aktion
const unsigned long overtakeDuration = 4000; // Dauer des Überholblinkens (5 Sekunden)
const unsigned long turnDuration = 30000; // Dauer des Abbiegeblinkens (30 Sekunden)
const unsigned long blinkTime = 800; // Intervall des Blinkens
void setup() {
pinMode(buttonPin, INPUT_PULLUP); // Taster-Pin als Eingang mit Pull-Up-Widerstand
pinMode(ledPin, OUTPUT); // LED-Pin als Ausgang
digitalWrite(ledPin, LOW); // LED ausschalten
Serial.begin(115200); // Serielle Kommunikation starten (zur Debugging-Zwecken)
}
void loop() {
int buttonState = digitalRead(buttonPin);
currentTime = millis();
switch (currentStateTaster) {
case 0: // Warten auf Tastendruck
if ((buttonState == LOW) && (currentStateBlinkerArt == 0)) { // Taster wurde gedrückt
startTime = currentTime; // Aktuelle Zeit speichern
actionStartTime = currentTime;
currentStateTaster = 1; // Zustand wechseln
Serial.println("Taster gedrückt");
}
break;
case 1: // Warten auf Loslassen des Tasters
if (buttonState == HIGH) { // Taster wurde losgelassen
duration = currentTime - startTime; // Zeitdauer berechnen
currentStateTaster = 0; // Zustand wechseln
Serial.print("Taster losgelassen, Zeitdauer: ");
Serial.println(duration);
}
break;
}
switch (currentStateBlinker) {
case 0: // Warten auf Tastendruck
if ((buttonState == LOW) && (currentStateBlinkerArt == 0)) { // Taster wurde gedrückt
blinkStartTime = currentTime; // Aktuelle Zeit speichern
digitalWrite(ledPin, HIGH); // LED einschalten
currentStateBlinker = 1; // Zustand wechseln
Serial.println("Taster gedrückt, LED eingeschaltet");
}
break;
case 1: // Dauerhaftes Blinken ON
if (currentTime - blinkStartTime > blinkTime) {
digitalWrite(ledPin, LOW); // LED einschalten
blinkStartTime = currentTime;
currentStateBlinker = 2; // Zustand wechseln
}
case 2: // Dauerhaftes Blinken OFF
if (currentTime - blinkStartTime > blinkTime) {
digitalWrite(ledPin, HIGH); // LED einschalten
blinkStartTime = currentTime;
currentStateBlinker = 1; // Zustand wechseln
}
}
switch (currentStateBlinkerArt) {
case 0: // Warten auf loslassen des Tasters
if (duration > 0 && duration < 800) {
// Aktion für Überholblinken
currentStateBlinkerArt = 2; // Zustand wechseln
Serial.println("Überholblinken gestartet");
} else if (duration >= 800 && duration < 1500) {
// Aktion für Abbiegeblinken
currentStateBlinkerArt = 3; // Zustand wechseln
Serial.println("Abbiegeblinken gestartet");
} else if (duration >= 1500) {
// Aktion für dauerhaftes Blinken
currentStateBlinkerArt = 4; // Zustand wechseln
Serial.println("Dauerhaftes Blinken gestartet");
}
break;
case 2: // Überholblinken
if (currentTime - actionStartTime >= overtakeDuration) {
blinkenBeenden();
Serial.println("Überholblinken beendet");
}
break;
case 3: // Abbiegeblinken
if (currentTime - actionStartTime >= turnDuration || buttonState == LOW) {
// Aktion für Abbiegeblinken beenden
blinkenBeenden();
currentStateBlinkerArt = 5;
Serial.println("Abbiegeblinken beendet");
}
break;
case 4: // Warten auf Tastendruck
if (buttonState == LOW) { // Taster wurde gedrückt
blinkenBeenden();
currentStateBlinkerArt = 5;
Serial.println("Dauerhaftes Blinken beendet");
}
case 5: // Warten auf Loslassen des Tasters
if (buttonState == HIGH) { // Taster wurde losgelassen
currentStateBlinkerArt = 0;
Serial.println("Taster losgelassen");
}
}
}
void blinkenBeenden() {
digitalWrite(ledPin, LOW); // LED ausschalten
currentStateBlinkerArt = 0; // Zurück zum Anfangszustand
currentStateBlinker = 0;
duration = 0;
}
Vielen Lieben Dank nochmal! Ich finde es wunderbar, dass es Leute wie euch gibt!
Schönen Abend wünsche ich noch.
Man liest sich!