Einfache if-Schleife

Hallo liebes Forum,
ich möchte nur ein einfaches Programm schreiben, das beim Drücken eines Knopfes etwas schließt, dann wieder öffnet, wieder schließt usw. ...

Dazu habe ich mir folgendes überlegt:

#include <Servo.h> 

int servoPin = 9;
const int button_pin = 13;
 
Servo servo;  
 
int closed = 90;   // servo position in degrees 
int open = 0;
int state = 1;
int button;
 

void setup() 
{ 
  Serial.begin(9600);

  servo.attach(servoPin); 
  pinMode(button_pin, INPUT);
  servo.write(open);
} 
 
 
void loop() 
{ 
  button = digitalRead(button_pin);
  Serial.print(button);
  Serial.println(state);

  if (button == 0 && state == 0){
    delay(30);
    servo.write(open);
    state = 1;
    delay(1000);
    
  }

  if (button == 0 && state == 1){
    delay(30);
    servo.write(closed);
    state = 0;
    delay(1000);
  }

}

Problem: Beim ersten If-Block wird die state Variable nicht auf 1 gesetzt, bzw. springt wieder auf 0 zurück. Auch die Stervostellung springt nach 1s wieder auf "close". Warum verstehe ich nicht.
Der zweite If-Block funktioniert aber, hier wird geschlossen und die state-Variable geändert.

Ich stehe hier wirklich auf dem Schlauch.

Danke vorab!
LG Alex

PS: Ich verwende ein Arduino Button Modul, das momentan in der Pull-Up-Konfiguration angeschlossen ist.

Moin @lexl55,

wenn Du den button_pin nicht mit einem Widerstand auf HIGH gezogen hast, wird der Eingang "floaten", also zufällig HIGH- und LOW-Werte ausgeben.

Stattdessen kannst Du den internen Pullup-Widerstand nutzen:

  pinMode(button_pin, INPUT_PULLUP);

Ich bastele Dir das Ganze mal auf Wokwi nach und schicke Dir den Link.

Gruß
ec2021

P.S.: Schau mal hier nach
Servo Control per Button

Und hier eine neue Version, die

  • Den Button entprelled und nur auf die fallende Flanke (HIGH -> LOW) reagiert.
  • Auf delays() verzichtet, damit die Buttonabfrage immer schnell genug erfolgen kann.
  • Switch/case verwendet, um je nach Zustand den Servo anzusteuern.

Hier findest Du noch eine etwas "gehübschte" Version mit einigen Kommentaren zum (hoffentlich) Nachvollziehen:
https://wokwi.com/projects/378132967574695937

Sketch
/*
  Forum: https://forum.arduino.cc/t/einfache-if-schleife/1176612
  Wokwi: https://wokwi.com/projects/378132967574695937

*/

#include <Servo.h> 

constexpr byte servoPin = 9;
constexpr byte button_pin = 13;
 
Servo servo;  
 
int closed = 90;   // servo position in degrees 
int open = 0;
byte oldState = 1; // Speichert den alten Status "closed"/"open"
                   // damit man erkennen kann, wann sich state ändert
byte state = 1;    // Speichert den aktuellen Status "closed/open", der sich
                   // durch einen Tastendruck ändern kann
 

void setup() 
{ 
  Serial.begin(115200);
  servo.attach(servoPin); 
  pinMode(button_pin, INPUT_PULLUP);  // Setzt den Modus des Pins so, dass er bei offener Taste HIGH ausgibt
                                      // Der Taster wird so angeschlossen, dass der Pin auf Masse/GND 
                                      // bei Betätigung gelegt wird. Da der interne Pullup-Widerstand hochohmig ist,
                                      // fliesst dabei nur ein kleiner Strom.
  servo.write(open);    
} 
 
 
void loop() 
{ 
  if (buttonJustDown()) {   // Prüft, ob die Taste gerade von HIGH auf LOW geschaltet wurde
    state = !state;         // und invertiert dann state (0 wird zu 1, 1 wird zu 0)
  }
  if (state != oldState){   // Nur wenn sich state geändert hat, geht es in den folgenden Zweig
    oldState = state;       // In diesem Fall merken wir uns den "neuen" Status auch in oldState
                            // und verhindern, dass wir bei folgenden Durchgängen bei denen sich
                            // state nicht geändert hat, wieder hier hineinkommen.
    switch (state){                      // Je nach state geht es in die case-Zweige
      case 0: servo.write(closed);       // bei state == 0 schließen wir
              Serial.println("Closing");
          break; 
      case 1: servo.write(open);        // bei state == 1 öffnen wir
              Serial.println("Opening");
          break;
    }
  }
}

boolean buttonJustDown(){   // Gibt genau dann einmal true zurück, wenn buttonState von HIGH auf LOW wechselt
  static unsigned long lastChange = 0;  // Hier merken wir uns den zeitpunkt, wann der letzte Wechsel HIGH/LOW
                                        // per digitalRead() erkannt wurde
  static byte buttonState = HIGH;       // Speichert den entprellten Zustand des Buttons
  static byte lastState = HIGH;         // Speichert den letzten unentprellten Zustand
  boolean justDown = false;             // Liefert am Ende den Rückgabewert der Funktion
  byte actState = digitalRead(button_pin);  // Liest den aktuellen nicht entprellten Zustand des Buttons
  if (actState != lastState) {              // Prüft, ob der zuvor ermittelte und der aktuelle ungleich sind
    lastChange = millis();                  // Falls ja, merken wir uns die Zeit in ms
    lastState = actState;                   // und den "neuen" nicht entprellten Zustand
  }
  if (actState != buttonState && millis()-lastChange > 30){  // Wenn der aktuelle Wert nicht dem entprellten 
                                                             // entspricht UND der letzte Wechsel länger als
                                                             // 30 ms her ist, dann sollte sich der Zustand des
                                                             // Buttons nun stabil geändert haben
    buttonState = actState;                                  // Deshalb akzeptieren wir diesen Zustand nun als
                                                             // neuen entprellten Zustand des Buttons
    if (buttonState == LOW) {             // Hier kommt jetzt der "Kunstgriff": Wir geben dann genau einmal TRUE
       justDown = true;                   //  zurück, wenn sich der Zustand von HIGH zu LOW geändert hat
    } 
  }
  return justDown;   // Gibt (meistens) FALSE zurück und nur beim Übergang von HIGH auf LOW einmal TRUE
}

und Schaltung:

image

Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden.
Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.
mfg ein Moderator.

if-schleife

Dein Sketch lässt sich so wunderbar runterkürzen.
Darum habe ich das gemacht.

#include <Servo.h>

const byte servoPin = 9;
const byte button_pin = 13;

Servo servo;

const int closed = 90;   // servo position in degrees
const int open = 0;
bool state = 1;
bool button;


void setup()
{
  Serial.begin(9600);
  servo.attach(servoPin);
  pinMode(button_pin, INPUT);
  servo.write(open);
}


void loop()
{
  button = digitalRead(button_pin);
  Serial.print(button);
  Serial.println(state);
  if (button == 0)
  {
    if ( state == 0)
    { servo.write(open); }
    else
    { servo.write(closed); }
    state = !state;
    delay(1000);
  }
}

Das ist aber nicht das was Du willst. Oder?
Ich lese raus, das Du mit jedem Tastendruck den Servo verstellen willst. Richtig?

Danke für die schnelle Antwort.
Dein Code funktioniert, mit jedem Knopfdruck bewegt sich der Servo richtig :+1:

@ec2021 auch dein Code funktioniert einwandfrei.

Danke für die ausführliche Antwort! :slight_smile:

Du wirst spätestens dann Probleme bekommen, wenn Du noch was anders machen willst.
Während dem delay() kannst Du NIX machen.
Der Code wartet da ab, bis die Zeit um ist.

Daher noch einmal die Frage:
Taste gedrückt - Servo geht in die eine Richtung
Taste loslassen
Taste gedrückt - Servo geht in die andere Richtung
Taste loslassen

Richtig?
Dann wäre der hier evtl. besser.

#include <Servo.h>

const byte servoPin = 9;
const byte button_pin = 13;

Servo servo;

const int closed = 90;   // servo position in degrees
const int open = 0;
bool state;
bool servoState;

constexpr uint32_t debounceTime {50};
uint32_t lastSwitch;


void setup()
{
  Serial.begin(9600);
  servo.attach(servoPin);
  pinMode(button_pin, INPUT);
}


void loop()
{
  if (!digitalRead(button_pin))
  {
    if (state == false)
    {
      lastSwitch = millis();
      state = true;
      servoState = !servoState;
      Serial.print(F("ServoStatus: "));
      Serial.println(servoState);
    }
  }
  else if (millis() - lastSwitch > debounceTime && state == true)
  {
    state = false;
  }
  if (servoState)
  { servo.write(closed); }
  else
  { servo.write(open); }
}

Gerne,

Ich empfehle Dir - genauso wie auch @my_xy_projekt - Tasten grundsätzlich zu debouncen/entprellen und das delay() loszuwerden. Soweit man nur auf die erste Flanke eines Tastendrucks reagiert und dann für eine ausreichend lange Zeit "nicht mehr hinschaut", geht es ohne Entprellen gut.

Aber dabei bleibt es (aus unserer gemeinsamen Erfahrung :wink: ) selten. Und dann geht's los mit den merkwürdigen "Fehlern" ...

Gruß (auch und besonders an @my_xy_projekt )
und weiterhin viel Spaß!
ec2021

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.