Taschenlampe mit SOS Funktion

Hallo erstmal,
ich würde gerne wegen einem Schulprojekt eine Taschenlampe mit SOS Funktion programmieren.
Ich versuche zum ersten mal etwas mit dem switch/case zu programmieren und bin deshalb in dem Sinne noch Anfänger.
Die Taschenlampe soll beim anmachen erstmal normales durchgehendes Licht an haben und erst nach Betätigen eines Knopfes die SOS Funktion aufrufen. - Das funktioniert auch
Nach einem weiteren Betätigen soll wieder die erste Funktion aufgerufen werden, aber bei mir läuft dann nur weiterhin die SOS Funktion.
Was mache ich falsch?
Ich würde mich freuen, wenn es hier Leute gibt, die mir helfen können! :slight_smile:

const int ledPin = 12;
const int buttonPin = 11;

int buttonState = 0;
int pushbutton = 0;

void setup(){
  Serial.begin(9600);
  Serial.println("Hello");
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}

void loop() {
  buttonState = digitalRead(buttonPin); 

  if (buttonState == HIGH) {
    pushbutton = +1;
  }
  Serial.println(pushbutton);
  switch(pushbutton) {
    case 1:                        //SOS Funktion
      Serial.println("case 1");
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(250);
      digitalWrite(ledPin, HIGH);
      delay(1000);
      digitalWrite(ledPin, LOW);
      delay(250);
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(3000);
      break;
      
    case 2:                         //von SOS Funktion wieder zurück
      Serial.println("case 2");     //zum durchgehendem leuchten  
      pushbutton = 0;               //durch erneutes Knop drücken
      
    default:                        //durchgehendes leuchten
      digitalWrite(ledPin, HIGH);
  }//Ende switch/case 
}//Ende void loop

Der Code hat mehrere Probleme.

a) diese Zeile macht nicht was du wahrscheinlich möchtest:

pushbutton = +1;

Ich vermute, dass hier pushbutton hochgezählt werden soll. Das ist aber nicht der Fall.
pushbutton wird lediglich auf 1 gesetzt. Deshalb wird pushbutton niemals 2 und case 2 wird niemals ausgeführt.
Das Hochzählen von pushbutton geht z.B. so:

pushbutton++;

oder so

pushbutton = pushbutton +1;

b) Für das Blinken verwendest du delays. Dabei legt das Programm Pausen mit "Nichtstun" ein. Während dieser Zeit wird aber auch der Taster nicht abgefragt, erst nach mehr als 5 Sekunden (5500 Milisekunden) wird der Taster wieder abgefragt. Zum Umschalten müsstest du den Taster also so lange gedrückt halten und noch dazu rechtzeitig loslassen. Das ist fast unmöglich.
Also auch wenn du den Code in a) änderst wird das nicht so funktionieren, wie geplant weil sofort wieder case 1 "aktiv" wird.

Fazit: Du musst deinen Code überdenken.
Du solltest keine delays verwenden. Sieh dir mal millis() an.
Den Taster würde ich auch anders abfragen (Stichwort: Flankenerkennung bzw. (Englisch) state change detection). Es gibt dazu ein Beispiel in der Arduino-IDE (Datei / Beispiele / 2.Digital / StateChangeDetection)

Hier gibt es auch ein paar Beispiele - vielleicht zur Insiration:
http://www.martyncurrey.com/switching-things-on-and-off-with-an-arduino/#Polling-example-05

Vielen Dank für die schnelle Hilfe!
Hmm dann lese ich mich mal durch und versuche es zu verstehen.

uxomm:
Den Taster würde ich auch anders abfragen (Stichwort: Flankenerkennung bzw. (Englisch) state change detection). Es gibt dazu ein Beispiel in der Arduino-IDE (Datei / Beispiele / 2.Digital / StateChangeDetection)

Das ist im Grunde nicht notwendig oder?
Das Problem, was ich jetzt nur noch habe ist das mit dem delay(x), richtig?

Soltanius:
Das ist im Grunde nicht notwendig oder?

Hängt davon ab... :slight_smile:
Beim Abfragen von Tastern ist es häufig wichtiger zu wissen wann ein Taster gedrückt (oder losgelassen) wird und weniger ob er gerade gedrückt/nicht gedrückt ist.

Deine Aufgabe lässt sich auf unterschiedlichen Wegen lösen. Ob Flankenerkennung "notwendig" ist oder nicht, hängt von dem Weg ab. :slight_smile:

Soltanius:
Das Problem, was ich jetzt nur noch habe ist das mit dem delay(x), richtig?

Höchstwahrscheinlich ja.
Die Verwendung von delays ist häufig problematisch, vor allem, wenn es darum geht, mehrere Aufgaben "gleichzeitig" zu erledigen, also wie in deinem Beispiel eine LED blinken zu lassen und einen Taster abzufragen. Das Wort "gleichzeitig" ist deshalb in Anführungszeichen, weil das natürlich nicht wirklich gleichzeitig passiert, sondern nacheinander, allerdings so schnell nacheinander, dass es für die menschliche Wahrnehmung wie gleichzeitig wirkt (also z.B. mit nur einer Tausendstelsekunde Verzögerung, oder sogar weniger).
Hier ein paar Beiträge zum Thema "mehreres gleichzeitig":
Blinken ohne Delay
Using millis() for timing. A beginners guide
Demonstration code for several things at the same time
Multi-tasking the Arduino - Part 1
Neuling hat ne Frage Projekt Leuchtturm-Karte
BlinkwithoutDelay - Die Nachtwächtererklärung
Der Beitrag mit dem Leuchtturm kommt deiner Fragestellung wohl am nächsten, ist aber - je nach Programmiererfahrung - schon ein wenig komplex. :slight_smile:

Im Grunde genommen berührt deine Aufgabenstellung sehr wesentliche grundlegende Fragestellungen von Programmierung und Ablaufsteuerung.

uxomm:
Der Code hat mehrere Probleme.

a) diese Zeile macht nicht was du wahrscheinlich möchtest:

pushbutton = +1;

Ich vermute, dass hier pushbutton hochgezählt werden soll. Das ist aber nicht der Fall.
pushbutton wird lediglich auf 1 gesetzt. Deshalb wird pushbutton niemals 2 und case 2 wird niemals ausgeführt.
Das Hochzählen von pushbutton geht z.B. so:

pushbutton++;

oder so

pushbutton = pushbutton +1;

auch

pushbutton += 1;

incrementiert um 1 und ist richtig.
Grüße Uwe

So, ich habe anhand den links von uxomm mal etwas versucht nach dem ich das Gefühl hatte, dass ich es etwas verstanden habe.
Jetzt ist es so, dass der Wechsel von Fall "default" zu Fall "case 1" gut funktioniert und anders rum genau so, nur "case 1" wird nicht richtig ausgeführt.
Die LED blinkt einfach 'wie wild'.

Die LED soll zu erst 250ms angehen, dann 500ms aus, 1000ms an, 500ms aus, 250ms an und 2000ms aus.
Leider wird im Seriellen Monitor alles gleichzeitig ausgeführt, bzw angezeit.

Meine Frage an euch, kann mir bitte jemand meinen Fehler zeigen und erklären?

const int ledPin = 12;
const int buttonPin = 11;

int buttonState = 0;
int pushbutton = 0;
int ledStatus = LOW;

unsigned long timestore;

void setup(){
  Serial.begin(9600);
  Serial.println("Hello");
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}

void loop() {
  buttonState = digitalRead(buttonPin); 

  if (buttonState == HIGH) {
    pushbutton++;
  }
  Serial.println(pushbutton);
  switch(pushbutton) {
    case 1:                              //SOS Funktion
      Serial.println("case 1");
      if (ledStatus == LOW){             //Led für 250ms an
        if (millis() - timestore >250){
          digitalWrite(ledPin, HIGH);
          timestore = millis();
          ledStatus = HIGH;
        }
      }
      Serial.println("250ms an");
      if (ledStatus == HIGH){             //Led für 500ms aus
        if (millis() - timestore >500){
          digitalWrite(ledPin, LOW);
          timestore = millis();
          ledStatus = LOW;
        }
      }
      Serial.println("500ms aus");
      if (ledStatus == LOW){             //Led für 1000ms an
        if (millis() - timestore >1000){
          digitalWrite(ledPin, HIGH);
          timestore = millis();
          ledStatus = HIGH;
        }
      }
      Serial.println("1000ms an");
      if (ledStatus == HIGH){             //Led für 500 ms aus
        if (millis() - timestore >500){
          digitalWrite(ledPin, LOW);
          timestore = millis();
          ledStatus = LOW;
        }
      }
      Serial.println("500ms aus");
      if (ledStatus == LOW){             //Led für 250ms an
        if (millis() - timestore >250){
          digitalWrite(ledPin, HIGH);
          timestore = millis();
          ledStatus = HIGH;
        }
      }
      Serial.println("250ms an");
      if (ledStatus == HIGH){             //Led für 2000ms aus
        if (millis() - timestore >2000){
          digitalWrite(ledPin, LOW);
          timestore = millis();
          ledStatus = LOW;
        }
      }
      Serial.println("2000ms aus");
      break;
    default:                               //durchgehendes leuchten
      digitalWrite(ledPin, HIGH);
  }                                        //Ende switch/case
  if (pushbutton >1) {                     //setzt zurück auf durchgehend licht wenn höher als 1
    pushbutton = 0;  
  }
  delay(150);
}//Ende void loop

Soltanius:
Meine Frage an euch, kann mir bitte jemand meinen Fehler zeigen und erklären?

Du hast case 2, case 3 usw. vergessen. Jeder SOS-Zustand braucht ein case.

... oder einen eigenen Status. :slight_smile:
ledStatus gibt es ja schon, allerdings hat der bislang nur 2 Zustände, bräuchte aber deutlich mehr. :slight_smile:
Zum Beispiel so:

const int ledPin = 12;
const int buttonPin = 11;

int buttonState = 0;
int pushbutton = 0;
int ledStatus = 0;

unsigned long timestore;

void setup() {
  Serial.begin(9600);
  Serial.println("Hello");
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}

void loop() {
  buttonState = digitalRead(buttonPin);

  if (buttonState == HIGH) {
    pushbutton++;
  }
  // Serial.println(pushbutton);
  
  switch (pushbutton) {
    case 1:                              //SOS Funktion
      // Serial.println("case 1");
      if (ledStatus == 0) {            //Led für 250ms an
        if (millis() - timestore > 250) {
          digitalWrite(ledPin, HIGH);
          Serial.print(ledStatus);
          Serial.print("    ");
          Serial.println("250ms an");
          timestore = millis();
          ledStatus = 1;
        }
      }
      if (ledStatus == 1) {            //Led für 500ms aus
        if (millis() - timestore > 500) {
          digitalWrite(ledPin, LOW);
          Serial.print(ledStatus);
          Serial.print("    ");
          Serial.println("500ms aus");
          timestore = millis();
          ledStatus = 2;
        }
      }
      if (ledStatus == 2) {            //Led für 1000ms an
        if (millis() - timestore > 1000) {
          digitalWrite(ledPin, HIGH);
          Serial.print(ledStatus);
          Serial.print("    ");
          Serial.println("1000ms an");
          timestore = millis();
          ledStatus = 3;
        }
      }
      if (ledStatus == 3) {            //Led für 500 ms aus
        if (millis() - timestore > 500) {
          digitalWrite(ledPin, LOW);
          Serial.print(ledStatus);
          Serial.print("    ");
          Serial.println("500ms aus");
          timestore = millis();
          ledStatus = 4;
        }
      }
      if (ledStatus == 4) {            //Led für 250ms an
        if (millis() - timestore > 250) {
          digitalWrite(ledPin, HIGH);
          Serial.print(ledStatus);
          Serial.print("    ");
          Serial.println("250ms an");
          timestore = millis();
          ledStatus = 5;
        }
      }
      if (ledStatus == 5) {            //Led für 2000ms aus
        if (millis() - timestore > 2000) {
          digitalWrite(ledPin, LOW);
          Serial.print(ledStatus);
          Serial.print("    ");
          Serial.println("2000ms aus");
          timestore = millis();
          ledStatus = 0;
        }
      }
      break;
    default:                               //durchgehendes leuchten
      digitalWrite(ledPin, HIGH);
  }                                        //Ende switch/case

  if (pushbutton > 1) {                    //setzt zurück auf durchgehend licht wenn höher als 1
    pushbutton = 0;
  }
  delay(150);
}//Ende void loop

Dann sollte noch das "Problem mit dem Taster" durch eine Flankenerkennung
verbessert werden.

Wie hast du den Taster angeschlossen?
Wenn du auf HIGH abfragst, dann brauchst du einen sogenannten "Pulldown-Widerstand". Gibt es den?

agmue:
Du hast case 2, case 3 usw. vergessen. Jeder SOS-Zustand braucht ein case.

uxomm:
... oder einen eigenen Status. :slight_smile:
ledStatus gibt es ja schon, allerdings hat der bislang nur 2 Zustände, bräuchte aber deutlich mehr. :slight_smile:

Achso, vielen Dank. ich wusste nicht, dass jeder Zustand einen einzelnen braucht, aber jetzt mit dem Beispiel wird es mir klar. :smiley:

uxomm:
Wie hast du den Taster angeschlossen?
Wenn du auf HIGH abfragst, dann brauchst du einen sogenannten "Pulldown-Widerstand". Gibt es den?

Ja genau, ich frage nach HIGH ab und ja ich habe einen 10k Ohm Wiederstand der mit GND verbunden ist zwischen Knopf und Kabel welches zu Pin 11 geht (leider kein Schaltplan)

Jetzt wären noch eine "Flankenerkennung" des Tasters günstig.
Das ist nicht sehr kompliziert. Dabei wird immer wieder abgefragt, ob sich der Status des Tasters seit "dem letzten Mal" geändert hat. Dazu braucht es eine zusätzliche Variable, in der der vorige Status gespeichert wird (oben im Code einfügen), zum Beispiel:

byte lastButtonState = 0;

Die bisherige Abfrage des Tasters, also das:

if (buttonState == HIGH) {
pushbutton++;
}

... ersetzt du durch folgendes:

// Flankenerkennung / state change detection:
if (buttonState != lastButtonState) {    // Hat sich der Status des Tasters verändert
  delay(50);     // Taster entprellen quick & dirty  :-)
  if (buttonState == HIGH) {     // Taster ist gedrückt
    pushbutton++;
  }
  lastButtonState = buttonState;     // Buttonstatus speichern  
}

Dann ist es egal,wie lange der Taster gedrückt gehalten wird. Die Variabel pushbutton wird nur dann hochgezählt, wenn der Taster zuerst (wieder) losgelassen wird und danach (nochmals) gedrückt wird.

Dann kannst du auch

delay(150);

am Ende deines Codes entfernen.

Vielen Dank für deine ganze Hilfe erstmal! :slight_smile:
Mir ist gerade aufgefallen, dass die Morse Zeichen für SOS . . . _ _ _ . . . ist und nicht wie ich es momentan habe (. _ .)
Also versuche ich einfach mal, dass die led sich in den einzelnen momenten wiederholt.

Okay, es hat geklappt.
Hab nur noch eine Frage, die eigentlich nicht mit Arduino zu tun hat, wenn nicht gewünscht löschen.
Ich habe einen ATTiny85 und würde den gerne anstatt des Arduinos nutzen.
Laut Internet soll der eine max. Spannung von 5V vertragen.
Mein Netzteil hat 5V aber 3A
Darf der ATTiny nur eine bestimmte Menge an Strom bekommen, bzw würde er von meinem Netzteil Schaden nehmen?

Du solltest Dich mal mit ein paar Elektronik-Grundlagen beschäftigen. Die 3A sind der Strom, den das Netzteil liefern kann.

Gruß Tommy

Das die 3A der Strom sind weiß ich.
Ich war mir nur unsicher bei der Sache, deshalb habe ich nochmal nachgefragt, damit ich keine Fehler habe…
Ein einfaches ‘Ja, nimmt Schaden’ oder ‘Nein, es ist so ok’ wäre ja zu einfach gewesen.
Es war nur wegen dem ATTiny die Frage, da ich neu in dem Bereich bin.
Ich kann später mal ein Schaltplan machen und diesen hier reinstellen.

Soltanius:
Das die 3A der Strom sind weiß ich.
Ich war mir nur unsicher bei der Sache, deshalb habe ich nochmal nachgefragt, damit ich keine Fehler habe…
Ein einfaches ‘Ja, nimmt Schaden’ oder ‘Nein, es ist so ok’ wäre ja zu einfach gewesen.

Wir versuchen keine Antworten zu geben bei denen Du nicht etwas lernst.
Wenn Du Zweifel mit dem Strom eines Netzteiles hast damm nuß diesere Zweifel ausgemerzt werden. Eine einfache Antwort Ja/Nein hilft dabei nicht.
Darum lerne die Grundlagen.

Grüße Uwe

Soltanius:
Mir ist gerade aufgefallen, dass die Morse Zeichen für SOS . . . _ _ _ . . . ist und nicht wie ich es momentan habe (. _ .)

Es gibt ja unterschiedliche Arten von Notsignalen, nicht nur SOS: Notsignal – Wikipedia

uxomm:
Es gibt ja unterschiedliche Arten von Notsignalen, nicht nur SOS: Notsignal – Wikipedia

Es ist aber ein Projekt gezielt auf SOS, welches international das gleiche Muster hat.

Soltanius:
Mein Netzteil hat 5V aber 3A

Das sagt man so dahin, aber etwas genauer könnte es heißen: "Mein Netzteil ist eine Spannungsquelle von 5V mit einem maximalen Strom von 3A." Damit würde sich Deine Frage wahrscheinlich schon erübrigen, oder?

Zum Vergleich: "Mein Netzteil ist eine Stromquelle von 3A mit einer maximalen Spannung von 5V." Da ist dann der Strom fix und die Spannung flexibel. Sowas findet man bei Netzteilen für LEDs.

agmue:
Das sagt man so dahin, aber etwas genauer könnte es heißen: "Mein Netzteil ist eine Spannungsquelle von 5V mit einem maximalen Strom von 3A." Damit würde sich Deine Frage wahrscheinlich schon erübrigen, oder?

Zum Vergleich: "Mein Netzteil ist eine Stromquelle von 3A mit einer maximalen Spannung von 5V." Da ist dann der Strom fix und die Spannung flexibel. Sowas findet man bei Netzteilen für LEDs.

Ich hab es schon wieder verstanden, aber danke für deine tolle Erläuterung! :slight_smile: