Break funktioniert nicht nach Programmstart, Schleife wird immer neu aufgerufen

Versuch eines HOMING Programms, das nach Programmstart einmalig ausgeführt werden soll bzw. nach Stromausfall, wenn z.B. der Schlitten einer Linearführung zwischen StartStop- und EndStop- Schalter stehen geblieben ist.
Ich habe meine Schritte und Gedanken dazu im Sketch kommentiert. Es funktioniert alles gut, bis auf das Verlassen der Routine.
Die Kommentare habe ich für mich ausführlich angegeben, da ich mich erst seit ein paar Tagen mit Arduino beschäftige. Werde in diesem Monat 78 Jahre alt und bin "zu jung" zum Nichtstun!

Zum Test gebe ich stellvertretend einen Text im "Hauptprogramm" aus.
Zum Verlassen der Schleife wollte ich "break" verwenden. "error: break statement not within loop or switch!!!"

In der Dokumentation habe ich gelesen, dass break dazu dient, aus einer loop harauszukommen. Das ist hier wohl nicht der Fall.

Meine Frage: Wie wird die erste Routine sauber beendet, dass sie während des Programmablaufes nicht wieder aufgerufen wird, sondern nur zu den Bedingungen, wie oben benannt, also zum Programmstart und nur einmal?

Momentan fährt der Schlitten zum Taster POS1, wenn gedrückt, um n Schritte in Richtung POS2, aber dann wieder zurück auf POS1. Das Spiel wiederholt sich in einer Endlosschleife.

Es gibt bestimmt eine einfache Lösung? Bitte um eure Hilfe, vielen Dank schon mal im Voraus.
Hier der Code:

// Versuch eines HOMING Programms, das nach Programmstart einmalig ausgeführt werden soll bzw. nach Stromausfall,
// wenn z.B. der Schlitten der Linearführung > StartStop- oder > EndStop- Schalter stehen geblieben ist: If home_erreicht
//Anschlüsse am TS 6600: PUL-, DIR- und ENA- an gemeinsame Masse
// Pinbelegung
const int DIR = 4;                    // für Links: DIR = HIGH
const int STEP = 5;                   // Entspricht "PUL" am TS 6600
const int ENA = 6;
const int STOP1 = 7;                  // Links ==> DIR = HIGH
const int STOP2 = 8;                  // Rechts

// Variablen definieren
int steps = 0;
int home = 0;
bool home_erreicht = false;     			      // Wird auf true gesetzt, wenn Homing erfolgreich ausgeführt wurde und verhindert, dass die Schleife noch einmal durchlaufen wird
int n = 800;                			    // Anzahl der Schritte hier anpassen je nach Stellung der Switches beim TS 6600
int pos = 0;                  			// Hier setze ich die Position des Schlittens und addiere die Schritte bei Abfrage POS1


void setup() {
  pinMode(DIR, OUTPUT);
  pinMode(STEP, OUTPUT);
  pinMode(ENA, OUTPUT);
  pinMode(STOP1, INPUT_PULLUP);
  pinMode(STOP2, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  // Homing
  digitalWrite(ENA, LOW);   			          // Motor aktivieren
  digitalWrite(DIR, LOW);    			          // Richtung festlegen, abhängig von den Anschlüssen der Motorwicklung 
  while (digitalRead(STOP1) == HIGH) {    	// Bewegung in Richtung STOP1
    digitalWrite(STEP, HIGH);
    delayMicroseconds(300);
    digitalWrite(STEP, LOW);
    delayMicroseconds(300);
    pos++;                        			    // Hier werden die Schritte bis zur POS1 aufaddiert
}
  
// Schlitten um n STEPs Zurückfahren, n muss noch ermittelt werden und ist abhängig von meinem Stepperdriver TS 6600 (Schalterstellung bzgl. Microsteps)
    while (digitalRead(STOP1) == LOW) {      	// Der Schalter STOP1 ist aktiviert, ab jetzt Bewegung in RICHTUNG STOP2 
   
   // MISSGLÜCKTER VERSUCH
   // *********************************************************************
    /*digitalWrite(STEP, LOW);
    delayMicroseconds(300);		
    delayMicroseconds(500);
    digitalWrite(DIR, HIGH);                  // Richtung umkehren
    digitalWrite(STEP, HIGH);                     	
    delayMicroseconds(500);			
    pos--;
    if (pos <= -n) { 				// Maximale Anzahl an Schritten erreicht?*/
    // ******************************************************************
  digitalWrite(DIR, HIGH); // Richtung umkehren
  for (int i = 0; i < n; i++) {
    digitalWrite(STEP, HIGH);
    delayMicroseconds(500);
    digitalWrite(STEP, LOW);
    delayMicroseconds(500);
    // break;
  }
     digitalWrite(ENA, HIGH); 			// Motor deaktivieren
     home_erreicht=true;
 Serial.print(home_erreicht);
if (home_erreicht) {
   Serial.print("Home erreicht");
  } // break;  error: break statement not within loop or switch!!!
        Serial.print("Hier kommt der Code für das Hauptprogramm hin");
    // ...
}
}

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.

Ihre HOMING muss sich also innerhalb von setup() befinden, damit sie nur einmal ausgeführt wird – nicht innerhalb von loop()

break; beendet eine for- oder while- loop statement

Danke, und wie rufe ich das deutsche Forum auf?
LG.,
Gerhard

Hier ist der Link zur Kategorie "Deutsch"

Wurde bereits verschoben. :wink:

Verfahre Deinen Antrieb nicht im loop() sondern im setup() solange, bis Dein Endschalter ausgelöst hat.
Geht ganz ohne break und sonstige Konstruktionen.

Bei setup gibt es ein paar Einschränkungen, weshalb ich in so einem Fall eher eine Schrittkette bevorzuge, deren erster Schritt nur einmalig verwendet wird. Im Prinzip so:

byte schritt = 0;

void setup() {
	...
}

void loop() {
  switch (schritt)
  {
    case 0;  // Homing
      ...
      break;
    case 1:
      ...
      break;
	...
    case 25:
      schritt = 1;
      break;
  }
}

Zusatztipp: Schrittmotoren lassen sich einfach mit der Bibliothek MobaTools bewegen.

Entgegen anderslautender Stimmen muss ich dir berichten, dass loop() im Arduino Umfeld eine Funktion ist.
loop() ist keine Schleife.
Du hast dich verwirren lassen.

Das sehe ich nicht so!

Möglicherweise habe ich die Anfrage nicht verstanden. Ich werde an meinem Deutsch arbeiten.

Doch, ich glaube schon :slightly_smiling_face:

Ich störe mich an dem "muß", denn einmalige Aktionen können in setup ablaufen, müssen aber nicht, sondern können auch in loop bearbeitet werden. Ich vermute, auch unser Bienchen wollte sowas summen.

Beim Anfahren eines Referenzpunktes, das verstehe ich unter "Homing", wartet man ja während der Bewegung auf das Referenzsignal. In setup landet das dann in einer blockierenden while-Schleife, während in loop eine einfache if-Bedingung verwendet werden kann, was andere Aktivitäten wie beispielsweise eine Anzeige ermöglicht. Daher plädiere ich für eine Verschiebung des "Homings" nach loop.

Ich auch.

Jedes mir bekannte Maschinchen, welches "Homing" Kann/muss/braucht, hat einen Knopf/Menue dafür.
Ohne, dass man Reset drücken, oder den Stecker ziehen muss.

Danke, das wars. Werde nun weiter am Projekt arbeiten. Stehe mit der Fertigstellung im Wettbewerb mit dem Reifegrad der Tomaten im Gewächshaus, ich schätze, dass ich für die ersten zu spät komme. Dafür klappt die Türöffnung in Abhängigkeit von Zeit, Temperatur und Regen ab heute heute prima. Nochmals vielen Dank.
Jetzt werde ich versuchen, den Code zu "verschlanken", indem ich nun lernen will, wie Funktionen aufgebaut sind. Konkret, ich will den hier vorliegenden Programcode als Funktion Tür bewegen (MoveDoor) irgendwo im Kopfbereich einsetzen und dann während des Programms mit Parameter für OpenDoor und CloseDoor, um bei der englischen Schreibweise zu bleiben, aufrufen.

Muss nur noch lernen, wo die Funktion ihren Platz hat.

Das ist Arduino egal.
Die IDE nimmt Dir viel ab.

Zum lernen bau Dir eine Funktion, mit der Du den Ausgangspunkt anfährst.
In der Funktion darf kein delay(), kein while... und auch sonst nix blockierendes drin sein.
Die Funktion soll einen bool zurückgeben.
Inhaltlich false, solange der Endschalter nicht erreicht ist und true, wenn erreicht.

Wenn Du das hast, dann kannst Du die zum einen wiederverwenden und zum anderen kannst Du damit experimentieren, wie auf den Rückgabewert reagiert werden kann.

(Tipp: Im setup() den Wert mittes while() abfragen :wink: )

Danke für den Tipp! Habe mir nach Anleitung und Hilfe von Heli Mech ein "Glas- Cockpit" G1000NXI für den MSFS2020 für die Cessna 172 gebaut. Habe mit ARDUINO MEGA und Mobiflight das Teil zusammengesetzt. Mobiflight
Heute habe ich deinen Rat befolgt und das neue Release 9.7 mit verbesserter Stepper-Unterstützung heruntergeladen. Muss erst die Doku lesen, vielleicht nehme ich das wahr. Funktion hat erst mal Vorrang.

Vielen Dank für die guten Ratschläge. Habe sie befolgt und meine Funktionen funktionieren so, wie ich es will bei Schonung der Ressourcen, da ich noch weitere von Funktionen in Abhängigkeit von Tempertur innen/ aussen, Uhrzeit, Feuchte usw. integriert habe.
Dabei ist mir ein für mich- trotz Nachlesens der einzelnen Funktionen in der Bibliothek AccelStepper.h etwas merkwürdiges Verhalten aufgetreten.
Konkret: Ich wollte den Teil

digitalWrite(ENA, LOW);   			          
  digitalWrite(DIR, LOW);    			          
  while (digitalRead(STOP1) == HIGH) {    	
  digitalWrite(STEP, HIGH);
  delayMicroseconds(300);
  digitalWrite(STEP, LOW);
  delayMicroseconds(300);
  pos++;            

... usw.

ersetzen durch Aufruf der Stepper- library

#include <AccelStepper.h>
AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin); 

 // Hier soll der Schrittmotor einmalig im Setup an ST01 fahren und diesen aulösen
  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(100);
  stepper.moveTo(-1000000);
  while (digitalRead(ST01)) {
    stepper.run();
  }
  stepper.stop();
}

void loop() {
  // Und hier soll der Schrittmotor von ST01 in Richtung ST02 um n Steps sich bewegen, 
 // n wird ermittelt nach Einbau des Gestänges für einen Türöffner:

  stepper.moveTo(stepper.currentPosition() + n);
  while (digitalRead(ST02)) {
    stepper.run();
  }
  
  // HIER setze ich die Position auf HOME zurück.
  stepper.setCurrentPosition(0);
}

Diese Funktion wird danach als "OpenDoor" bzw. "CloseDoor" deklariert und bei Bedarf aufgerufen.

Frage: Warum dauert es so lange, bis MaxSpeed erreicht ist? Das bedeutet hier konkret, dass der sich bewegende Schlitten nach Auslösen des Stop Schalters sich trotzdem weiterbewegt, bis laaaaangsam von 1000 auf 0 zurückgezählt wird. Ich habe es zum Glück händisch ausgelöst, sonst wäre der Schlitten über den Stopschalter herausgefahren und die Trapezstänge u.U. deformiert, (NEMA 24 und TB6600)

Also, was muss geschrieben werden, dass der Motor sofort nach Auslösen des Schaltkontaktes stehenbleibt, um danach in die andere Richtung bewegt werden kann? Tipp? Vielen Dank für Drüberschauen.

Ja, „muß“ war wahrscheinlich das falsche Wort und Sie können es auf jeden Fall auf dem loop() halten

Ich habe dies vorgeschlagen, weil ich vermutete, dass das Programm nichts zu tun hatte, bis es seine Konfiguration kannte, was bedeutet, dass es keinen anderen Code zum Ausführen gibt, sofern keine Referenzierung durchgeführt wird. Es entspricht dem begin()-Code, den Sie für andere Services haben.

Das könnte auch eine falsche Annahme gewesen sein.

Es gibt nicht die Stepper-Bibliothek, sondern viele, welche verwendest Du?

Bei den von mir verwendeten MobaTools gibt es dies:

void myStepper.stop( );
Hält den Motor sofort an (Notstop).

Ich würde es aber vorziehen, die Rampe zu ändern.

Jede motorgetriebene Vorrichtung muß einen Nothalt durch Ausschalten der Motorspannung haben.

Auch ich könnte etwas Falsches angenommen haben, wer weiß das schon :slightly_smiling_face:

Probeweise habe ich die Parameter angepasst:

void setup() {
  pinMode(ST01, INPUT_PULLUP);
  pinMode(ST02, INPUT_PULLUP);
  pinMode(enablePin, OUTPUT);
  digitalWrite(enablePin, LOW); // Enable the driver

    stepper.setMaxSpeed(500);
   stepper.setSpeed(500); //Konstante Geschwindigkeit eingestellt
  stepper.setAcceleration(500); // Lasse ich die Beschleunigung weg, dann ruckelt er nur schrittweise ganz langsam vor
  stepper.moveTo(-100000);
  while (digitalRead(ST01)) {
    stepper.run();
  }
  stepper.stop();
}

mit dem Ergebnis, dass der Taster im Toleranzbereich bewegt wird. Damit könnte ich leben, ist aber nicht die Antwort auf die Frage, wie der Schrittmotor SOFORT gestoppt werden kann, wenn Taster auf LOW

Meine Annahme basierte auf dieser Aussage

➜ dh beim Booten, also wird setup() ausgeführt.

Ja, verstehe ich, halte ich aber für eine ganz schlechte Idee. Nach einem Stromausfall sollte ein Mensch die Situation beurteilen und Entscheidungen treffen, wie es weitergehen soll. Bei einer CNC-Fräsmaschine stelle ich mir einen automatischen Neustart gefährlich vor.

Für mich gehören nach einem Reset die Tasten wie "Einrichtbetrieb", "Schleichfahrt" und "Referenzfahrt" abgefragt und eine Anzeige mit Werten gefüllt.

Da bin ich beruflich vorbelastet. Möglicherweise macht der Schrittmotor aber auch was ganz anderes.