Prozess an der richtigen Stelle pausieren

OK, kannte ich natürlich, habe ich nun noch einmal gelesen. Jedoch keinen Widerspruch gefunden, da ich keinen code als Bild gesendet habe und die Regeln diesbezüglich auch der Konjunktiv verwenden. Nun gut, ich hab's noch mal gelesen, da der Grund ja weiter unten schon genannt wurde, bleibt mir nur, Dich um eine Lösung zu bitten. Interessant ich darüber hinaus, warum sich der Arbeitszustand überhaupt wieder einstellt, müsste dort dann nicht Schluss sein?

Das ist unkritisch, es sollte bei erreichen der max. Temperatur unten angehalten werden, wenn der Prozessablauf "unten" angekommen ist. Dies, da das System Zugkräfte aufbaut, welche im Zustand "unten" gering sind und daher der Motor möglichst in dieser Position abkühlen sollte.

Doch, doch - ich muss das gross sehen, also so richtig gross. Und das ist mit dem Bildschirmfoto nicht schick.

So nu aber:

Das macht es.
Dir fehlt, um das richtig einzuordnen das Wissen, wann es zu warm wird.
Darum hatte ich in #18 die 5 Zeilen.
Ersetze mal die Ausgaben durch das:
[edit: Klammerfehler beseitigt]

    Serial.print(F("Temperatur: "));
    Serial.print(Motortemp);
    Serial.print(F(" °C \t"));
    Serial.print(F("warm: "));
    Serial.print(warm);
    Serial.print(F("\t heben: "));
    Serial.println(digitalRead(heben));
    Serial.print(F("\t senken: "));
    Serial.print(digitalRead(senken));
    Serial.print(F("\t kontakt oben: "));
    Serial.print(digitalRead(oben));
    Serial.print(F(" | kontakt unten: "));
    Serial.println(digitalRead(unten));

Wenn der senkenPIN von 0 auf 1 springt und die Temp drüber ist, muss es von warm 0 auf warm 1 springen.
Und jetzt bleibt es solange in diesem Zustand (also heben 1 und senken 1 und warm 1 und oben 1 und unten 0) bis warm wieder 0 wird - sprich die Hysterese durchlaufen ist.
Wenn warm 0 wird, wird auch heben 0, unten wird 1. Das solange bis oben angeschlagen.

So zumindest die Theorie...

Und hier siehst Du, das Du den Code rauskopieren kannst. Ich kann das mit Deiner Meldung oben nicht...

Nein warum denn?
Es gibt ja weder Exit oder Verriegelung.
Kein delay() kein while() in Dauerschleife.
Deine Dauerschleife ist loop()
Und weil das blockadefrei programmiert ist (das wirste noch öfter lesen) macht es das immer wieder.

Wenn Du einen Exit willst, oder nach dem xten Mal anhalten nicht emhr starten, dann musst Du einen Zähler nehemen und am Ende verriegeln.

OK, hab's , es lag am Umgang mit meinem Versuchsaufbau, man muss natürlich die Taster auch so auslösen, wie es in der Praxis geschehen wird. :pensive:
Vielen Dank, es funktioniert!!!

So und nu noch:
Was passiert, wenn der Antrieb nach (hier bitte selbst Zeit eintragen) den Endschalter nicht erreicht, weil das Ding klemmt (und der Motor heiss gelaufen)
Und sag nicht, das Du das ausschliessen kannst.

Na dann...

Ja, stimmt. War in der wihle Schleife kein Problem, aber ich habe ja gelernt, dass man blockadefrei programmieren sollte. Hast Du einen Fingerzeig wie man das Problem blockadefrei angehen könnte?

Suchst Du sowas?
[EDIT: Code ein wenig aufgeräumt und getauscht]

// Ungetestet - compiliert fehlerfrei
// Pause mit Störmelder 
// https://forum.arduino.cc/t/prozess-an-der-richtigen-stelle-pausieren/904082/27?u=my_xy_projekt
float MAXtemp = 23; //in °C
float HYSTtemp = 2; //in °C
float tempKorrektur = 2.0; //in °C
float Motortemp;

bool warm = false;

const byte oben = 10;//Endschalter oben
const byte unten = 12;//Endschalter unten
const byte heben = 5;//Relais heben
const byte senken = 7;//Relais senken

//Temperatur-Sensor NTC
const byte ntc_pin = A0; //Pin für NTC
float R1 = 10000; //10K Resistor

// Fuer Zwangsabschaltung
// Zeit in ms für eine Fahrt von oben runter
// und wieder hoch - mit Sicherheit rechnen!
const unsigned long warteZeit = 5000;
unsigned long stoermillis = 0; // Merker

void setup()
{
  Serial.begin(9600);
  pinMode(heben, OUTPUT);//Relais heben
  digitalWrite(heben, HIGH); // aus
  pinMode(senken, OUTPUT);//Relais senken
  pinMode(oben, INPUT_PULLUP);//Endschalter oben
  pinMode(unten, INPUT_PULLUP);//Endschalter unten
  pinMode(A0, INPUT);//Temperatur Motor ANALOG-PIN
  digitalWrite(senken, LOW); // ein
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop()
{
  getTemp();
  bewegung();
  ausgabe(500);  // schreibt im Abstand von xxx ms auf dem SerMon.
}
void getTemp()
{
  //Temperaturmessung
  float ain = analogRead(ntc_pin);
  float R2 = R1 * (1023.0 / (float)ain - 1.0);
  float lgr = log(R2);
  float tmp = (1.0 / (1.009249522e-03 + 2.378405444e-04 * lgr + 2.019202697e-07 * lgr * lgr * lgr));
  Motortemp = tmp - 273.15 + tempKorrektur;
}

void bewegung()
{
  if (!digitalRead(oben))           // Oben angeschlagen?
  {
    digitalWrite(heben, HIGH);      // Heben aus
    digitalWrite(senken, LOW);      // senken an
    stoermillis = millis();         // mit jedem Anschlag oben wird der Timer neu gesetzt
  }
  if (!digitalRead(unten))          // unten angeschlagen
  {
    digitalWrite(senken, HIGH);     // Senken aus
    if (Motortemp >= MAXtemp)       // Motor warm (und unten angeschlagen)
    {
      warm = true;                  // Merke, das es warm ist
    }
    stoermillis = millis();
  }
  if (warm)                         // solange warm ist
  {
    if (Motortemp <= MAXtemp - HYSTtemp) // Warte darauf, das kalt wird
      warm = false;                 // und komm wieder zurück
  }
  else
  {
    // Hier kommst Du nur hin, wenn Motor kalt
    digitalWrite(heben, LOW);       // heben an
  }
}

bool stoermelder()
{
  bool stoerung = false;
  // hier wird der Timer ausgewertet
  if (millis() - stoermillis >= warteZeit)
  {
    digitalWrite(heben, HIGH);
    digitalWrite(senken, HIGH);
    digitalWrite(LED_BUILTIN, HIGH);
    stoerung = true;
  }
  return stoerung;
}

void ausgabe(const uint32_t pause)
{
  static uint32_t lastmillis = 0;
  if (millis() - lastmillis >= pause)
  {
    if (stoermelder())
    {
      Serial.println(F("ANGEHALTEN! STOERUNG"));
    }
    else
    {
      Serial.print(F("Temperatur: "));
      Serial.print(Motortemp);
      Serial.print(F(" °C \t"));
      Serial.print(F("warm: "));
      Serial.print(warm);
      Serial.print(F("\t heben: "));
      Serial.print(digitalRead(heben));
      Serial.print(F("\t senken: "));
      Serial.print(digitalRead(senken));
      Serial.print(F("\t kontakt oben: "));
      Serial.print(digitalRead(oben));
      Serial.print(F(" | kontakt unten: "));
      Serial.println(digitalRead(unten));
    }
    lastmillis = millis();
  }
}

Was der Code machen soll:
Wenn ich oben bin, wird eine Variable mit der aktuellen Systemzeit gesetzt.
Wenn ich in einer bestimmten Zeit nicht wieder oben an einem Endpunkt ankomme (hier 5000 ms) geht der in Störung, macht die LED ONBoard an, macht den Motor aus.

Warum frage ich die Temperatur nicht ab?
Weil ich die nicht brauche.
Wenn der Antrieb den Weg nicht schafft, ist was faul.

Und wenn es Dir zu unübersichtlich wird, kannst das aufräumen
oder wartest noch ein Weilchen.... :wink:
Achso Hinweis:
Ich hab das extra so gemacht, das der erstmal nicht auswertet, wenn der unten ist.
Das geht dauerhaft natürlich nur, wenn Du unten und warm mit auswertest. Also noch nichts endgültiges.

cool, in diese Richtung habe ich auch gerade versucht mich "durchzugraben" aber mit

setzt Du natürlich noch einen ober drauf, na klar!!
Ich hatte schon die & Taste bemüht. :man_facepalming:

Was hindert Dich daran?

  const unsigned int motorBrennt = 38;
  // hier wird der Timer ausgewertet
  if ((millis() - stoermillis >= warteZeit) && (motortemp < motorBrennt))

Wo das hin gehört, findest allein.
Für die Kritiker: Ja, das ist schlechter SchreibStil.

Mein Motor beginnt auch gerade zu brennen, ich habe jetzt 1,5 h lang verglichen, auskommentiert und getestet , ich finde jedoch nicht den Grund, warum "heben" sich verabschiedet hat. Ich zähle jetzt bis morgen erst einmal ein millis runter und mache dann weiter.
Ich hänge den Sketch noch mal an. Du wirst Dir sicher vor Lachen auf die Schenkel schlagen und den Fehler sofort sehen.

// Ungetestet - compiliert fehlerfrei
// Pause mit Störmelder
// https://forum.arduino.cc/t/prozess-an-der-richtigen-stelle-pausieren/904082/27?u=my_xy_projekt

float MAXtemp = 23; //in °C
float HYSTtemp = 2; //in °C
float tempKorrektur = 0.0; //in °C
float Motortemp;

bool warm = false;

const byte oben = 10;//Endtaster oben
const byte unten = 12;//Endtaster unten
const byte heben = 5;//Relais heben
const byte senken = 7;//Relais senken

//Temperatur-Sensor NTC
const byte ntc_pin = A0; //Pin für NTC
float R1 = 10000; //10K Resistor

// Fuer Zwangsabschaltung
// Zeit in ms für eine Fahrt von oben runter
// und wieder hoch - mit Sicherheit rechnen!
const unsigned long warteZeit = 10000;
const unsigned int motorBrennt = 38;
unsigned long stoermillis = 0; // Merker

void setup()
{
  Serial.begin(9600);
  pinMode(heben, OUTPUT);//Relais heben
  digitalWrite(heben, HIGH); // aus
  pinMode(senken, OUTPUT);//Relais senken
  pinMode(oben, INPUT_PULLUP);//Endtaster oben
  pinMode(unten, INPUT_PULLUP);//Endtaster unten
  pinMode(A0, INPUT);//Temperatur Motor ANALOG-PIN
  digitalWrite(senken, LOW); // ein
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop()
{
  getTemp();
  bewegung();
  ausgabe(500);  // schreibt im Abstand von xxx ms auf dem SerMon.
}
void getTemp()
{
  //Temperaturmessung
  float ain = analogRead(ntc_pin);
  float R2 = R1 * (1023.0 / (float)ain - 1.0);
  float lgr = log(R2);
  float tmp = (1.0 / (1.009249522e-03 + 2.378405444e-04 * lgr + 2.019202697e-07 * lgr * lgr * lgr));
  Motortemp = tmp - 273.15 + tempKorrektur;
}

void bewegung()
{
  if (!digitalRead(oben))           // Oben angeschlagen?
  {
    digitalWrite(heben, HIGH);      // Heben aus
    digitalWrite(senken, LOW);      // senken an
    stoermillis = millis();         // mit jedem Anschlag oben wird der Timer neu gesetzt
  }
  if (!digitalRead(unten))          // unten angeschlagen
  {
    digitalWrite(senken, HIGH);     // Senken aus
    if (Motortemp >= MAXtemp)       // Motor warm (und unten angeschlagen)
    {
      warm = true;                  // Merke, das es warm ist
    }
    stoermillis = millis();
  }
  if (warm)                         // solange warm ist
  {
    if (Motortemp <= MAXtemp - HYSTtemp) // Warte darauf, das kalt wird
      warm = false;                 // und komm wieder zurück
  }
  else
  {
    // Hier kommst Du nur hin, wenn Motor kalt
    digitalWrite(heben, LOW);       // heben an
  }
}

bool stoermelder()
{
  bool stoerung = false;
  // hier wird der Timer ausgewertet
  if ((millis() - stoermillis >= warteZeit) && (Motortemp < motorBrennt))
  {
    digitalWrite(heben, HIGH);
    digitalWrite(senken, HIGH);
    digitalWrite(LED_BUILTIN, HIGH);
    stoerung = true;
  }
  return stoerung;// Hier kann das Ganze eigentlich enden, denn ein Neustart ist in jedem Fall nötig
}

void ausgabe(const uint32_t pause)
{
  static uint32_t lastmillis = 0;
  if (millis() - lastmillis >= pause)
  {
    if (stoermelder())
    {
      Serial.println(F("ANGEHALTEN! STOERUNG"));
    }
    else
    {
      Serial.print(F("Temperatur: "));
      Serial.print(Motortemp);
      Serial.print(F(" °C \t"));
      Serial.print(F("warm: "));
      Serial.print(warm);
      Serial.print(F("\t heben: "));
      Serial.print(digitalRead(heben));
      Serial.print(F("\t senken: "));
      Serial.print(digitalRead(senken));
      Serial.print(F("\t kontakt oben: "));
      Serial.print(digitalRead(oben));
      Serial.print(F("\t kontakt unten: "));
      Serial.println(digitalRead(unten));
    }
    lastmillis = millis();
  }
}

Was meinst du mit verabschiedet? Irgendwie sagt das genauso viel aus wie "Funktioniert nicht"

Was passiert nicht wie gewollt? Was hättest du erwartet?

Jein. Letztres ist im Moment schlecht - nein soweit ist alles gut.
Las mal das && (Motor - dingens weg.
Wenn der dann geht, dann ist alles i.O.
Ich schau drauf - dauert aber etwas... Vermutlich mein Fehler...
Erster Nachtrag:

  return stoerung;// Hier kann das Ganze eigentlich enden, denn ein Neustart ist in jedem Fall nötig

Trenne Dich von Deiner Denke. :wink:

Kannst Du mal DEINEN Sketch laufen lassen
Brauchst nicht - ich kann das jetzt nachbauen.

21:33:19.478 -> Temperatur: -17.26 °C 	warm: 0	 heben: 0	 senken: 0	 kontakt oben: 1	 kontakt unten: 1
21:33:20.008 -> Temperatur: -9.17 °C 	warm: 0	 heben: 0	 senken: 0	 kontakt oben: 1	 kontakt unten: 1
21:33:20.538 -> Temperatur: -8.49 °C 	warm: 0	 heben: 0	 senken: 0	 kontakt oben: 1	 kontakt unten: 1
21:33:21.068 -> ANGEHALTEN! STOERUNG
21:33:21.565 -> ANGEHALTEN! STOERUNG

Las mir nen Moment.

Zu Lange!

Ersetze:

void bewegung()
{
  if (!digitalRead(oben))           // Oben angeschlagen?
  {
    digitalWrite(heben, HIGH);      // Heben aus
    digitalWrite(senken, LOW);      // senken an
    stoermillis = millis();         // mit jedem Anschlag oben wird der Timer neu gesetzt
  }
  if (!digitalRead(unten))          // unten angeschlagen
  {
    digitalWrite(senken, HIGH);     // Senken aus
    if (Motortemp >= MAXtemp)       // Motor warm (und unten angeschlagen)
    {
      warm = true;                  // Merke, das es warm ist
    }
    stoermillis = millis();
    if (warm)                         // solange warm ist
    {
      if (Motortemp <= MAXtemp - HYSTtemp) // Warte darauf, das kalt wird
        warm = false;                 // und komm wieder zurück
    }
    else
    {
      // Hier kommst Du nur hin, wenn Motor kalt
      digitalWrite(heben, LOW);       // heben an
    }
  }
}

Ich habe eine Ebene zwischendurch verschoben. Das wird...

Super, vielen Dank, hab's gesehen, der Lehrling(ich) versucht jetzt mal die unterschiedlichen Auswirkungen nachzuvollziehen, der will ja schließlich was lernen. Dann werde ich mal noch ein paar millis zwischen den Umschaltvorgang schieben, sollte ich eigentlich schaffen, wenn nicht, bitte ich höflichst noch einmal "anklopfen" zu dürfen.

Hallo xy, ich habe nun daran gearbeitet mich von der alten Denke zu trennen und bitte noch einmal um Deinen Rat. Ich habe hier einen Sketch mit 2 blinkenden LEDs geschrieben, der mir jedoch viel zu lang und auch zu komplizier erscheint. Meine Frage: wie macht man das besser?

const byte LED_1 = 5;
const byte LED_2 = 7;
bool Start_1 = true; //true für Start
bool Start_2 = false;
bool Start_3 = false;
bool Start_4 = false;

const int UmschaltZeit = 1000;
const int LaufZeit = 2000;
unsigned long Umschaltpause_1 = 0; // Merker
unsigned long Umschaltpause_2 = 0; // Merker
unsigned long Laufzeitmillis_1 = 0; // Merker
unsigned long Laufzeitmillis_2 = 0; // Merker

void setup()
{
  Serial.begin(9600);
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);
  digitalWrite(LED_1, LOW); // aus
  digitalWrite(LED_2, LOW); // aus
}
void loop()
{
  LEDblink();
  ausgabe(500);
}
void  LEDblink()
{
  if (Start_1 && (millis() - Umschaltpause_1 >= UmschaltZeit))
  {
    digitalWrite(LED_2, HIGH);
    Laufzeitmillis_1 = millis();         // Sartet den Timer für Laufzeit 1
    Start_1 = !Start_1;
    Start_2 = !Start_2;
  }
  if (Start_2 && ((millis() - Laufzeitmillis_1 >= LaufZeit)))
  {
    digitalWrite(LED_2, LOW);
    Umschaltpause_2 = millis();         // Sartet den Timer für Umschaltpause 2
    Start_2 = !Start_2;
    Start_3 = !Start_3;
  }
  if (Start_3 && (millis() - Umschaltpause_2 >= UmschaltZeit))
  {
    digitalWrite(LED_1, HIGH);
    Laufzeitmillis_2 = millis();         // Sartet den Timer für Laufzeit 2
    Start_3 = !Start_3;
    Start_4 = !Start_4;
  }
  if (Start_4 && ((millis() - Laufzeitmillis_2 >= LaufZeit)))
  {
    digitalWrite(LED_1, LOW);
    Umschaltpause_1 = millis();         // Sartet den Timer für Umschaltpause 1
    Start_4 = !Start_4;
    Start_1 = !Start_1;
  }
}

void ausgabe(const uint32_t pause)
{
  static uint32_t lastmillis = 0;
  if (millis() - lastmillis >= pause)
  {
    Serial.print("\t LED_1: ");
    Serial.print(digitalRead(LED_1));
    Serial.print("\t LED_2: ");
    Serial.print(digitalRead(LED_2));
    Serial.print("\t Umschaltpause_1: ");
    Serial.print(Umschaltpause_1 / 1000);
    Serial.print("\t Laufzeitmillis_1: ");
    Serial.print(Laufzeitmillis_1 / 1000);
    Serial.print("\t Umschaltpause_2: ");
    Serial.print(Umschaltpause_2 / 1000);
    Serial.print("\t Laufzeitmillis_2: ");
    Serial.print(Laufzeitmillis_2 / 1000);
    Serial.print("\t Millis: ");
    Serial.println(millis() / 1000);
    lastmillis = millis();
  }
}

in dem man vor der ersten Codezeile mal ein Diagramm zeichnet dass das Zeitverhalten aller Kompenten grafisch zeigt.
Dann sieht man auch was wovon abhängig ist, was gleich ist und somit generalisiert werden kann.

Durchnummerierte Variablen rufen - nein schreien - eigentlich nach Arrays.
Mehrere durchnummerierte Variablen deuten auf Datenstrukturen --> struct.
Die Kombination daraus: auch Strukturen kann man in Arrays geben.

aber retour zum ersten Satz:
Zeichne es mal auf und poste es.

Oh ja, das klingt gut, in Arrays packen und generalisieren, eine grafische Darstellung vor die erste Codezeile zu setzten ist auch eine super Idee, das versuche ich morgen mal, soviel noch vorweg, es handelt sich nur um 2 blinkende LEDs, mehr nicht, das Ganze dient mir nur zur Übung, um wie xy vorschlug, zu versuchen, blockadefrei programmieren zu lernen.

Ich denke noiasca hat das eher zeitlich gemeint :wink: :
Bevor man die erste Codezeile schreibt, sollte man sich den Ablauf auf einem Blatt Papier klarmachen.

1 Like

Das weiss ich nicht.
Ich würde es anders machen.
Ein Versuch.
Ungetestet. Kompiliert Fehlerfrei. Und es geht kürzer

const byte LED[] = {5, 7};
enum : byte {Start, Ende};

const int UmschaltZeit = 1000;
const int LaufZeit = 2000;
unsigned long lastmillis = 0; // Merker

byte b = 0; // Zaehler...
byte schritt;
void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  for (byte b = 0; b < sizeof(LED); b++)
  {pinMode(LED[b], OUTPUT); digitalWrite(LED[b], LOW);} // aus
  schritt = Start;
}
void loop()
{
  LEDblink();
}

void  LEDblink()
{
  switch (schritt)
  {
    case Start:
      if (millis() - lastmillis >= UmschaltZeit)
      {
        digitalWrite(LED[b], HIGH);
        lastmillis = millis();         // Merker für Laufzeit
        schritt = Ende;
        ausgabe();
      }
      break;
    case Ende:
      if (millis() - lastmillis >= LaufZeit)
      {
        digitalWrite(LED[b], LOW);
        lastmillis = millis();         // Merker für Umschaltpause
        schritt = Start;
        ausgabe();
        b++; if (b >= sizeof(LED)) b = 0;
      }
      break;
  }
}

void ausgabe()
{
  for (byte b = 0; b < sizeof(LED); b++)
  {
    Serial.print(F("LED")); Serial.print(b); Serial.print(": ");
    Serial.print(digitalRead(LED[b]));
    Serial.print("\t");
  }
  Serial.println();
}

Und um mal das aufzugreifen, was vorher schon gesagt wurde: Es gibt nur ein Array - das mit den Pins.
Weiter brauchst Du nichts.
Jede ungenutzte Zählvariable ist eine gute Zählvariable.
Jeder Merker braucht Speicher. Jeder vermiedene Merker ist ein guter Merker :wink:

Na dann...

Und noch ein edit: Dein Code für einen Mega compiliert:

Der Sketch verwendet 3752 Bytes (1%) des Programmspeicherplatzes. Das Maximum sind 253952 Bytes.
Globale Variablen verwenden 325 Bytes (3%) des dynamischen Speichers, 7867 Bytes für lokale Variablen verbleiben. Das Maximum sind 8192 Bytes.

Meiner:

Der Sketch verwendet 3324 Bytes (1%) des Programmspeicherplatzes. Das Maximum sind 253952 Bytes.
Globale Variablen verwenden 200 Bytes (2%) des dynamischen Speichers, 7992 Bytes für lokale Variablen verbleiben. Das Maximum sind 8192 Bytes.

Und da geht noch was....