Probleme mit Funktionsaufruf für 2 Funktionen mit WHILE,

Ich wende mich heute zum 3. Mal als Laie an die Erfahrenen hier im Forum.
Dank eurer Hilfe habe ich mein "Tomatenhaus- Projekt" fertigstellen können.
Es dient "nur" zum Lernen ARDUINO, damit ich nicht einroste. Die Fertigstellung steht im Wettbewerb mit dem Reifegrad der Tomaten und ich glaube, ich bin auf der Zielgerade angekommen. Wäre da nicht:
Ich habe zwei Funktionen definiert: "TuerAuf" und "TuerZu".
In Abhängigkeit von Temperatur (außen), Uhrzeit (nachts/ tagsüber) und/oder Regen wird TuerAuf oder TuerZu aufgerufen.
Ich habe das - aus VB kommend - mit if bzw. While aufgerufen.
Blöd nur, dass die Funktionen immer wieder aufgerufen werden.
In der Ausführung des Programms wird z.B. nach Anfahren der HOME Position (nur 1x ausgeführt) die Tür geöffnet. Das Programm wird wieder neu durchlaufen und die Tür wird wieder geöffnet. Und das Nervt. Beim Schreiben kommt mir gerade die Idee, einen Zähler n einzubauen. Wenn n == 1, dann weiter oder so? Oder könnte per WHILE das Problem ohne Zähler gelöst werden?
Hier der SKETCHTEIL, bei dem das Problem auftritt:

if (rainDigital == 1) {
      TuerAuf();
    } else {
      TuerZu();
    }

Beim Sketchteil

 if (rainDigital == 1) {
      lcd.print("Kein Regen");
    } else {
      lcd.print("Regen");
    }

zeigt das Display auch nicht Regen an, wenn kein Regen fällt!!! Warum gerade hier?

#include <AccelStepper.h>
#include <LiquidCrystal_I2C.h>
// LCD-Objekt erstellen
LiquidCrystal_I2C lcd(0x27, 20, 4);
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <RTClib.h>
RTC_DS3231 rtc;
const int rainDigitalPin = 13;
const int rainAnalogPin = A0;
const int rainSensorPowerPin = A1;

#define TEMP_PIN 13
OneWire oneWire(TEMP_PIN);
DallasTemperature sensors(&oneWire);
int doorPosition = 0;
float temperature = 0;
bool isRaining = false;

const int stepPin = 5;
const int dirPin = 4;
const int enablePin = 6;
AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);

#define ST01 7
#define ST02 8

#define RAIN_PIN A0       // Regensensor
#define TEMP_PIN A2       // Temperatursensor
#define FEUCHTE_PIN_1 A3  // Feuchtigkeitssensor 1
#define FEUCHTE_PIN_2 A4  // Feuchtigkeitssensor 2
#define FEUCHTE_PIN_3 A5  // Feuchtigkeitssensor 3
#define FEUCHTE_PIN_4 A6  // Feuchtigkeitssensor 4
#define FEUCHTE_PIN_5 A7  // Feuchtigkeitssensor 5
#define FEUCHTE_PIN_6 A8  // Feuchtigkeitssensor 6

#define PUMP_PIN_1 20  // Pumpe 1
#define PUMP_PIN_2 21  // Pumpe 2
#define PUMP_PIN_3 22  // Pumpe 3
#define PUMP_PIN_4 23  // Pumpe 4
#define PUMP_PIN_5 24  // Pumpe 5
#define PUMP_PIN_6 25  // Pumpe 6

#define FEUCHTE_THRESHOLD_LOW 30   // Schwellwert für niedrige Bodenfeuchte in Prozent
#define FEUCHTE_THRESHOLD_HIGH 80  // Schwellwert für hohe Bodenfeuchte in Prozent

#define START_HOUR 8  // Startstunde des Programms
#define END_HOUR 19   // Endstunde des Programms \

void setup() {
  pinMode(ST01, INPUT_PULLUP);
  pinMode(ST02, INPUT_PULLUP);
  pinMode(enablePin, OUTPUT);
  pinMode(rainDigitalPin, INPUT);
  pinMode(rainAnalogPin, INPUT);
  pinMode(rainSensorPowerPin, OUTPUT);

  Serial.begin(9600);
  Wire.begin();
  rtc.begin();
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  digitalWrite(enablePin, LOW);
  stepper.setMaxSpeed(1700);
  stepper.setSpeed(1000);
  stepper.setAcceleration(700);
  stepper.moveTo(-100000);
  while (digitalRead(ST01)) {
    stepper.run();
  }
  stepper.setCurrentPosition(0);
  digitalWrite(enablePin, HIGH);
  digitalWrite(enablePin, LOW);
  stepper.moveTo(stepper.currentPosition() + 600);  // 600 ist in meinem Fall der ermittelte Abstand (in STEPS) vom Taster, um ihn mechanisch zu entlasten!
  stepper.runToPosition();
  stepper.setCurrentPosition(0);
  digitalWrite(enablePin, HIGH);

  pinMode(FEUCHTE_PIN_1, INPUT);
  pinMode(FEUCHTE_PIN_2, INPUT);
  pinMode(FEUCHTE_PIN_3, INPUT);
  pinMode(FEUCHTE_PIN_4, INPUT);
  pinMode(FEUCHTE_PIN_5, INPUT);
  pinMode(FEUCHTE_PIN_6, INPUT);

  pinMode(PUMP_PIN_1, OUTPUT);
  pinMode(PUMP_PIN_2, OUTPUT);
  pinMode(PUMP_PIN_3, OUTPUT);
  pinMode(PUMP_PIN_4, OUTPUT);
  pinMode(PUMP_PIN_5, OUTPUT);
  pinMode(PUMP_PIN_6, OUTPUT);

  if (!rtc.begin()) {
    lcd.print("RTC nicht gefunden!");
    while (1)
      ;
  }
}

void TuerZu() {
  // Zur "Home" Position fahren
  digitalWrite(enablePin, LOW);
  stepper.setMaxSpeed(1700);
  stepper.setSpeed(1000);
  stepper.setAcceleration(700);
  stepper.moveTo(-180000);
  while (digitalRead(ST01)) {
    stepper.run();
  }
  stepper.setCurrentPosition(0);
  digitalWrite(enablePin, HIGH);
  digitalWrite(enablePin, LOW);
  stepper.moveTo(stepper.currentPosition() + 600);
  stepper.runToPosition();
  stepper.setCurrentPosition(0);
  digitalWrite(enablePin, HIGH);
}

void TuerAuf() {
  digitalWrite(enablePin, LOW);
  stepper.setMaxSpeed(1700);
  stepper.setSpeed(1000);
  stepper.setAcceleration(700);
  stepper.moveTo(180000);
  while (digitalRead(ST02)) {
    stepper.run();
  }
  stepper.setCurrentPosition(0);
  digitalWrite(enablePin, HIGH);
  digitalWrite(enablePin, LOW);
  stepper.moveTo(stepper.currentPosition() - 600);
  stepper.runToPosition();
  stepper.setCurrentPosition(0);
  digitalWrite(enablePin, HIGH);
}


void loop() {

  DateTime now = rtc.now();
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Uhrzeit: ");
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);

  lcd.setCursor(0, 1);
  lcd.print("Datum: ");
  lcd.print(now.day(), DEC);
  lcd.print('.');
  lcd.print(now.month(), DEC);
  lcd.print('.');
  lcd.print(now.year(), DEC);

  if (now.hour() >= START_HOUR && now.hour() < END_HOUR) {
    digitalWrite(rainSensorPowerPin, HIGH);
    delay(100);
    int rainDigital = digitalRead(rainDigitalPin);
    int rainAnalog = analogRead(rainAnalogPin);
    lcd.init();
    lcd.backlight();
    Serial.print("Analog Value: ");
    Serial.print(rainAnalog);
    Serial.print("\t Digital Value: ");
    Serial.println(rainDigital);  // 0 = Regen / 1 = kein Regen
    if (rainDigital == 1) {
      lcd.print("Kein Regen");
    } else {
      lcd.print("Regen");
    }

    if (rainDigital == 1) {
      TuerAuf();
    } else {
      TuerZu();
    }

    /*  Dasselbe - auch bei WHILE
     if (rainDigital == 1) {
      TuerAuf();
    } 
    if (rainDigital == 0) {
        TuerZu();
    }
    */
    delay(500);

    digitalWrite(rainSensorPowerPin, LOW);
    delay(2000);
    int feuchte_1 = map(analogRead(FEUCHTE_PIN_1), 0, 700, 100, 0);  // Umrechnung von ADC-Wert zu Prozent
    int feuchte_2 = map(analogRead(FEUCHTE_PIN_2), 0, 700, 100, 0);  // Umrechnung von ADC-Wert zu Prozent
    int feuchte_3 = map(analogRead(FEUCHTE_PIN_3), 0, 700, 100, 0);  // Umrechnung von ADC-Wert zu Prozent
    int feuchte_4 = map(analogRead(FEUCHTE_PIN_4), 0, 700, 100, 0);  // Umrechnung von ADC-Wert zu Prozent
    int feuchte_5 = map(analogRead(FEUCHTE_PIN_5), 0, 700, 100, 0);  // Umrechnung von ADC-Wert zu Prozent
    int feuchte_6 = map(analogRead(FEUCHTE_PIN_6), 0, 700, 100, 0);  // Umrechnung von ADC-Wert zu Prozent

    if (feuchte_1 < FEUCHTE_THRESHOLD_LOW) {
      // Schalte Pumpe 1 ein, wenn die Bodenfeuchte zu niedrig ist
      digitalWrite(PUMP_PIN_1, HIGH);
    } else if (feuchte_1 > FEUCHTE_THRESHOLD_HIGH) {
      // Schalte Pumpe 1 aus, wenn die Bodenfeuchte hoch genug ist
      digitalWrite(PUMP_PIN_1, LOW);
    }
    lcd.init();
    lcd.backlight();
    lcd.setCursor(0, 0);
    lcd.print("F1: ");
    lcd.print(feuchte_1);
    lcd.setCursor(10, 0);
    lcd.print("F2: ");
    lcd.print(feuchte_2);
    lcd.setCursor(0, 1);
    lcd.print("F3: ");
    lcd.print(feuchte_3);
    lcd.setCursor(10, 1);
    lcd.print("F4: ");
    lcd.print(feuchte_4);
    lcd.setCursor(0, 2);
    lcd.print("F5: ");
    lcd.print(feuchte_5);
    lcd.setCursor(10, 2);
    lcd.print("F6: ");
    lcd.print(feuchte_6);
    lcd.backlight();

    delay(5000);
    if (feuchte_2 < FEUCHTE_THRESHOLD_LOW) {
      digitalWrite(PUMP_PIN_2, HIGH);
    } else if (feuchte_2 > FEUCHTE_THRESHOLD_HIGH) {
      digitalWrite(PUMP_PIN_2, LOW);
    }
    if (feuchte_3 < FEUCHTE_THRESHOLD_LOW) {
      digitalWrite(PUMP_PIN_3, HIGH);
    } else if (feuchte_3 > FEUCHTE_THRESHOLD_HIGH) {
      digitalWrite(PUMP_PIN_3, LOW);
    }
    if (feuchte_4 < FEUCHTE_THRESHOLD_LOW) {
      digitalWrite(PUMP_PIN_4, HIGH);
    } else if (feuchte_4 > FEUCHTE_THRESHOLD_HIGH) {
      digitalWrite(PUMP_PIN_4, LOW);
    }
    if (feuchte_5 < FEUCHTE_THRESHOLD_LOW) {
      digitalWrite(PUMP_PIN_5, HIGH);
    } else if (feuchte_5 > FEUCHTE_THRESHOLD_HIGH) {
      digitalWrite(PUMP_PIN_5, LOW);
    }
    if (feuchte_6 < FEUCHTE_THRESHOLD_LOW) {
      digitalWrite(PUMP_PIN_6, HIGH);
    } else if (feuchte_6 > FEUCHTE_THRESHOLD_HIGH) {
      digitalWrite(PUMP_PIN_6, LOW);
    }
  }
}

Dann musst Du Dir halt merken, dass das Öffnen schon läuft.

Gruß Tommy

Ja, wie?? In einer Variablen? Also doch n ==1 oder n > 0?
Und wie frage ich sie dann ab?

Kleiner Tipp?

Das ist der Sinn des ganzen.
loop() wird dauernd durchlaufen und stellt normalerweise fest, dass nichts zu tun ist.

while Schleifen und delays stören nur.

Serial.println(rainDigital);  // 0 = Regen / 1 = kein Regen
   if (rainDigital == 1) {
     lcd.print("Kein Regen");
   } else {
     lcd.print("Regen");
   }

Was schreibt Ser Mon?

 lcd.setCursor(0, 1);
  lcd.print("Datum: ");
  lcd.print(now.day(), DEC);
  lcd.print('.');
  lcd.print(now.month(), DEC);
  lcd.print('.');
  lcd.print(now.year(), DEC);

Bei now month() wird die die Anzeige tanzen, warum nicht

 lcd.setCursor(0, 1);
  lcd.print("Datum: ");
  lcd.print(now.day(), DEC);
  lcd.print('.');
  if (now.month() <10 ) lcd.print("0"); //          sieht schöner aus  8.07. 2023 , bei dir 8.7.2023
  lcd.print(now.month(), DEC);
  lcd.print('.');
  lcd.print(now.year(), DEC);
bool openRun = false;
...
// wenn ausgelöst:
openRun = true;

Gruß Tommy

gib deiner Tür einen Status

bool isDoorClosed = false.

Diesen Status kannst du nun jeweils am Ende deiner tuerAuf() und tuerZu() Funktion entsprechend setzen.
Damit kannst du auch in deinen Bedingungen auf isDoorClosed abfragen und entsprechend reagieren (oder bleiben lassen).

Danke, mit "Tanzen" meinst du bestimmt, die fehlende Null bei einstelligen Monatszahlen. Habs geändert, sieht so wirklich besser aus, habs auch beim Tag gemacht. Danke!

Ich habe dein Projekt und die früheren Fragen nicht mitverfolgt.
Deshalb habe ich einige Detailfragen zu deinem Code:

In deiner function TuerZu wird ein Digitaleingang abgefragt

  while (digitalRead(ST01)) {
    stepper.run();
  }

in gleicher Art und Weise bei function TuerAuf()

  while (digitalRead(ST02)) {
    stepper.run();
  }

Sind die Digitaleingänge ST01 und ST02 mit Endschaltern verbunden die ein Signal liefern wenn
eine Endposition erreicht ist?

Wenn ja dann könnte man auch einfach mit Absolutkoordinaten arbeiten.

Momentan setzen deine Functions TuerZU() und TuerAuf() immer wieder neu

  stepper.setCurrentPosition(0);

und dadurch führt dann ein neuer Aufruf mit

  stepper.moveTo(-180000);

dazu das wieder neu Schritte ausgegeben werden.

Wenn du

  stepper.setCurrentPosition(0);

nur einmal nach der Referenzfahrt aufrufst.

und dann in function TuerAuf() immer nur

  stepper.moveTo(180000);

aufrufst
ohne stepper.setCurrentPosition(0);
dann werden einmal Schritte ausgegeben wenn sich der interne Positionszähler der AccelStepper-library noch nicht auf 180000 befindet
Wenn die Position 180000 erreicht ist und du ruft ein weiteres mal
TuerAuf() auf
dann stellt die library fest
wo bin ich? Ist-Position 180000
wo soll ich hinfahren Soll-Position 180000
Anzahl Schritte um von Ist-Position zu Soll-Position zu fahren 180000 - 180000 = 0 Schritte
OK ich gebe 0 Schritte aus.

Und genauso mit mit Türzu()
wenn Tuer gerade auf ist dann ist das Ist-Position 180000
Tuer zu hat Position 0
in function TuerZu()

  stepper.moveTo(0); // hier muss 0 stehen = Tuer-zu-Position als Absolutkoordinate
  while (digitalRead(ST01)) {
    stepper.run();
  }

Wenn die Tür wirklich zu ist dann ist die Ist-Position 0
damit werden für die Soll-Position 0

Anzahl Steps um von Ist-Position zu Soll-Position zu kommen
Soll-Position - Ist-Position
0 - 0 = 0 Steps ausgeben. Passt

Die beiden modifizierten functions als ganzes

void TuerZu() {
  // Zur "Home" Position fahren
  digitalWrite(enablePin, LOW);
  //stepper.setMaxSpeed(1700);
  //stepper.setSpeed(1000);
  //stepper.setAcceleration(700);
  stepper.moveTo(0);//stepper.moveTo(-180000);
  while (digitalRead(ST01)) {
    stepper.run();
  }
  // HERAUSNEHMEN ! // stepper.setCurrentPosition(0);
  digitalWrite(enablePin, HIGH);
  digitalWrite(enablePin, LOW);
  stepper.moveTo(stepper.currentPosition() + 600);
  stepper.runToPosition();
  // HERAUSNEHMEN ! // stepper.setCurrentPosition(0);
  digitalWrite(enablePin, HIGH);
}


void TuerAuf() {
  digitalWrite(enablePin, LOW);
  //stepper.setMaxSpeed(1700);
  //stepper.setSpeed(1000);
  //stepper.setAcceleration(700);
  stepper.moveTo(180000); // als ABSOLUT-koordinate anfahren
  while (digitalRead(ST02)) {
    stepper.run();
  }
  // HERAUSNEHMEN ! // stepper.setCurrentPosition(0);
  digitalWrite(enablePin, HIGH);
  digitalWrite(enablePin, LOW);
  stepper.moveTo(stepper.currentPosition() - 600);
  stepper.runToPosition();
  // HERAUSNEHMEN ! // stepper.setCurrentPosition(0);
  digitalWrite(enablePin, HIGH);
}

Wenn du das Position = nullsetzen
mit dem function-call

  stepper.setCurrentPosition(0);

' nur einmal in in setup() machst
dann kann man statt einer extra booleschen Variable
auch direkt die aktuelle Position abfragen
mit dem function-call

currentPosition();

vgs

Nachtrag:

Wenn du das so machen willst dann empfiehlt es sich statt der hart codierten Zahlen

"0" und "180000" zwei Konstanten zu verwenden.

long const TuerZuPosition = 0;
long const TuerAufPosition = 180000;

vgs

Ja, genau das ist so. Ich habe nach Erreichen und Auslösen des Tasters 600 - 700 Steps in die andere Richtung bewegt, damit der Taster nicht ständig gedrückt bleibt (mechanische Entlastung)

Wenn die Uhr erstmal gestellt ist, willst du diese Zeile auf Kommentar setzen und den Sketch nochmal übersetzen und laden.

Ja das ist gut.
Eine "Profi"-Referenzfahrt (zumindest wie ich das kennengelernt habe) macht das so:

Fahre zum Endschalter hin bis der Endschalter betätigt ist
Fahre gaaanz langsam so lange vom Endschalter herunter bis der Endschalter nicht mehr betätigt ist.
Dann müsstest du noch nachschauen ob der Endschalter in dieser Position mechanisch wirklich entlastet ist. Wenn Endschalter noch nicht mechanisch entlastet ist eine feststehende Anzahl Schritte weiterfahren bis entlastet ist.

Danke, habe ich auch so vor. Habs auch gleich gemacht.
Zeile aus ARDUINO.IO Beispiel

Hallo Tommy,

könntest du das bitte mal konkret machen.
Habe ein bissel probiert und bin noch nicht zum guten Ergebnis gekommen.
Muss noch viiiiel lernen!

Danke,

Gerhard

Sehr ausführlich erklärt, hast dir wirklich sehr viel Mühe gemacht!
Ich habe alles verstanden und versuche jetzt, Zeile für Zeile zu verändern.

Nebenbei: Musste lernen (schmerzliche Erfahrungen gemacht), dass jegliche Veränderung im Programm auch wohl sofort im SKETCH gespeichert wird. Wenn das Programm Fehler aufweist, dann kann man das zuvor gespeicherte Programm auch NUR mit diesen Fehlern wieder laden. Jetzt habe ich mir zur Angewohnheit gemacht, das bisher funktionierende Programmteil 2x zu speichern, bevor ich weiterarbeite. 1x im Kopierordner und einmal im Original.

Es gibt eine Archivierungsfunktion
image

Die erzeugt eine ZIP-Datei vom momentanen Zustand der *.ino-Datei
Das würde ich immer dann machen wenn ein funktionierender Zustand erreicht ist.

Hast du schon mal die Tastenkombination Strg-Z ausprobiert? Damit kann man Änderungen rückgängig machen. Selbst nach dem compilieren und flashen. Sowohl in der IDE Version 1.8.19 als auch in der IDE 2.1.1

vgs

STRG+Z und STRG+T regelmäßig, das andere ist mir neu und ab jetzt auch Archive Sketch. Danke!
Der neue Code
´´´
void TuerZu() {
stepper.setAcceleration(400);
digitalWrite(enablePin, LOW);
stepper.moveTo(0);
while (digitalRead(ST01)) {
stepper.run();
}
digitalWrite(enablePin, HIGH);
digitalWrite(enablePin, LOW);
stepper.moveTo(stepper.currentPosition() + 700);
stepper.runToPosition();
digitalWrite(enablePin, HIGH);
}
´´´
funktioniert super. Ist kürzer uns spart Speicher.
Habe noch stepper.setAcceleration(400); eingefügt, der Schlitten fährt sonst zu lange weiter, bevor er stoppt.

Hallo Tommy,

könntest du das bitte mal konkret machen.
Habe ein bissel probiert und bin noch nicht zum guten Ergebnis gekommen.
Muss noch viiiiel lernen!

Danke,

Gerhard

Das kann eigentlich nicht sein, dass der Schlitten zu lange weiterfährt. Jedenfalls dann nicht wenn der Schrittmotor auf eine Art und Weise betrieben wird dass keine Schrittverluste auftreten.

setAcceleration() macht das wie die Funktion heißt
Lege eine Beschleunigung fest.

Wenn man den Beschleunigungswert zu hoch setzt dann verliert der Schrittmotor unter Umständen Schritte. Aber so soll er nicht betrieben werden.

Das ist im übrigen auch eine Voreinstellung die so lange gültig ist bis man einen function-call mit einem anderen Zahlenwert macht.
Das bedeutet du machst den function-call

stepper.setAcceleration(400);

einmal im setup() und dann gilt diese Einstellung.

vgs