Attachinterrupt & Software timer

@Tino52, first you are long enough in this community to know how to format code blocks - I know I have reminded you before to use the "Preformatted text" image feature - please do.

For the question at hand: Do you really need the exact timing down to a few microseconds?
If not, you can well use the interrupt to set a flag but then act upon it in your loop().
Starting a software timer from an ISR should be the exception not the first option.

First kick out that dreaded delay() at the end of your loop() and wrap the delayed actions in a millis() timing block.
When that is taken care of, you can implement the flag idea rather comfortably

something like this

bool  startNeeded[2] = { false, false };                // flags for ISR to tell loop() to initiate the timer [0]..off, [1]..on
Timer timer[2]       = { Timer( 500, CentrOff, true)    // array of timers to wrap similar actions in one loop
                       , Timer(5000, CentrOn , true) };

void loop() {
  static uint32_t ms1Sec = 0;

  for (int i = 0; i < 2; i++) {                         // traverse timer array
    if (startNeeded[i] && !timer[i].isActive()) {       // when a start is needed and not currently running
      startNeeded[i] = false;                           // reset the start flag
      timer[i].start();                                 // start the timer
    }
  }

  if (millis() - ms1Sec >= 1000) {                      // when last execution is at least one second in the past
    ms1Sec        = millis();
    StatoZ1       = digitalRead(Zona1);
    StatoInscent  = digitalRead(Inscent);
    StatoDInscent = digitalRead(DInscent);
    Uscita        = digitalRead(D8);
    Serial.printlnf("StatoC   : %5d\r\n"
                    "Uscita   : %5d\r\n"
                    "Stato on : %5d\r\n"
                    "Stato off: %5d\r\n"
                   , StatoC
                   , Uscita
                   , StatoInscent
                   , StatoDInscent
                   );
  }
}

void CentrIntOn() {
  startNeede[1] = true;
}
    
void CentrIntOff() {
  startNeeded[0] = true;
}

BTW, you'd usually first set the pinMode() for the pins before you attach an interrupt to said pin. Otherwise you may be getting erroneous triggers of the floating pins.
I'd also not use a CHANGE trigger for this. Usually I'd opt for the button release to trigger any action with time component.
(for button handling you may have a look at Rick's brilliant library - debouncing is also something your code should do)

Also this is wrong

and

Here you are not checking the state of your flags but setting them.

You may also need to give the re-trigger logic some more thought.
Your code (and hence my derivative of it too) does not properly address at least two possible states:

  • what if the button was pressed again while the timer was running?
  • what if the button stays pressed for the duration of the timer running (or while the timer is about to expire)?

You first need to formulate the intent for all cases and based on that develop your code.

1 Like