interrupt problem

Hello I’m having some trouble with an interrupt. Here’s what i want to do. There is a push button on one of the interrupt pins, the other side of which goes to ground. When the button is pressed, I want it to go into a menu routine, whereby the menu number is increased each time the button is pressed, and if the button is unpressed for 5 seconds, the menu option remains at that number. So I have a while loop, which will time out after 5 seconds. I’m assuming that if the button is pressed during that while loop, the interrupt will be called again, it goes back to the top of loop() and since menuFlag is set, the if menu condition starts again, and the counter increments again, until finally 5 seconds passes and the counter stays where it is.

However, it doesn’t quite do this. Although the interrupt is called, it doesnt’ seem to break out of the while loop. Obviously I’m doing it wrong but how best to achieve what I want?

volatile int functionOption = 0;
volatile unsigned long last_millis;
volatile bool menuFlag = false;
void setup()
{
  Serial.begin(57600);
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(0, my_interrupt_handler, FALLING);
}

void loop()
{
  if (menuFlag)
  {
    functionOption++;
    if (functionOption > 7) functionOption = 0;
    Serial.print("next option is ");
    Serial.println(functionOption);
    last_millis = millis();
    while ((millis() - last_millis) < 5000) {
    }

    Serial.print("Function is set to ");
    Serial.println(functionOption);
    menuFlag=false;
    }
}

void my_interrupt_handler()
{
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 200ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 200)
  {Serial.println("interrupt");
    menuFlag = true;

  }
  last_interrupt_time = interrupt_time;
 return;
}

it doesnt' seem to break out of the while loop.

Why do you assume that it will break out of the while loop ?
The ISR will be called, the code in the ISR will be executed then program execution will return to where it was before the ISR was called.

By the way, you cannot print inside an ISR because interrupts are disabled and Serial uses interrupts

Think very carefully about whether you need to use an interrupt in the first place

Got it. So this seems to work, and ignoring for now the reasonable question of whether I actually need an interrupt, is there any reason for not doing it like this?

volatile int functionOption = 0;
volatile unsigned long last_millis;
volatile bool menuFlag = false;
volatile bool secondPress = false;
void setup()
{
  Serial.begin(57600);
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(0, my_interrupt_handler, FALLING);
}

void loop()
{
  if (menuFlag)
  {
    functionOption++;
    if (functionOption > 7) functionOption = 0;
    Serial.print("next option is ");
    Serial.println(functionOption);
    last_millis = millis();
    while (((millis() - last_millis) < 5000) && (!secondPress)) {
    }
    Serial.print("Function is set to ");
    Serial.println(functionOption);
    menuFlag = false;
    secondPress = false;
  }
}

void my_interrupt_handler()
{
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 200ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 200)
  { // Serial.println("interrupt");
    if (menuFlag) secondPress = true;


  }
  last_interrupt_time = interrupt_time;
  menuFlag = true;

}

1. If you don't press the button for a period of 5-sec, is the session is going to be over/end and the counter will show 0?

2. If you press the button after 2-sec, the counter will be incremented by 1; after that you don't press the button, is the session going to be over/end after 5-sec period being counted from the instant of return to the interrupted program?

IIRC, bool may not be an atomic data type on all architectures. Non-atomic types require that interrupts be disabled in the main code when accessed, even if they are declared volatile. 200ms is 10x too long a debounce for most switches.

GolamMostafa:
1. If you don’t press the button for a period of 5-sec, is the session is going to be over/end and the counter will show 0?

No, the idea is that if you don’t press the button for 5 seconds, the counter remains where it has got to, and this is then written to EEPROM so that when you switch it on again, it remembers the option that was chosen. The presumption is that if the user presses the button it’s because they want to change the setting, although if they want to keep it as it is, then can cycle through by repeated button presses until they get back to the starting point

GolamMostafa:
2. If you press the button after 2-sec, the counter will be incremented by 1; after that you don’t press the button, is the session going to be over/end after 5-sec period being counted from the instant of return to the interrupted program?

Yes. But this makes me think that an interrupt is the wrong way to go because returning to the interrupted program can have unpredictable results. I think it would be better simply to test the button state on each cycle through loop. Then, once the setting is changed, it would be better to restart the program by using a watchdog timeout maybe.

Your point about volatile bool variables is also taken.