Prozess an der richtigen Stelle pausieren

Das ist in den aller meisten Fällen die falsche Vorgehensweise. Du hast in loop() eine Schleife die ständig laufen sollte. Da kann man auch einfach nichts tun, statt irgendwo wortwörtlich zu warten. Und je nach Zustand des Systems macht man dann was man braucht

Hmm, also alles noch mal verwerfen und neu aufbauen?

Na das ist das geringste Übel, nur machst Du das nicht.

Ich würde im setup() einmal eine Fahrt nach unten machen und dann von dort aus starten. Hat den Vorteil, das Du bei einem möglichen reset sofort merkst, ob der Motor warm gelaufen ist und nicht erst kurz überm Endschalter startest und nach oben und dann wieder nach unten fährst.

Und dann nicht alles in loop() schreiben sondern nach Funktion aufteilen.

In etwa so:

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

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); //  treibt nach unten
}

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
  }
  else 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
    }
    //  // solange warm ist 
    if (warm)
    {
      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
    }
  }
}

void ausgabe(const uint32_t pause)
{
  static uint32_t lastmillis = 0;
  if (millis() - lastmillis >= pause)
  {
    Serial.print("Temperatur: ");
    Serial.print(Motortemp);
    Serial.print(" °C \t");
    Serial.print("warm: ");
    Serial.print(warm);
    Serial.print("\t heben: ");
    Serial.println(digitalRead(heben));
    lastmillis = millis();
  }
}

kein einziges while drin und kein delay() und trotzdem gehts :wink:

1 Like

:clap: :clap: :clap: Sehr cool gemacht, schon fast amüsant, wie Du mit der Programmierlogik "spielst". Es funktioniert auch mit der HW. Jedoch ist die Reaktion auf die Temperaturänderung extrem langsam geworden, woran könnte das liegen?

Naja. Die Motertemperatur wird ja nur verglichen und dementsprechend gesetzt wenn:

    if (Motortemp >= MAXtemp)       // Motor warm (und unten angeschlagen)
    {
      warm = true;                  // Merke, das es warm ist
    }

Erreicht wird. Und das passiert nur wenn:

if (!digitalRead(unten))

Vorher wahr ist.

Das sage ich Dir, wenn Du hier gelsen hast: Wie man dieses Forum benutzt - bitte lesen

Im Seriellen Monitor einfach strg-a + strg-c machen und dann in codetags (steht auch da drin wie es geht) an Stelle des Bildes einfügen.

:wink:

Das ist nicht sein alleiniges Problem.
Bei 23° ist MaxTemp erreicht.
Der hebenPin ist vorher schon HIGH.
Ihm fehlt die Information was wann mit dem senkenPin passiert.
Das ginge so:

    Serial.print(warm);
    Serial.print("\t heben: ");
    Serial.println(digitalRead(heben));
    Serial.print("\t senken: ");
    Serial.println(digitalRead(senken));

Und mir fehlt die Info, ob direkt auf die maxTemp beim hochfahren angehalten und sofort nach unten gefahren werden soll, oder ob erst oben angeschlagen und der Zyklus beendet werden muss.

Ja, Was wann genau passieren soll, muss natürlich geklärt werden.

Ich wollte nur darauf hinweisen, das die Variable 'warm' ihren zustand nicht ändert sobald die MaxTemperatur überschritten wird, sondern erst, wenn unten angechlagen wird und die MaxTemperatur überschritten wird.

Die Variable 'warm' ist so wie es bisher ist nur ein Merker ob die Hochfahrt wieder gestartet werden kann. Nicht ein Merker dafür das die Maximale Temperatur überschritten ist.

:frowning: Ja, ich weiss das. Hab das ja so geschrieben... Nur verraten wollte ich es später. Siehe oben.
Na gut. War vielleicht nicht so eindeutig rauszulesen... :wink:

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?