WEMOS D1 - Absturz in der Interruptroutine

Hallo,
es klemmt mal wieder…
Ein WEMOS soll mittels Interrupt Impulse eines Reed-Kontaktes (zwischen D2 und GND) zählen. Die geschlossen-Zeit des Kontaktes soll mindestens 500 mSec. sein. Es kann passieren dass der Magnet am Kontakt stehen bleibt und dieser dann lange geschlossen ist. In diesem Fall stürzt er nach ca. 5 Sekunden Geschlossenzeit ab…

#include <ArduinoOTA.h>

#define Reed         D2                                            // digital Pin 2 Reed
#define BLUE_LED     D4

int     nX = 0;

// --------------------------------------------------------------------
void setup()
{
  pinMode(Reed, INPUT_PULLUP);                                      // REED-Port ist Eingang

  pinMode(BLUE_LED, OUTPUT);                                        // Interne LED
  digitalWrite(BLUE_LED, LOW);                                      // an
  attachInterrupt(digitalPinToInterrupt(Reed), interruptISR, FALLING);

  Serial.begin(74880);
  Serial.println("los");

  ArduinoOTA.setHostname("Interrupt");
  ArduinoOTA.begin();                                              // https://arduino-esp8266.readthedocs.io/en/latest/ota_updates/readme.html

  digitalWrite(BLUE_LED, HIGH);                                    // aus

}
// --------------------------------------------------------------------
void loop()
{
  ArduinoOTA.handle();

  digitalWrite(BLUE_LED, LOW);                                      // ein
  delay(10);
  digitalWrite(BLUE_LED, HIGH);
  delay(1000);
}
// --------------------------------------------------------------------
void interruptISR()
{
  unsigned long ein_time = millis();
  while (digitalRead(Reed) == 0)
  {
    digitalWrite(BLUE_LED, LOW);                                      // an
  }
  digitalWrite(BLUE_LED, HIGH);

  if (millis() - ein_time >= 500)
  {
    nX++;
    Serial.println(nX);

  }
}


Nach dem Absturz gibt es diverse überwiegend nicht druckbare Zeichen am Monitor (unvollständiges Beispiel ⸮܋K ⸮L ⸮’⸮⸮X% ).
Wo könnte da der Fehler liegen.

Sowas hat in einer ISR nichts zu suchen.

  while (digitalRead(Reed) == 0)
  {
    digitalWrite(BLUE_LED, LOW);                                      // an
  }

Dein Interrupt reagiert auf die fallende Flanke. Dem kann es egal sein, wie lange das Signal LOW ist.

Merke Dir in der ISR die Millis, wenn er LOW gegangen ist (volatile) und werte das im loop aus, wenn Dir das zu lange ist. Wobei den Magneten kannst Du ja trotzdem nicht wegschieben ;)

Gruß Tommy

Nach dem Absturz gibt es diverse überwiegend nicht druckbare Zeichen am Monitor (unvollständiges Beispiel ⸮܋K ⸮L ⸮’⸮⸮X% ).

Das ist die Meldung über die Absturzursache und den Reboot.
Die kommt mit einer anderen Baudrate, deswegen siehst du nur Krüssel…

Ausgegeben wird u.a. ein Stack Dump, den man mit Hilfe des EspExceptionDecoder analysieren kann

void interruptISR()
{
  unsigned long ein_time = millis();
  while (digitalRead(Reed) == 0) // << ------- brandgefährlich 
  {
    digitalWrite(BLUE_LED, LOW);                                      // an
  }
  digitalWrite(BLUE_LED, HIGH);

  if (millis() - ein_time >= 500)  
  {
    nX++;
    Serial.println(nX);  // << ------- brandgefährlich (?)

  }
}

Es ist “brandgefährlich” langlaufende Dinge in ISR zu tun. Die haben in ISR nichts zu suchen, es sei denn, man weiß GENAU was man da tut.

uk1408:  digitalWrite(BLUE_LED, LOW);                                      // an

Ich ergänze, dass der Kommentar vermutlich falsch ist. Etwas LOW zu schalten und „an“ zu nennen, ist IMO reichlich daneben. „LED schalten“ ist als Kommentar mit Sicherheit besser.

Gruß

Gregor

Etwas LOW zu schalten und „an" zu nennen,

Und, wenn es aber doch die reine Wahrheit ist?

Was gibt es gegen die Wahrheit einzuwenden?

Und, wenn es aber doch die reine Wahrheit ist? Was gibt es gegen die Wahrheit einzuwenden?

Danke... es ist so, mit LOW geht die LED AN!!! Ich möchte ja festhalten wie die LED schaltet. Aber das ist ja nicht mein Problem....

Die Baudrate passt, Meldungen des ESP kommen auch mit den 74880 Bd.

Tommy, hast du da nähere Hinweise (Sowas hat in einer ISR nichts zu suchen).

Grundsatz: Alles was die Gefahr birgt, lange zu brauchen hat in einer ISR nichts zu suchen. ISR müssen so kurz/schnell, wie möglich sein. Der Rest ergibt sich von allein.

Beim ESP8266 kann es auch sein, dass die ISR in einem speziellen Speicherbereich liegen muss:

void ICACHE_RAM_ATTR regenISR() {

}

Gruß Tommy

Erst mal Danke für eure Beiträge. Bei mir ist es schon ein Weilchen her dass ich mit Assembler eine Z80 und Interrupts programmiert habe. Und da hatte man schon alles im Griff was sich so tat. Und da konnte man auch grundsätzlich alles was man wollte in der Interrupt-Routine abhandeln. Und in der Loop zu prüfen was sich in der ISR ereignet hat wird eher nichts. Mein Programm (das am Anfang ist nur ein Test) hat noch ein paar andere Funktionen die etwas Zeit kosten (WLAN bedienen, Messwerte erfassen). Und wenn jetzt die ISR aufgerufen wird, die millis() gespeichert werden und dann womöglich erst noch das Restprogramm ablaufen muss bis in der Loop() nach den ISR-Millis gefragt wird passt da nicht mehr. Man sollte doch in der ISR auch ein paar sinnvolle Dinge abarbeiten können.....

Kann man, aber nicht solche Sachen, die den Ablauf auf unbestimmte Zeit blockieren können.

Das kannst Du beim ESP8266 auch in der Form im loop nicht, da beißt Dich auch der Wachhund.

Gruß Tommy

Man sollte doch in der ISR auch ein paar sinnvolle Dinge abarbeiten können.....

"Man" kann!

Aber du scheinst dir da einige Hürden in den Restcode gebaut zu haben, so dass du jetzt mit dem Kopf durch die Wand willst/musst.

Tipp: Manchmal muss man 2 bis 3 Schritt zurückgehen, denn dann sieht man vielleicht ein Loch, welches ein Maurer dort mit Absicht gelassen hat. Perspektive, Blickwinkel, Sicht, Projektion

na dann suche ich mal :o :o

Hallo,

uk1408: Erst mal Danke für eure Beiträge. Bei mir ist es schon ein Weilchen her dass ich mit Assembler eine Z80 und Interrupts programmiert habe. Und da hatte man schon alles im Griff was sich so tat. Und da konnte man auch grundsätzlich alles was man wollte in der Interrupt-Routine abhandeln.

Selbst beim Z80 mußte man aufpassen, wenn es mehr als eine Interruptquelle gab... Im Gegensatz zum Z80 bist Du auf dem ESP nicht alleine. Der will seine Core-Geschichten wie WLAN usw. gern abarbeiten, sonst schlägt der harware-Watchdog zu und den kann man nicht abschalten. Auch millis() läuft da z.B. nicht, serielle Ausgaben gehen nicht usw., also alles, was seinerseits Interrupts braucht.

Gruß aus Berlin Michael