Arduino UNO, 2Schalter, 1LED

Hallo,

stecke wieder in der Sackgasse und kann mir irgendwie mit meinem Programm nicht helfen.

Es geht um eigentlich etwas ganz simples, scheitere jedoch daran kläglich.

Ich habe ein Projekt mit Arduino UNO das der OUTPUT(eine LED) durch 2 INPUTS(Schalter) eingeschaltet wird. Wobei die Reihenfolge der eingeschalteten Schalter wichtig ist. Sprich zuerst der erste Schalter wird eingeschalten und dann der zweite Schalter erst dannach soll die LED leuchten.

Ich habe mir das so vorgestellt das ich beim ersten Schalter eine if-abfrage mache(ob gedrückt) und dann denn Zustand speichere. Beim zweiten Schalter müsste irgendwie der Zustand miteinbezogen werden.

also:

void loop() {

  buttonState = digitalRead(buttonPin);
  buttonState1 = digitalRead(buttonPin1);
  
  val = digitalRead(buttonPin);
  int reading= 0;

  if(buttonState == HIGH ){
    reading = 1;
  } 
  if(reading == 1 && buttonState1 == HIGH){
    digitalWrite(ledPin, HIGH);
  }
}

lg Greg

Ich habe mir das so vorgestellt das ich beim ersten Schalter eine if-abfrage mache(ob gedrückt) und dann denn Zustand speichere. Beim zweiten Schalter müsste irgendwie der Zustand miteinbezogen werden.

Richtig!
Und deswegen nennt man das, was du bauen willst einen Zustands Automaten, State Machine, oder Endlicher Automat.
Dazu gibts hier, im forum, schon etliche Threads.

Also nach langem hin und her habe ich die Funktion millis() benützt um mein Problem (teilweise) zu lösen.

Hier ist mein Code:

const int buttonPin = 2;     
const int ledPin =  13;      
const int buttonPin1 = 4;


int buttonState = 0; 
int buttonState1 = 0;

int reading = 0;
unsigned long time;

void setup() {

  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin, INPUT);

  Serial.begin(9600);
}

void loop() {
  buttonState = digitalRead(buttonPin);
  buttonState1 = digitalRead(buttonPin1);
 
   if(buttonState == HIGH ){
    reading = 1;
    } 

    if(buttonState1 == HIGH){
      time = millis();
      }
      

    if(reading == 1 && buttonState1 == HIGH){
     digitalWrite(ledPin, HIGH);
     } 
     else if((time > 0) && (buttonState1 == LOW)){
       digitalWrite(ledPin,LOW);
       reading= 0;
       }
     
     Serial.println(time);
     delay(500);  
     
}

Es macht das was es soll. Button1 wird gedrückt der Zustand wird gespeichert. Dannach wird der zweite Pushbutton gedrückt und die LED leuchtet. Wenn ich den zweiten Pushbutton loslasse erlischt die LED und der Vorgang beginnt von neu, sprich wieder button1 und dannach button2 drücken, usw...

Alles schön und gut, nun die millis-Funktion beginnt nach paar Stunden wieder von neu zu zählen. Das möchte ich aber nicht.

Gibt es eine möglichkeit die millis-Funktion zu resten ??
habe veruscht die variable time= 0; zu setzen aber das hilft nicht :frowning:

mfg Greg

Alles schön und gut, nun die millis-Funktion beginnt nach paar Stunden wieder von neu zu zählen. Das möchte ich aber nicht.

Naja, millis laufen nach etwa 49,7 Tagen über und fangen wieder bei Null zu zählen an, das ist doch deutlich mehr als nach "ein paar Stunden". Lässt sich leider nicht verhindern der Überlauf. Auf Null setzen kann man diesen Zähler z.B. durch einen Reset des Arudino. Aber du könntest natürlich einen eigenen Zähler machen, den kannst du dann beliebig oft auf Null setzen.

Naive Frage: Warum willst du denn millis auf Null setzen?

Es könnte ja sein das bei einem Überlauf gerade wenn nötig ist die 0 auftaucht und die Funktion die das abfängt eben nicht abfängt.

Aber ich könnte natürlich schreiben timer = millis()+1; und somit ist der Wert nie null oder ?

Aber du könntest natürlich einen eigenen Zähler machen, den kannst du dann beliebig oft auf Null setzen.

Ist da RTC(Hardware) gemeint ? Oder gibt es einen anderen Zähler noch ?

Ich möchte den Code mit Standart-Funktionien auf Arduino UNO modelieren denn später soll es auf Attiny45 landen.

mfg Greg

Hallo Greg,
bitte sei mir nicht böse, aber ich glaube nicht, daß Dein Sketch macht, was Du glaubst, was er tut.

d4rkdr4g0n1:
Also nach langem hin und her habe ich die Funktion millis() benützt um mein Problem (teilweise) zu lösen.

    if(buttonState1 == HIGH){
      time = millis();
      }
...
if((time > 0)
...      

     delay(500);

Mir erschließt sich der Sinn diese Codes nicht. Üblicherweise nutzt man if(currentMillis - previousMillis >= interval). In diesem Fall macht dann auch der Überlauf von millis() nichts.

d4rkdr4g0n1:
Ist da RTC(Hardware) gemeint ? Oder gibt es einen anderen Zähler noch ?

Mit RTC hat das nicht zu tun. es ist einfach zaehler++; gemeint. Mit millis() zählst Du den Zähler bis zu seinem Maximalwert und setzt ihn dann wieder auf 0. Ist aber mit der richtigen Nutzung von millis() s. o. nicht notwendig.

Mir erschließt sich der Sinn diese Codes nicht.

Ich dachte mir wenn ich pushbutton1 drücke dann kommet er in die if-anweisung und startet zu zählen.

Vielleicht gibts bessere Methode um zu überprüfen wann man welchen Schalter gedrückt hat.
Wäre sehr denkbar mir dann den Weg zu zeigen.

if(currentMillis - previousMillis >= interval)

Diesen code-schnippsel verstehe ich nicht zu 100% deswegen habe ich den nicht in meinem Skech miteinbezogen.

d4rkdr4g0n1:

if(currentMillis - previousMillis >= interval)

Diesen code-schnippsel verstehe ich nicht zu 100% deswegen habe ich den nicht in meinem Skech miteinbezogen.

Das solltest du aber versuchen!

Vielleicht gibts bessere Methode um zu überprüfen wann man welchen Schalter gedrückt hat.
Wäre sehr denkbar mir dann den Weg zu zeigen.

Es dreht sich nicht um den Button, sondern um deine etwas seltsame Art der Zeitverwaltung.

Nachtrag:
Erst muss Button A gedrückt (und festgehalten) werden.
Dann muss Button B gedrückt (und festgehalten) werden.
LED leuchtet, bis einer der Buttons losgelassen wird.

const int buttonA = 2;     
const int buttonB = 4;
const int ledPin  = 13;  
const unsigned long entprellzeit = 10;



enum AutomatenZustand {Start,WaitForA,WaitForB,Activ};
unsigned long lastHit = millis();
AutomatenZustand zustand = Start;




void setup() 
{
  pinMode(ledPin, OUTPUT);
  pinMode(buttonA, INPUT);
  pinMode(buttonB, INPUT);
  // Serial.begin(9600);
}

void loop() 
{
    automat();   
}






void automat()
{
 bool buttonStateA = digitalRead(buttonA);
 bool buttonStateB = digitalRead(buttonA); 
 unsigned long currentTime = millis();
 
 switch(zustand)
 {
   case Start :  
                 digitalWrite(ledPin,LOW);
                 lastHit = currentTime;
                 if(!(buttonStateA || buttonStateB))
                 {
                   zustand = WaitForA;
                 }
                 break;
                 
   case WaitForA :  
                 if(buttonStateB)
                 {
                   zustand = Start;
                 }else
                 {
                   if(buttonStateA)
                   {
                     if(currentTime - lastHit > entprellzeit)
                     {
                       zustand = WaitForB;
                     }  
                   }else
                   {
                     lastHit = currentTime;
                   }
                 }  
                 break;
                 
   case WaitForB :  
                 if(!buttonStateA)
                 {
                   zustand = Start;
                 }else
                 {
                   if(buttonStateB)
                   {
                     if(currentTime - lastHit > entprellzeit)
                     {
                       digitalWrite(ledPin, HIGH);
                       zustand = Activ;
                     }  
                   }else
                   {
                     lastHit = currentTime;
                   }
                 }  
                 break;
                 
   case Activ :  
                 if(!(buttonStateA && buttonStateA))
                 {
                   zustand = Start;
                 }  
                 break;
                 
 }  
}

ungetestet

d4rkdr4g0n1:

if(currentMillis - previousMillis >= interval)

Diesen code-schnippsel verstehe ich nicht zu 100% deswegen habe ich den nicht in meinem Skech miteinbezogen.

Da hast Du Dein Grundproblem erkannt, darum setze ich bei dieser Frage an. Die Lösung weicht allerdings etwas ab, um es leichter erklären zu können:

Stell Dir vor, wir verabreden uns zu einem Treffen in fünf Minuten. Was passiert?

  • Du schaust auf die Uhr, um die aktuelle Zeit zu ermitteln und addierst fünf Minuten => Zeit der Verabredung.
  • Du wartest, bis die aktuelle Zeit auf Deiner Uhr mit der der Zeit der Verabredung übereinstimmt. Wir treffen uns.

Zu 1.: Zeit_der_Verabredung = aktuelle_Zeit + fünf_Minuten

Zu 2.: Wenn aktuelle_Zeit == Zeit_der_Verabredung dann "Hallo!"

Mit RTC könntest Du das so machen.

Ohne RTC brauchst Du Dir nur zu überlegen, daß die Zeit auf Deiner Uhr die Sekunden, Minuten und Stunden seit Mitternacht anzeigt. millis() zeigt die Millisekunden seit Reset an. Für die Verabredung "in fünf Minuten" ist das aber nicht relevant, wann die Zeitzählung startet. Deine Uhr könnte Winterzeit zeigen, meine Sommerzeit oder auch vollkommen falsch gehen, wir würden uns dennoch in fünf Minuten treffen, weil es sich um eine relative Zeitangabe handelt.

Das jetzt in millis (Intervall = fünf Minuten):

Zu 1.: Zeit_der_Verabredung = millis() + Intervall;

Zu 2.: if (millis() == Zeit_der_Verabredung) {Serial.println("Hallo");}

Für den (schlechten) Fall, Dein Programm sollte länger als eine Millisekunde für loop() benötigen, schreibt man besser:

Zu 2.: if (millis() >= Zeit_der_Verabredung) {Serial.println("Hallo");}

Bekommst Du das in einen Sketch?

PS.: Eines meiner ersten Programme enthielt
zaehlerMillisekunden++;
if (zaehlerMillisekunden >= 1000) {zaehlerMillisekunden=0; zaehlerSekunden++;}
delay(1);

Deine Gedankengänge sind mir also durchaus bekannt.

Danke für die ausführliche Erklärung. Bin noch ein blutiger Anfänger wenn ein Stück Code unverstädnlich ist dann demotiviert das sehr.

Nichtsdestotrotz bekomme ich es weiter hin nicht 2 pushbuttons so zu steuern wie ich es möchte. Bin schon echt am verzweifeln. :confused:

Also noch einmal zur meiner Aufgabenstellung:

1)buttonA wird gedrückt los gelassen
2)buttonB wird gedrückt und gehalten
3)erst dann soll die LED leuchten
4)buttonB wird losgelasen und wieder das selbe spiel von Anfang an.

Wichtig ist die Reihenfolg und mit dieser habe ich die meisten Probleme.

Mein gedankengang dazu:

ad 1) buttonA:

if(buttonA !=lastState){
                      if(buttonA == HIGH){
                       if(ledStateA == HIGH){
                         ledStateA = LOW;
                       else{
                         ledStateA = HIGH;
                         }
                       }
                     }
          lastState = buttonA;

}

Somit toggle ich den buttonA

ad 2) buttonB:

if(buttonB == HIGH){
          ledStateB = HIGH;
         }
          else{
          ledStateB = LOW;
         }

hier wird nur überprüft ob mein ButtonB gedrückt ist

ad 3)output,ledPin

if(ledStateA == HIGH && ledStateB == HIGH){
                 digitalWrite(ledPin,HIGH);
}
else{
digitalWrite(ledPin,LOW);
}

ad 4) Hier wie oben erwähnt habe ich das größte Problem denn wie gesagt die Reihenfolge muss stimmen.
Und mit millis()-Funktion bin ich gescheitert. Dannach habe ich mir überlegt, was eigentlich auf das selbe in diesem BSP hinausläuft, dass ich einen counter bei buttonB einbaue. Aber leider alles was ich gemacht bzw. versucht habe hat nicht funktioniert.

Wie könnte man dieses Problem elegant lösen ?

lg Greg

Wie könnte man dieses Problem elegant lösen ?

combie:
Und deswegen nennt man das, was du bauen willst einen Zustands Automaten, State Machine, oder Endlicher Automat.
Dazu gibts hier, im forum, schon etliche Threads.

Beispiel für einen endlichen Automaten.

1)buttonA wird gedrückt los gelassen
2)buttonB wird gedrückt und gehalten
3)erst dann soll die LED leuchten
4)buttonB wird losgelasen und wieder das selbe spiel von Anfang an.

Oh!
Eine neue Anforderung!
Das los lassenvon ButtonA , ist in meinem Code nicht drin.
Und in WaitForB muss dann natürlich der ButtonA ignoriert werden.

Also noch 1 bis 2 Zustände mehr einführen....

Du wirst dich, zusätzlich zu dem millis() Problem, noch mit endlichen Automaten beschäftigen dürfen.

Also noch 1 bis 2 Zustände mehr einführen....

DerName für das Konzept "endlicher Automat" soll eigentlich nicht abschrecken, sondern Hoffnung geben.

Auch wenn es hinterher deutlich umfangreicher wird als anfangs gedacht, geht es immer nur um endlich viele Zustände. :wink:

@ combie danke für deinen automatenzustand Beispiel dadurch konnte ich endlich mein Problem lösen !! 8)

Hier mein Code:

const int buttonA = 2;
const int buttonB = 4;
const int ledPin = 13;

enum AutomatenZustand {START,WaitForA,WaitForB,ACTIVE};
AutomatenZustand zustand = START;

int ledState = LOW;
int aktiverZustand = 0;
unsigned long previousMillis = 0;
const long interval = 2000;


void setup() {
  pinMode(ledPin,OUTPUT);
  pinMode(buttonA , INPUT);
  pinMode(buttonB, INPUT);
  

}

void loop() {
    automat();
}

void automat() {
   int buttonStateA = digitalRead(buttonA);
   int buttonStateB = digitalRead(buttonB);
   
   unsigned long currentMillis = millis();

   switch(zustand){
           case START:
                       ledState = LOW;
                       digitalWrite(ledPin,ledState);
                       if(buttonStateA == LOW && buttonStateB == LOW){
                        zustand = WaitForA;
                       }
                       
                       break;
            case WaitForA:
                       if(buttonStateA == HIGH){  
                        zustand = WaitForB;
                        }
                       break;
                   
             case WaitForB:
                       if(buttonStateB == HIGH){
                         ledState = HIGH;
                         digitalWrite(ledPin,ledState);
                         zustand = ACTIVE;
                         }
                         break;
                         
            case ACTIVE:
                        if(buttonStateB == LOW){
                         if(currentMillis - previousMillis >= interval){
                           previousMillis = currentMillis;
                           zustand = START;  
                           }
                         }
                         break;
                      
     
     }
  }

mfg Greg

Ja, Danke für die Blumen, und Glückwunsch!