Blinken ohne delay() mit 2 Taster und 2 LEDs

Hallo,

ich bin grade dabei für mein Auto ein kleines Projekt zu realisieren, jedoch stehe ich vor einem kleinen Rätsel. Ich bin noch ein Arduino-Anfänger, und hab mich erst in den letzten Tagen wirklich da reingearbeitet , jedoch komme ich nicht weiter. Folgendes ist der Plan:

  1. Wenn ich Taster 1 drücke, fängt LED1 an zu blinken.
  2. Sobald ich Taster 2 drücke, hört LED1 auf zu blinken und leuchtet nur noch, jedoch fängt dann LED2 an zu blinken

Ich muss dieses Projekt ja ohne delay() machen da ja sonst die 2. Tasterabfrage nicht gemacht werden kann. Jedoch komme ich eben da nicht weiter.

Wie kann ich das am einfachsten realisieren?

Dann zeig mal deinen Sketch. Basics durcharbeiten, vorallem Blink Without Delay.

Erstmal alle Zustände auflisten, welche das System annehmen können soll. Dann alle Übergangsbedingungen zwischen den Zuständen definieren.

Das Ganze nimmst du dann und formulierst einen endlichen Automaten.

Also das ist der Code den ich bis jetzt geschrieben hab:

const int taster1 = A3; // Pins
const int taster2 = A0;
const int led1 = 10;
const int led2 = 8;

int ledState = LOW;
unsigned long previousMillis = 0;
const long interval = 1000;

void setup()
{
pinMode(taster1, INPUT);
pinMode(taster2, INPUT);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
}

void loop()
{
unsigned long currentMillis = millis();

if (digitalRead(taster1) == HIGH)
{
if (currentMillis - previousMillis >= interval) {

previousMillis = currentMillis;

if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}

digitalWrite(led1, ledState);
}
}

else if (digitalRead(taster2) == HIGH)
{
digitalWrite(led1, HIGH);

if (currentMillis - previousMillis >= interval) {

previousMillis = currentMillis;

if (ledState == LOW)
{
ledState = HIGH;
}

else
{
ledState = LOW;
}
digitalWrite(led2, HIGH);
}
}
}

Blink_without_delay___mit_2_Tastern.ino (973 Bytes)

Das sieht doch schon fast gut aus…

Ein Automat könnte in etwa so aussehen:

const byte taster1 = A3;  
const byte taster2 = A0;  
const byte led1 = 10;
const byte led2 = 8;

enum Zustand {start,blink1,blink2};

Zustand zustand = start;
unsigned long letzteTaste = 0; //Tastenprellen
const unsigned long interval = 20; //Tastenprellen

void setup() 
{
  pinMode(taster1,INPUT);
  pinMode(taster2,INPUT);
  pinMode(led1,OUTPUT);
  pinMode(led2,OUTPUT);
}

void automat()
{
  bool taste = false;
  switch(zustand)
  {
    case start :  digitalWrite(led1,0);
                  digitalWrite(led2,0);
                  taste = digitalRead(taster1);
                  if(!taste) letzteTaste = millis();
                  if(taste && millis()-letzteTaste>interval)
                  {
                    zustand = blink1;
                  }
                  break;
  
    case blink1:  digitalWrite(led1,(millis()%1000)<500);
                  digitalWrite(led2,0);
                  taste = digitalRead(taster2);
                  if(!taste) letzteTaste = millis();
                  if(taste && millis()-letzteTaste>interval)
                  {
                    zustand = blink2;
                  }
                  break;
  
    case blink2:  digitalWrite(led1,1);
                  digitalWrite(led2,(millis()%1000)<500);
                  taste = digitalRead(taster2);
                  if(!taste) zustand = start;
                  break;
  }  
}

void loop() 
{
  automat();
}

ungetestet

combie: Das Ganze nimmst du dann und formulierst einen endlichen Automaten.

Thumbs up!!

jonah123: 1. Wenn ich Taster 1 drücke, fängt LED1 an zu blinken. 2. Sobald ich Taster 2 drücke, hört LED1 auf zu blinken und leuchtet nur noch, jedoch fängt dann LED2 an zu blinken

Und was soll danach passieren?

Viele Dank erstmal für die Antworten.

Also das ist nur ein kleiner Baustein für eine größere Sache, undzwar baue ich für mein Auto einen Keyless Start Button. im Grundsatz nehme ich einen RFID Reader, einen Fingerabdrucksensor und 4 Taster, die jeweils beleuchtet sind. Sobald ein HIGH Signal vom RFID Reader oder vom Fingerabdrucksensor kommt, fängt die Led1 im 1. Taster an zu blinken. Drückt man diesen Taster, leuchtet diese Led nur noch normal, und die Led im 2. Taster fängt an zu blinken. Gleichzeitig wird ein Relais geschaltet, welches das Auto auf die "ACC" Position bringt. Sobald Taster 2 gedrückt wird, lautet auch diese nur noch Normal und eine Led im 3. Taster fängt an zu blinken. Ein Relais schaltet die Zündung an. Der 3. Taster ist der Start - Engine Taster, welcher den Motor anlässt. Ein letzter Taster Schaltet alle Led und Relais aus. (RFID und Fingerabdruck hab ich noch nicht, und baue ich auf separate Arduinos, ich simuliere das HIGH Signal mit einem Taster)

Also :

  1. HIGH Signal --> Led1 blinken, Relais1 an
  2. Taster 1 --> Led1 leuchten, Led2 blinken, Relais2 an
  3. Taster 2 --> Led1 bleibt an, Led2 leuchten, Relais3 an
  4. Taster 3 --> Led1 bleibt an, Led2 bleibt an, Relais4 schaltet solange ich den Taster gedrückt halte
  5. Taster 4 --> Led1 aus, Led2 aus , alle Relais aus

Zu dem Code von Combie:

Der 1. Schritt funktioniert super, jedoch beim 2. Schritt leuchtet Led1 und blinkt Led2 nur so lange, wie ich den Taster gedrückt halte, kannst du mir sagen wie ich das ändern kann?

Wenn du einen längeren Ablauf mit mehreren Zuständen hast, dann bietet sich wirklich die Statemachine bzw. der endliche Automat an.

D.h. du beschreibst erstmal verbal deine Zustände, was wird im jeweiligen Zustand gemacht, und wie kommt man in einen anderen Zustand.

Das hat Agmue hier gut beschrieben: Anleitung: Ein endlicher Automat entsteht

Ist dieser endliche Automat "einfach" eine Switch-Case Funktion?

ja, codiert wird das üblicherweise als Switch Case.

Ein Entwurf zu deiner statemachine könnte z.B. so aussehen:

Zwischenablage01.jpg

jonah123: Ist dieser endliche Automat "einfach" eine Switch-Case Funktion?

In den einfachen Versionen ja. Kann man auch anders machen.

Ist der Anfang prinzipiell richtig? Das was in // steht, füge ich noch ein.

const int high = A0;
const int taster1 = A1;
const int taster2 = A2;
const int taster3 = A3;
const int taster4 = A4;
const int led1 = 2;
const int led2 = 3;
const int led3 = 4;

enum ZUSTAENDE {Wait, Start, ACC, Ignition, Enginestart, Enginestartoff, OFF };
byte zustand = Wait;

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
}

void loop() {
  switch (zustand) {
    case Wait:
      if (digitalRead(high) == HIGH) 
      {
        zustand = Start;
      }
      break;
      
    case Start:
       
      //led 1 blinken
      if (digitalRead(taster1) == HIGH);
      {
        zustand = ACC;
      }
        
    break;
    
    case ACC:
      digitalWrite(led1, HIGH);
    //digitalWrite(accrelais, HIGH);
    //led2 blinken;  
      if (digitalRead(taster2) == HIGH);
      {
        zustand = Ignition;
      }
      break;
    case Ignition:
      digitalWrite(led1, HIGH);
      digitalWrite(led2, HIGH);
    //digitalWrite(accrelais, HIGH);  
    //digitalWrite(ignitionrelais, HIGH);
    //led 3 blinken
      if (digitalRead(taster3) == HIGH);
      {
        zustand = Enginestart;
      }
      break;
    
  }
  }

Soll das in ein richtiges Kfz oder ist das nur eine Demo?

jonah123: Ist der Anfang prinzipiell richtig?

Ja, ich denke, du hast das Prinzip erkannt. Zum debuggen kannst du überall Serial.println() mit einfügen, damit du auf dem Seriellen Monitor siehst, wo sich dein Automat bewegt. (in dem Falle, und nur im dem ist dann auch ein delay() erlaubt, um die Ausgabe zum Testen einzubremsen)

@ElEspanol : also Momentan ist es noch eine Demo, jedoch will ich es erstmal auf längere Zeit testen ob es zuverlässig funktioniert aber später soll es wirklich in mein KFZ

@guntherb : Vielen Dank für die Tipps, hab mal wieder was neues gelernt !!! Ich geb nochmal Rückmeldung wenn ich fertig bin!

jonah123: ... aber später soll es wirklich in mein KFZ

Dann vergiß bitte nicht, das von TÜV und Versicherung abnicken zu lassen, denn Versicherer sind ja durchaus erfinderisch, nicht bezahlen zu müssen, wenn in Dein Auto eingebrochen wurde.

Mit der Versicherung ist klar, jedoch irrelevant aufgrund fehlender Teil- bzw. Vollkaskoversicherung, da sowieso keine Entschädigung bei Diebstahl gezahlt wird oder?

Muss man es sicher beim TÜV eintragen lassen?

Ich habe grade folgenden Code vervollständigt:

const int high = A0;
const int taster1 = A1;
const int taster2 = A2;
const int taster3 = A3;
const int taster4 = A4;
const int led1 = 2;
const int led2 = 3;
const int led3 = 4;
const int relais1 = 5;
const int relais2 = 6;
const int relais3 = 7;

enum Zustand { Wait,Start,ACC,Ignition,Enginestart,Enginestartoff,OFF };
Zustand zustand = Wait;

void setup()
{
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  
}
void loop() 
{
  
  switch (zustand) 
  {
    
    case Wait:
      
      if (digitalRead(high) == HIGH) 
      {
        zustand = Start;
        
      }
      break;
      
    case Start:
      
      digitalWrite(led1, HIGH);               // Auf blinken ändern
      if (digitalRead(taster1) == HIGH);
      {
        zustand = ACC;
      }
        
    
    
    case ACC:
      
      digitalWrite(led1, HIGH);
      digitalWrite(relais1, HIGH);
      digitalWrite(led2, HIGH);               // Auf blinken ändern 
      if (digitalRead(taster2) == HIGH);
      {
        zustand = Ignition;
      }
      break;
    case Ignition:
     
      digitalWrite(led1, HIGH);
      digitalWrite(led2, HIGH);
      digitalWrite(relais1, HIGH);  
      digitalWrite(relais2, HIGH);
      digitalWrite(led3, HIGH);               // Auf blinken ändern
      if (digitalRead(taster3) == HIGH);
      {
        zustand = Enginestart;
      }
      break;
    case Enginestart:
      
      digitalWrite(led1, LOW);
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      digitalWrite(relais3, HIGH);
      if (digitalRead(taster3) == LOW);
      {
        zustand = Enginestartoff;
      }
      break;

    case Enginestartoff:
    
       digitalWrite(led1, HIGH);
       digitalWrite(led2, HIGH);
       digitalWrite(led3, HIGH);
       if (digitalRead(taster4) == HIGH);
       {
        zustand = OFF;
       }
       break;

     case OFF:
     
        digitalWrite(led1, LOW);
        digitalWrite(led2, LOW);
        digitalWrite(led3, LOW);

        zustand = Wait;   
    
         
        
    
  }
  }

Jedoch hab ich ihn ausprobiert, und es passiert gar nichts von dem was ich will. Das einzige was passiert, es leuchten LED1 und LED2 Solange ich ihm das erste "high" Signal gebe.. Hat jemand eine Idee was ich falsch gemacht habe?

du musst unbedingt das debuggen lernen!

Das ist eine Methode, zu sehen, wie der Code abgearbeitet wird, welchen Wert eine Variable wo hat etc.
Beim Arduino ist die einfachste Möglichkeit zum Debugging die Ausgabe von Werten über den Seriellen Monitor.

Du solltest also hinter jeden case Befehl einen Serial.print() setzen, der dir Ausgibt, wo der Code steht.
also:

   case Start:
    Serial.println("Start");
...

    case Ignition:
    Serial.println("Ignition");

Wenn du das getan hast, und die Ausgabe ansiehst, wirst du folgendes feststellen:

Ausgabe / Aktion
Wait
Wait
Wait
Wait / "high" signal anlegen
Start
ACC
ACC
ACC
...

Der Code springt also aus “Wait” raus, rennt durch “Start” durch und geht sofort in “ACC”.
Wenn du das weißt, kannst du auch den Fehler schnell finden…

Noch ein Hinweis zu den LEDs:
Ich würde die Ansteuerung aus der Statemachine rausnehmen. In den case-Pfade nur eine Statusvariable setzen: “LED1 = Blinken; LED2 = AN” und dann ausserhalb der Statemachine eine Funktion, die die LEDs entsprechend ansteuert.

So eine Funktion könnte z.B. so aussehen:

void LEDs_setzen(){
  static unsigned long lastchange = 0;
  const int Blinkdauer = 500;
  static boolean BlinkHL;
  if (millis()- Blinkdauer > lastchange){    // Blinkrhytmus erzeugen
    lastchange = millis();
    BlinkHL = !BlinkHL;
  }  
  for (int i = 0; i<4; i++){
    if (LED_Status[i] == AN)      digitalWrite(LED_PIN[i],HIGH);
    if (LED_Status[i] == AUS)     digitalWrite(LED_PIN[i],LOW);
    if (LED_Status[i] == BLINK)   digitalWrite(LED_PIN[i],BlinkHL);
  }
}

ungetesteter Code!

dafür musst du die LED-Pins in einem Array vereinbaren, und auch ein Array für den Zustand der einzelnen LEDs:

const int LED_PIN[4] = {2,3,4,5};
byte LED_Status[4];
enum LED_Stati {AN, AUS, BLINK  };

in der loop steht dann nur:

LEDs_setzen();

und die einzelnen LEDs werden geschaltet mit

LED_Status[1] = BLINK;

Halte uns da auf dem laufenden, weil so etwas ähnliches würde mich evtl. für mein Trike interessieren. Da will ich auch die Instrumentierung ändern und könnte sowas mit einbauen. Das Gefummel mit dem Zündschlüssel links unten ist nämlich Mist.

P.S.: Hinweise auf die StVO sind unnötig. Erstens weiß ich, was ich tue, zweitens gilt die für mich eh nicht ;)