How to use a Button as a Switch?

Hello,
In my programm, I need to use a button, like a switch. Ive already written a code for this, but I think i have a problem with the "Control Structures". in my eyes is there everything right, but the LED (Pin D8) only goes one time to HIGH. Because I am from germany; Here the same explanation in german:
Ich versuche hier in dem Programm, mithilfe eines boolen einen Knopf, wie einen schalter wirken zu lassen. Meiner Meinung nach sollte dies auch funktionieren, jedoch will die Lampe irgendwie nicht an und aus gehen so wie ich es will. Es folgt das Programm:

bool knopfi = false;        //A bool to switch behind the Status
const int buttonPin = D1;   
int buttonStatus = 0;

void setup() {
pinMode(buttonPin, INPUT);  // The Button
pinMode( D8, OUTPUT);       // Its could be a LED
}

void loop() {
 buttonStatus=digitalRead(buttonPin);
 if (knopfi == false&& digitalRead(buttonStatus == 1 )) 
 {
   knopfi = true;
 }
 
if (knopfi == true && digitalRead(buttonPin == 1 ))
{
   knopfi = false;
 }
 
 while (knopfi == false){              //während
         digitalWrite(D8, HIGH);
         }
 while (knopfi == true){
         digitalWrite(D8, LOW);
         }
}

Its coded for a NodeMCU. Can anyone help explain how I can fix this, so that it will run? Danke im Voraus :wink:

Testfahrt_Button_bol2.ino (650 Bytes)

Setze Deinen Code bitte in Codetags (</>-Button oben links im Forumseditor oder [code] davor und [/code] dahinter ohne *).
Dann ist er auch auf mobilen Geräten besser lesbar.
Das kannst Du auch noch nachträglich ändern.

Gruß Tommy

Da wir hier im deutschen Teil des Forums sind, kannst Du auch deutsch schreiben.

Aus dieser While-Schleife kommst Du nie mehr raus:

 while (knopfi == false){              //während
          digitalWrite(D8, HIGH);
          }

Da die Variable 'knopfi innerhalb der Schleife nicht mehr verändert wird. ( Ebenso natürlich aus der folgenden, je nachdem in welche er zuerst reinspringt )

Wenn Du mit einem Taster einen Zustand umschalten (toggeln) willst ( um ihn wie einen Schalter wirken zu lassen ) musst Du ihn auch auf jeden Fall entprellen.

Ausserdem verstehe ich dein digitalRead - Anweisungen nicht. Digitalread erwartet ein Pin-Nummer als Parameter und keine logische Abfrage.

Bitte bleibe in deutsch...

funnyfritz:
Hello,
In my programm, I need to use a button, like a switch. Ive already written a code for this, but I think i have a problem with the "Control Structures". in my eyes is there everything right, but the LED (Pin D8) only goes one time to HIGH. Because I am from germany; Here the same explanation in german:
Ich versuche hier in dem Programm, mithilfe eines boolen einen Knopf, wie einen schalter wirken zu lassen. Meiner Meinung nach sollte dies auch funktionieren, jedoch will die Lampe irgendwie nicht an und aus gehen so wie ich es will. Es folgt das Programm:

while (knopfi == false){ //während
digitalWrite(D8, HIGH);
}
while (knopfi == true){
digitalWrite(D8, LOW);
}

Da steht:
solange knopfi falsch ist, bleibt die LED an.

Dieser Zustand tritt mit Start ein:

bool knopfi = false;        //A bool to switch behind the Status

und verbleibt dort, weil es keinen Exit-punkt gibt.

In einigen Beipielen findest Du etwas ähnliches: while(1) ist eine Endlosschleife, weil sich die Bedingung nicht ändert.

Mach ein if draus.

(deleted)

Moin Jungs,
vielen Dank für eure zahlreichen Antworten. Leider war es mir nicht von Anfang an bewusst, dass es hier einen deutschen Teil des Forums gibt, da die Seite bei mir immernochin Englisch gestaltet ist. Außerdem ist dies mein erster Beitrag, daher bin ich noch ziemlich unerfahren mit der Seite hier(Sry für fehler) :3 Hoffentlich nimmt es mir keiner Übel.
Um zurück zum Programm zu kommen:

MicroBahner:
Aus dieser While-Schleife kommst Du nie mehr raus:

 while (knopfi == false){              //während

digitalWrite(D8, HIGH);
          }



Da die Variable 'knopfi innerhalb der Schleife nicht mehr verändert wird. ( Ebenso natürlich aus der folgenden, je nachdem in welche er zuerst reinspringt )

Ausserdem verstehe ich dein digitalRead - Anweisungen nicht. Digitalread erwartet ein Pin-Nummer als Parameter und keine logische Abfrage.

Diese beiden Tipps habe ich umgesetzt, es sieht nun wiefolgt aus;

void loop() {
  buttonStatus=digitalRead(buttonPin);
  if (knopfi == false&& buttonStatus == HIGH) 
  {
    knopfi = true;
  }
  
if (knopfi == true && buttonStatus == HIGH)
 {
    knopfi = false;
  }
  
 if (knopfi == false){             
          digitalWrite(D8, HIGH);
          }
 if (knopfi == true){
          digitalWrite(D8, LOW);
          }

Leider funktioniert es jedoch immernoch nicht so wie ich es mir wünsche. Ich komme stark davon aus, dass es daran liegt, dass das Programm immer bei der ersten if-Schleife bleibt und somit nicht die anderen durchgeht. Wie bekomme ich das hin, dass alle schleifen gleichzeitig angesprochen werden, bzw brauche ich dafür eine andere "Control Structures" (-> If,for,while...). VIELEN Dank schon mal im Voraus! Ich finde es super, wie schnell und zuverlässig hier geantwortet wird.
MfG funnyfritz

Abgesehen davon, dass es keine if-Schleifen gibt, wäre zur Diskussion der aktuelle Code sinnvoll.

Gruß Tommy

Ich hab mal Deinen Code formatiert und kommentiert.
Vielleicht kommst Du selbst drauf.

funnyfritz:
Diese beiden Tipps habe ich umgesetzt, es sieht nun wiefolgt aus;

void loop()

{
 buttonStatus = digitalRead(buttonPin);       // Speichert Zustand in Variable
 if (knopfi == false && buttonStatus == HIGH) // Prüft ob knopfi nicht gesetzt und Taste gedrückt
   {                                          // Wenn JA:
   knopfi = true;                             // setzt knopfi
   }
 if (knopfi == true && buttonStatus == HIGH)  // Prüft ob knopfi gesetzt und Taste gedrückt
   {                                          // Wenn JA:
   knopfi = false;                            // löscht knopfi
   }
 if (knopfi == false)                         // Wenn knopfi gelöscht
   {                                          // Dann:
   digitalWrite(D8, HIGH);                    // Mache D8 an
   }                                          
 if (knopfi == true)                          // Wenn knopf1 gesetzt
   {                                          // Dann:
   digitalWrite(D8, LOW);                     // Mache D8 aus
   }




Ich komme stark davon aus, dass es daran liegt, dass das Programm immer bei der ersten if-Schleife bleibt und somit nicht die anderen durchgeht.

Wenn Du genau aufpasst, siehst Du im Code, warum D8, LOW nie erreicht wird :wink:

Hallo funnyfritz,

wenn es beim Lesen des codes noch nicht klick macht hilft debug-output

void setup() {
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);
  digitalWrite(buttonPin,HIGH);
  pinMode(D8, OUTPUT);
}

void loop()
  {
  buttonStatus = digitalRead(buttonPin);       // Speichert Zustand in Variable
  if (knopfi == false && buttonStatus == HIGH) // Prüft ob knopfi nicht gesetzt und Taste gedrückt
    {                                          // Wenn JA:
    knopfi = true;                             // setzt knopfi
    Serial.println("(1: knopfi == false && buttonStatus == HIGH) ist wahr setze knopfi = true;");
    }

     
  if (knopfi == true && buttonStatus == HIGH)  // Prüft ob knopfi gesetzt und Taste gedrückt
    {                                          // Wenn JA:
    knopfi = false;                            // löscht knopfi
    Serial.println("((2: knopfi == true && buttonStatus == HIGH) ist wahr setze knopfi = false;");
    }

  if (knopfi == false)                         // Wenn knopfi gelöscht
    {                                          // Dann:
    digitalWrite(D8, HIGH);                    // Mache D8 an
    Serial.println("3: if (knopfi == false) ist wahr setze digitalWrite(D8, HIGH);");
    }                                          
    
  if (knopfi == true)                          // Wenn knopf1 gesetzt
    {                                          // Dann:
    digitalWrite(D8, LOW);                     // Mache D8 aus
    Serial.println("4: if (knopfi == true) ist wahr setze digitalWrite(D8, LOW);");
    }

}

In dieser Variante wird der serielle Monitor mit Ausgaben zugeballert
Das heißt wenn der Bildschirm voll ist autoscroll im seriellen Monitor deaktivieren und in Ruhe lesen welche Meldungen werden ausgegeben und welche nicht

viele Grüße Stefan

#include <CombiePin.h>
#include <CombieTimer.h>
#include <CombieTools.h>

using Taster = Combie::Pin::InvInputPin<2>; // Taster gegen GND geschaltet
using Led    = Combie::Pin::OutputPin<13>;

Combie::Timer::EntprellTimer   entprellen(20); // ms
Combie::Tools::ToggleSwitch    tgSw ;

void setup()
{
  Taster{}.initPullup();
  Led{}.init();
}

void loop()
{
  Led{} = tgSw = entprellen = Taster{};
}

CombieLib.zip (81.9 KB)

Hallo Combie,

zunächst einmal vielen Dank das du deine CombieLib zur Verfügung stellst.
Ich habe aber auch ein Supertalent genau die Sachen herauszupicken die nicht auf Anhieb laufen.
Bei streaming.h wusste ich was zu tun ist: über den library-manager nachinstallieren.

Dann habe ich das Beispiel:
C:\Users\Stefan\Documents\Arduino\ESPSchedulerLoopCount\ESPSchedulerLoopCount.ino

ausprobiert. Da bringt mir der compiler folgende Fehlermeldungen

Arduino: 1.8.12 (Windows 10), Board: "Generic ESP8266 Module, 80 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), dtr (aka nodemcu), 26 MHz, 40MHz, DOUT (compatible), 1MB (FS:64KB OTA:~470KB), 2, nonos-sdk 2.2.1+100 (190703), v2 Lower Memory, Disabled, None, Only Sketch, 115200"

"C:\\Users\\Stefan\\AppData\\Local\\Arduino15\\packages\\esp8266\\tools\\xtensa-lx106-elf-gcc\\2.5.0-4-b40a506/bin/xtensa-lx106-elf-g++" -D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-IC:\\Users\\Stefan\\AppData\\Local\\Arduino15\\packages\\esp8266\\hardware\\esp8266\\2.6.3/tools/sdk/include" "-IC:\\Users\\Stefan\\AppData\\Local\\Arduino15\\packages\\esp8266\\hardware\\esp8266\\2.6.3/tools/sdk/lwip2/include" "-IC:\\Users\\Stefan\\AppData\\Local\\Arduino15\\packages\\esp8266\\hardware\\esp8266\\2.6.3/tools/sdk/libc/xtensa-lx106-elf/include" "-IC:\\Users\\Stefan\\AppData\\Local\\Temp\\arduino_build_189467/core" -c -w -Os -g -mlongcalls -mtext-section-literals -fno-rtti -falign-functions=4 -std=gnu++11 -MMD -ffunction-sections -fdata-sections -fno-exceptions -DNONOSDK22x_190703=1 -DF_CPU=80000000L -DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=0 -DARDUINO=10812 -DARDUINO_ESP8266_GENERIC -DARDUINO_ARCH_ESP8266 "-DARDUINO_BOARD=\"ESP8266_GENERIC\"" -DLED_BUILTIN=2 -DFLASHMODE_DOUT -DESP8266 "-IC:\\Users\\Stefan\\AppData\\Local\\Arduino15\\packages\\esp8266\\hardware\\esp8266\\2.6.3\\cores\\esp8266" "-IC:\\Users\\Stefan\\AppData\\Local\\Arduino15\\packages\\esp8266\\hardware\\esp8266\\2.6.3\\variants\\generic" "-IC:\\Users\\Stefan\\Documents\\Arduino\\libraries\\Streaming\\src" "-IC:\\Users\\Stefan\\Documents\\Arduino\\libraries\\CooperativeTask\\src" "C:\\Users\\Stefan\\AppData\\Local\\Temp\\arduino_build_189467\\sketch\\ESPSchedulerLoopCount.ino.cpp" -o "C:\\Users\\Stefan\\AppData\\Local\\Temp\\arduino_build_189467\\sketch\\ESPSchedulerLoopCount.ino.cpp.o"
In file included from C:\Users\Stefan\Documents\Arduino\ESPSchedulerLoopCount\ESPSchedulerLoopCount.ino:6:0:

SchedulerLoopCountTask.h:28:3: error: cannot declare variable 'schedulerLoopCountTask' to be of abstract type 'SchedulerLoopCountTask'

 } schedulerLoopCountTask(1000);

   ^

C:\Users\Stefan\AppData\Local\Temp\arduino_build_189467\sketch\SchedulerLoopCountTask.h:6:7: note:   because the following virtual functions are pure within 'SchedulerLoopCountTask':

 class SchedulerLoopCountTask: public Task

       ^

In file included from C:\Users\Stefan\Documents\Arduino\libraries\CooperativeTask\src/Task.h:5:0,

                 from C:\Users\Stefan\Documents\Arduino\libraries\CooperativeTask\src/Scheduler.h:4,

                 from C:\Users\Stefan\Documents\Arduino\libraries\CooperativeTask\src/CooperativeTask.h:4,

                 from C:\Users\Stefan\Documents\Arduino\ESPSchedulerLoopCount\ESPSchedulerLoopCount.ino:5:

C:\Users\Stefan\Documents\Arduino\libraries\CooperativeTask\src/Runable.h:18:18: note: 	virtual void Runable::run()

     virtual void run()  = 0;

                  ^

C:\Users\Stefan\Documents\Arduino\ESPSchedulerLoopCount\ESPSchedulerLoopCount.ino: In function 'void setup()':

ESPSchedulerLoopCount:15:12: error: 'class Scheduler' has no member named 'begin'

  scheduler.begin();

            ^

C:\Users\Stefan\Documents\Arduino\ESPSchedulerLoopCount\ESPSchedulerLoopCount.ino: In function 'void loop()':

ESPSchedulerLoopCount:20:12: error: 'class Scheduler' has no member named 'loop'

  scheduler.loop();

            ^

Bibliothek Streaming in Version 5.0.0 im Ordner: C:\Users\Stefan\Documents\Arduino\libraries\Streaming  wird verwendet
Bibliothek CooperativeTask in Version 1.0.1 im Ordner: C:\Users\Stefan\Documents\Arduino\libraries\CooperativeTask  wird verwendet
exit status 1
cannot declare variable 'schedulerLoopCountTask' to be of abstract type 'SchedulerLoopCountTask'

variable to be abstract type geht weit über meinen Wissensstand hinaus.
Kannst du mir auf die Sprünge helfen? Was muss ich denn da anders machen damit dein Beispielcode läuft?

ESP im Dateinamen hat mich ja vermuten lassen ESP8266 Das es was boardspezifisches ist. Also habe ich ein ESP8266 angestöpselt. Und es damit porbiert. Kein Erfolg.

StefanL38:
Der Post eins weiter oben ist die diplomatische Version jetzt kommt die ehrliche aber "ausgepiepte" Version

######! solche "examples" liebe ich ja wie #######! Für Newbees ist das #######!

Ich hoffe in der Form ist das jetzt forumsregelkonform.

viele Grüße Stefan

Du kannst mich mal!
Und dein Geschrei kannst du dir irgendwo hin stecken.

Was ich zugeben muss:
Da ist mir noch ein veraltetes Beispiel mit rein gerutscht.
Konter entfernt

Im Anhang die korrigierte Version.
Sollte mit allen Arduino kompatiblen Boards und Kompilern(C++11,C++14,C++17) funktionieren.

CombieLib.zip (81 KB)

StefanL38:
Der Post eins weiter oben ist die diplomatische Version jetzt kommt die ehrliche aber "ausgepiepte" Version

######! solche "examples" liebe ich ja wie #######! Für Newbees ist das #######!

Ich hoffe in der Form ist das jetzt forumsregelkonform.

viele Grüße Stefan

Glückwunsch! Du hast gerade Einzug in meine persönliche Troll-Liste gehalten.

Gruß Tommy

Hallo Combie,

es hat eine Weile gedauert zu verstehen was geht und was nicht. OK. OK. PC is King.
Damit habe ich nicht gerechnet das das so ankommt.
Ich bedanke mich für die korrigierte Version. Jetzt compiliert das Beispiel.

Es tut mir Leid. Das war nicht meine Absicht.
viele Grüße Stefan

StefanL38:
Es tut mir Leid. Das war nicht meine Absicht.

Doch war es.
Da der Post gelöscht ist, auf den combie sich bezog (ich hatte ihn gesehen).

Es ist mir nicht egal.

Deswegen hatte ich ihn zitiert. Das kann er nicht löschen.

Gruß Tommy

my_xy_projekt:
Doch war es.
Da der Post gelöscht ist, auf den combie sich bezog (ich hatte ihn gesehen).

Es ist mir nicht egal.

Das andere Leute mit meinem Kopf besser denken können und noch genauer wissen was ich für Absichten habe als ich selbst ist mir neu. Ich hatte mich gerärgert, dass das Beispiel nicht compiliert. Und diesem mich ärgern habe ich auf diese missglückte Art und Weise Ausdruck verliehen. Mein Problem, dass ich mich geärgert habe. Aber es stimmt schon: Die Bedeutung der Kommunikation ist die Bedeutung die der Empfänger dem gesendeten gibt. Die Entscheidung welche Bedeutung man dem Empfangenen gibt trifft der Empfänger. Das heißt der Empfänger hat es in der Hand wie er es deutet. Ist jedenfalls meine Meinung/Ansicht. Dem werden aber bestimmt nicht alle Menschen zustimmen.
viele Grüße Stefan

Dem werden aber bestimmt nicht alle Menschen zustimmen.

Ich stimme dir zu!

Formuliere es aber anders:

Ich bin verantwortlich für das, was ich sage.
Nicht für das, was du dabei empfindest.

Oder anders:

Das größte Problem, im Leben eines Menschen, ist die Wahl der richtigen Gedanken.

Man kann vieles über mich behaupten, oder mir Etiketten ans Hemd kleben...
Aber, dass ich keine Fehler mache, oder alles weiß, das gehört bestimmt nicht dazu.

Hallo, vielen dank für das drauf aufmerksam machen.
Erst jetzt habe ich gesehen, dass er beide If-schleifen parallel versucht anzufahren.

my_xy_projekt:
Ich hab mal Deinen Code formatiert und kommentiert.
Vielleicht kommst Du selbst drauf.

Danke für den Code @Combie, ehrlich gesagt ist er mir aber viel zu komplex, sodass ich garnicht durchblicke xD. Ich wollte das Programm eigentlich so kurz wie möglich halten :3
Gibt es den keine andere Möglichkeit, die Schleifen hintereinander abzufragen, ich komme jetzt gerade nur Spontan auf folgende Idee:

if (knopfi == false && buttonStatus == HIGH&& i == 0) // Prüft ob knopfi nicht gesetzt und Taste gedrückt und i 0 ist
    {                                          // Wenn JA:
    knopfi = true;                             // setzt knopfi
    Serial.println("(1: knopfi == false && buttonStatus == HIGH) ist wahr setze knopfi = true;");
    i++;
    }

    
  if (knopfi == true && buttonStatus == HIGH&& i > 0 )  // Prüft ob knopfi gesetzt und Taste gedrückt und i 1 ist
    {                                          // Wenn JA:
    knopfi = false;                            // löscht knopfi
    Serial.println("((2: knopfi == true && buttonStatus == HIGH) ist wahr setze knopfi = false;");
    i = 0 ;
    }

Hierbei habe ich einen int "i" erstellt, der in diesem Programm 0 oder höher wird. Leider funktioniert das auch nicht. Falls jemand von euch eine Idee hat, wie man anders hierbei vorgehen kann (könnte), lasst es mich wissen.
Grüße funnyfritz
PS: Ich bekomme irgendwie noch keine Benachrichtigungen wenn jemand hier etwas Antwortet, daher antworte ich immer so spät ):

Hallo Funnyfritz,

hast du dir schonmal die bounce2 - Library angeschaut,
die entprellt deinen Btn und mit:

#include <Bounce2.h>;

Bounce myBtn = Bounce();  // myBtn müsste dein Knopfi sein.

const int buttonPin = 2;
const int ledPin = 13;
int ledState = HIGH;

void setup() {

  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin,ledState);
  
  pinMode(buttonPin, INPUT);

  myBtn.attach(buttonPin);
  myBtn.interval(10);
}

void loop() {

myBtn.update();
  
  if(myBtn.fell() == true)
  {
    ledState = !ledState;
    digitalWrite(ledPin,ledState);
  }
}

kannst du einen Button als Toogle nutzen.

Schau dir aber auch noch gern andere Beispiele zur Bounce2 Library an und
entscheide selbst ob das für Dich zutrifft und sinnvoll ist.