Sketch pausieren und wieder starten lassen

Hallo, ich würde gerne mein Programm per Taster pausieren und bei erneuten betätigen wieder von der gleichen Stelle starten können.
Leider weiß ich nicht wie dieser Code ausschauen sollte.

Mein bisheriges Programm:

int motor = 10;
int in1 = 9;
int in2 = 8;
int f = 0;
int taster = 13;

void setup()
{
  pinMode(motor, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);

  pinMode(taster, INPUT);
  
  digitalWrite(in1, HIGH);  //Rechtsdrehend
  digitalWrite(in2, LOW);
}

void loop()
{

  if(digitalRead(taster)==HIGH)
  {
    //Programm pausieren
    
    //Wenn Taster nochmal HIGH dann wieder Programm an der beendeten Stelle weiterlaufen lassen
  }
  
  if(f == 0)  //Nur ein Durchgang
  {
  analogWrite(motor, 0);  //Aus für 3 Sek.
  delay(3021);

  analogWrite(motor, 110);  // Konstant für 25 Sek.
  delay(24800);

    for(int i = 108; i <= 255; i++) //Beschleunigen
    {
      analogWrite(motor, i);
      delay(100);
    }

    delay(4000);
    for(int j = 255; j >= 108; j--) //Entschleunigen
    {
      analogWrite(motor, j);
      delay(80);
    }

    delay(2000);
    for(int k = 108; k <= 255; k++) //Beschleunigen2
    {
      analogWrite(motor, k);
      delay(100);
    }

    delay(4000);
    for(int l = 255; l >= 108; l--) //Entschleunigen2
    {
      analogWrite(motor, l);
      delay(80);
    }

    delay(2000);
    for(int m = 108; m <= 255; m++) //Beschleunigen3
    {
      analogWrite(motor, m);
      delay(100);
    }

    delay(4000);
    for(int n = 255; n >= 108; n--) //Entschleunigen3
    {
      analogWrite(motor, n);
      delay(80);
    }
  
    analogWrite(motor, 0); //Motor aus
    f++;
  }
}

Vielleicht kann mir einer von euch helfen.
LG

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.

Mehrere Bedingungen und Zeitabläufe unter einen Hut bekommt man hin, wenn man das BlinkWithoutDelay Prinzip auf die loop() anwendet.
Ein Durchlauf von loop wird dann so schnell, dass man leicht den aktuellen Zustand ( per Taster geperrt oder frei ) jederzeit auswerten kann.

Nennt sich auch gern Zustandsautomat (state machine), wobei solche Begriffe nicht abschreckend wirken sollten.

Ihr Code ist voll von delay(), daher ist das Lesen des Zustands der taster am Anfang der loop() nicht sehr effektiv, um den Prozess sofort zu stoppen.

Sie müssen den Code neu strukturieren und das delay() loswerden, damit jeder Schritt superschnell ist.

void loop() {
    if(digitalRead(taster)==LOW) {
      einenSchrittAusfuhren(); // keine delay(). Dies muss bei Bedarf einen Schritt machen und schnell zurückkommen
    }
}

Using millis() for timing. A beginners guide
Several things at the same time

Sage mal, ist die Beschleunigung und Entschleunigung 3mal das Gleiche?

Dann kannst Du das als Schleife laufen lassen.
Das loop() wäre dadurcch entschieden kürzer...

void loop()
{
  if (digitalRead(taster) == HIGH)
  {
    //Programm pausieren
    //Wenn Taster nochmal HIGH dann wieder Programm an der beendeten Stelle weiterlaufen lassen
  }
  if (f == 0) //Nur ein Durchgang
  {
    analogWrite(motor, 0);  //Aus für 3 Sek.
    delay(3021);
    analogWrite(motor, 110);  // Konstant für 25 Sek.
    delay(24800);
    for (byte b = 0; b < 3; b++)
    {
      for (int i = 108; i <= 255; i++) //Beschleunigen
      {
        analogWrite(motor, i);
        delay(100);
      }
      delay(4000);
      for (int j = 255; j >= 108; j--) //Entschleunigen
      {
        analogWrite(motor, j);
        delay(80);
      }
      delay(2000);
    }
    analogWrite(motor, 0); //Motor aus
    f++;
  }
}

Allerdings wird das pausieren nichts mit dem delay() da drinnen.
In der Zeit wird die Taste nicht abgefragt.

Das was Du da hast ist eigentlich eine Schrittkette. Das 3x drehen im Kreis für Beschleunigung / Entschleunigung lässt sich damit auch machen, in dem ein Zähler gesetzt wird und jedesmal geschaut wird, ob nochmal oder dann ans Ende gegangen wird.

Durch die Schrittkette braucht es auch keine explizite Prüfung, ob Du schon mal durchgelaufen bist. (Dein f++);

Die Schwierigkeit besteht darin, das während der Pausenzeit die Laufzeit nicht weiterzählen darf.

Was mir noch nicht klar war, ob während der Pause der Motor weiter läuft. Ich gehe davon aus, das dem so ist...
Ich hab mal was probiert.

Ob das das ist, was Du willst, weiss ich nicht.
Aber ich habs kommentiert und wenn Du fragen hast, frag.

// Forensketch - Mittels Taste pausieren
// basiert auf https://forum.arduino.cc/t/sketch-pausieren-und-wieder-starten-lassen/1040603
// kompiliert fehlerfrei, ungetestet
const byte motorPin = 10;
const byte in1 = 9;
const byte in2 = 8;

const byte tasterPin = 13;
const byte minPwm = 108;
const byte maxPwm = 255;
byte myPwm = 0;
byte zyklus = 0;
enum {start, speedstart, pauseone, speedup, pausemaxspeed, speeddown, pauseminspeed, aus};
byte status = start;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  pinMode(motorPin, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(tasterPin, INPUT);
  digitalWrite(in1, HIGH);  //Rechtsdrehend
  digitalWrite(in2, LOW);
}

void loop()
{
  antrieb();
}

bool pauseTaste(uint32_t &switchTime )
{
  static bool lastSwitch = false;
  static uint32_t stopTime = 0;
  static uint32_t lastmillis = 0;
  static bool isPause = false;
  if (digitalRead(tasterPin))                       // Taste gedrückt?
  {
    if (!lastSwitch)                                // Vorher nicht gedrückt?
    {
      lastSwitch = HIGH;                            // Merken
      lastmillis = millis();                        // Zeit merken
      isPause = !isPause;                           // Variable ändern
      if (isPause)                                  // Wenn erstmals gesetzt
      {
        stopTime = millis() - switchTime;           // Merke die bisher abgelaufene Zeit
      }
      else                                          // Wenn Pauseende
      {
        switchTime = millis() - stopTime;           // wird die laufuźeit mit der alten Zeit gesetzt
      }
    }
  }
  else if (millis() - lastmillis > 50)              // Taste losgelassen - BounceTime
  {
    lastSwitch = LOW;                               // Merken
  }
  return isPause;                                   // gibt den Zustand zurück
}



void bewegen(const byte endPoint, byte &speed)      // PWM berechnen
{
  if (endPoint > speed)
  {
    speed++;
  }
  else if (endPoint < speed)
  {
    speed--;
  }
  analogWrite(motorPin, speed);
}


void antrieb()
{
  static uint32_t lastmillis = millis();
  if (!pauseTaste(lastmillis))              // wenn Pausentaste gedrückt
  {
    return;                                 // dann ist hier Ende
  }
  switch (status)
  {
    case start:
      analogWrite(motorPin, myPwm);         // einstellen
      lastmillis = millis();                // Zeit merken
      status = speedstart;                  // nächsten Schritt auswählen
      break;
    case speedstart:
      if (millis() - lastmillis >= 3021)    // Wenn Zeit abgelaufen
      {
        myPwm = minPwm;                     // neuen Speed setzen
        analogWrite(motorPin, myPwm);       // einstellen
        lastmillis = millis();              // Zeit merken
        status = pauseone;                  // nächster Schritt
      }
      break;
    case pauseone:
      if (millis() - lastmillis >= 24800)   // Wenn Zeit abgelaufen
      {
        lastmillis = millis();              // Zeit merken
        bewegen(maxPwm, myPwm);             // Speed setzen
        status = speedup;                   // nächster Schritt
      }
      break;
    case speedup:
      if (millis() - lastmillis >= 100)     // Wenn Zeit abgelaufen...
      {
        bewegen(maxPwm, myPwm);
        lastmillis = millis();
      }
      if (myPwm == maxPwm)
      {
        status = pausemaxspeed;
      }
      break;
    case pausemaxspeed:
      if (millis() - lastmillis >= 4000)
      {
        bewegen(minPwm, myPwm);
        lastmillis = millis();
        status = speeddown;
      }
      break;
    case speeddown:
      if (millis() - lastmillis >= 80)
      {
        bewegen(minPwm, myPwm);
        lastmillis = millis();
      }
      if (myPwm == minPwm)
      {
        zyklus++;                             // jeden Umlauf merken
        if (zyklus < 3)                       // solange nicht erfüllt
        { status = pauseminspeed; }           // weitermachen
        else
        {
          myPwm = 0;                          // sonst
          status = aus;                       // Ende
        }
      }
      break;
    case pauseminspeed:
      if (millis() - lastmillis >= 2000)
      {
        bewegen(maxPwm, myPwm);
        lastmillis = millis();
        status = speedup;                     // fang wieder an von vorn
      }
      break;
    case aus:
      analogWrite(motorPin, myPwm);           //Motor aus
      break;
  }
}
1 Like

Danke für den Tipp mit dem verkürztem Loop. Da hätte ich auch drauf kommen können.

Beim Betätigen des Tasters soll der Motor aufhören sich zu drehen. Allerdings soll die zuletzt gefahrene Geschwindigkeit gespeichert und bei erneuten betätigen des Taster mit der selben Geschwindigkeit fortfahren.

Danke trotzdem

Dann wäre meine Idee beim auslösen der Pause die Geschwindigkeit mit 0 schreiben und beim erneuten auslösen mit myPwm.

bool pauseTaste(uint32_t &switchTime )
{
  static bool lastSwitch = false;
  static uint32_t stopTime = 0;
  static uint32_t lastmillis = 0;
  static bool isPause = false;
  if (digitalRead(tasterPin))                       // Taste gedrückt?
  {
    if (!lastSwitch)                                // Vorher nicht gedrückt?
    {
      lastSwitch = HIGH;                            // Merken
      lastmillis = millis();                        // Zeit merken
      isPause = !isPause;                           // Variable ändern
      if (isPause)                                  // Wenn erstmals gesetzt
      {
        stopTime = millis() - switchTime;           // Merke die bisher abgelaufene Zeit
        analogWrite(motorPin, 0);    
      }
      else                                          // Wenn Pauseende
      {
        switchTime = millis() - stopTime;           // wird die laufuźeit mit der alten Zeit gesetzt
        analogWrite(motorPin, myPwm);
      }
    }
  }
  else if (millis() - lastmillis > 50)              // Taste losgelassen - BounceTime
  {
    lastSwitch = LOW;                               // Merken
  }
  return isPause;                                   // gibt den Zustand zurück
}

Super, danke ich werde das Testen wenn ich wieder zu hause bin.

Vielen Dank.

Hallo, wollte mich nur nochmal melden.
Funktioniert super. DANKE

Musst nur im void antrieb die negierung von der IF Abfrage vom pauseTaster aufheben.
Vielen Danke

1 Like

Danke für die Rückmeldung! Schick. Viel Spass damit.

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