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.
/*
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
}
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.
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); }
}
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 ) selten. Und dann geht's los mit den merkwürdigen "Fehlern" ...
Gruß (auch und besonders an @my_xy_projekt )
und weiterhin viel Spaß!
ec2021