Use this forum to chat about hardware specific topics for the ESP8266 (peripherals, memory, clocks, JTAG, programming)

User avatar
By Cabooze
#64473 Hello,

I have several problems with my C++ Code.
I am actualy trying to get a LED blink with a simple interrupt. But nothing really works.

I have the NodeMCU esp12 e.
I have a circuit using a push button and a LED. When pushing the button, I want to cause an Interrupt and the LED to blink for a certain period of time.
It usually works. But randomly nothing happens and I get a watchdog reset.

Here is the code:

Code: Select allconst int LED_PIN = 13;
const int BUTTON_PIN =  0; 

void setup() {

    Serial.begin(115200);
    Serial.println("");
   
    //set pios
    pinMode(LED_PIN, OUTPUT);
    pinMode(BUTTON_PIN, INPUT);

    //set light off at the beginning
    digitalWrite(LED_PIN, LOW); //blue

    attachInterrupt(BUTTON_PIN, Interrupt_Sequence, FALLING);

    Serial.println("Settings Done!");
}

void loop() {
  //do nothing except interrupt is detected
}

void Interrupt_Sequence(){
  Serial.println("Interrupt Detected: Red");

    detachInterrupt(digitalPinToInterrupt(BUTTON_PIN_RED));
   
    //Start Countdown
    for(int i = 0; i <= 5; i++){

    delay(950);

      digitalWrite(LED_PIN, HIGH);      //blink
      delay(50);                           
      digitalWrite(LED_PIN, LOW);      //blink
      yield();                               //gives control back to scheduler, so the watchdog does not reset
     
    }
    attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), Interrupt_Sequence, HIGH);
}



I don't understand why this problem occurs. My code isn't that complicated.

Does anyone know the problem?
Thanks in advance!
User avatar
By daniel_ezsbc
#64569 Try not to do anything in the interrupt handler that is not absolutely essential to handle the interrupt. Also, don't nest interrupts as it leads to obscure bugs.

You may inadvertently be nesting interrupts by having the println in the interrupt handler. Also, you should never, ever have a long delay inside an interrupt handler. Even more important is to not remove the link to the interrupt handler from inside the interrupt handler.

Here's a better plan. Put your entire interrupt handler in the loop section of your code. Wrap it inside an if statement that checks if a flag called InterruptOccurred was set. In the interrupt handler, set InterruptOcurred to a non-zero value. Since you want to detach the handler, do it as the first line after the if( InterruptOccurred) statement. Clear InterruptOccurred. Now do the serial IO, delays, led flashing etc. and be sure that the interrupts of the print function won't occur while you are in your interrupt handler.

I don't think it is a good idea to call detachInterrupt(digitalPinToInterrupt(BUTTON_PIN_RED)); from inside an interrupt handler. It feels like a recipe for strange behavior.

Also, interrupt handlers should be parameter-less. I don't know enough about the way the PDK deals with interrupts to know if it can deal with a parameter as part of the interrupt handler. Remember, parameters are passed on the stack. The interrupt handler pushes a bunch of stuff onto the stack before it starts executing and the chip takes care of some or all of those items. When the interrupt handler returns, something has to take care of the parameter pushed onto the stack and I'm not sure who does that. If you split the handler into something that sets a flag and some other code in normal code space then nothing strange can happen with the call to a function that requires a parameter.

Remeber to declare the flag 'volatile'.

Incrementing a counter in an interrupt handler is an excellent way to deal with events that may occur again before the first event was dealt with. Lets assume you leave the handler in place after an interrupt occured and while you are handling the led flashing the user pushes the button again. If InterruptOccurred is incremented in the handler and decremented in the code that's part of the loop(), then the led flashing won't stop until InterruptOccurred reaches zero so the user can extend the time the led flashes by pressing the button again. If you don't want that to happen then the loop() code can just zero InterruptOccurred as the last operation.

Hope this helps