Calling a function inside interrupt

Hi, I have found another post about this but it stated the reply conditionally so I wanted to ask with my correct code.

So I have an external interrupt and inside the interrupt function I want to call 2 another functions.

I'll try it myself but even if it works correctly for now but it fails for some untested reason it might create some mess. Because it is for irrigation system, if this fails somehow, pump wont work and plants die. That is not my main concern. The main concern is if it fails and "alarmOut" is HIGH for a long time, pump will work without water until I realise it which creates some safety concerns. So your input is highly appreciated.

Just please let me know if the functions I'll call has any risky code to call during an interrupt.

Here is some part of the code:

void setup()
attachInterrupt(digitalPinToInterrupt(blynkOut), irrigationManualActive, CHANGE);

void irrigationManualActive()
{
  if(digitalRead(blynkOut) == LOW){
   alarm1();  
   }
 if(digitalRead(blynkOut) == HIGH){
   alarmOver();
   }
 }

void alarm1()
{
 flowPulses = 0;
 digitalWrite(alarmOut, HIGH);                         //Activate alarm output
 serialPrintDateAndTime();
 Serial.println(" - Irrigation started");
 screenTimeOutReset();
 Alarm.free(alarmID[10]);
 alarmPeriodValue = M[10]*60 + S[10];
 alarmID[10] = Alarm.timerOnce(alarmPeriodValue, functions[10]);    //Create once only alarmPeriod timer for screen backlight timeout
}


void alarmOver()                      //Disable Alarm Output
{
 digitalWrite(alarmOut, LOW);        //Deactivate alarm output
 Alarm.free(alarmID[10]);             //Deactivate alarm period timer for reuse
 screenTimeOutReset();
 
 serialPrintDateAndTime();
 Serial.print(" - Irrigation Volume: ");
 Serial.print(transferVolume);
 Serial.println("ml");
}


void serialPrintDateAndTime()
{
 if(day()< 10) {Serial.print('0');}
 Serial.print(day());        //This code will send data, time and transfer volume to Serial port, so ESP can listen and write to Blynk
 Serial.print("/");
 if(month()< 10) {Serial.print('0');}
 Serial.print(month());
 Serial.print("/");
 if(year()< 10) {Serial.print('0');}
 Serial.print(year());
 Serial.print(" ");
 if(hour()< 10) {Serial.print('0');}
 Serial.print(hour());
 Serial.print(":"); 
 if(minute()< 10) {Serial.print('0');}
 Serial.print(minute());
 Serial.print(":");
 if(second()< 10) {Serial.print('0');}
 Serial.print(second());
}


void screenTimeOutReset()   //Turn on lcd backlight, free current screenTimeOut timer and create a new one
{
 lcd.backlight();
 Alarm.free(alarmID[9]);
 alarmID[9] = Alarm.timerOnce(S[9], functions[9]);
}

To answer the Title of your post directly, there is no problem with calling other functions from inside an ISR. After all, your ISR is really a function called from the true interrupt vector ISR. Just don’t do anything inside those other functions that you shouldn’t be doing from the interrupt context.

That being said, the general advice is to keep your ISRs short and simple. The best thing to do is to set a (volatile) flag indicating that the interrupt event occurred and then exit the ISR. Let your main loop() function pick up that flag (probably reset it) and then handle the event accordingly.

The stuff you’re trying to do in your ISR-called functions is really bad.

Interrupts are disabled when in an ISR or a function called from it
Serial print uses interrupts
Your are printing in a function called by an ISR

Can you see a problem ?

Are all of the variables changed by the ISR and functions called from it declared volatile as they should be ?

1 - don't call serial.out inside an interrupt.

2 - you don't need interrupts for this.

boolean alarmOn = false;

void loop() {
  if(!alarmOn && digitalRead(blynkOut) == LOW) {
    alarm1(); 
    alarmOn = true;
  }

  if(alarmOn && digitalRead(blynkOut) == HIGH){
    alarmOver();
    alarmOn = false;
  }


  // do anything else you'd normally do in the loop

  
}

gunaygurer:
Hi, I have found another post about this but it stated the reply conditionally so I wanted to ask with my correct code.

So I have an external interrupt and inside the interrupt function I want to call 2 another functions.

I'll try it myself but even if it works correctly for now but it fails for some untested reason it might create some mess. Because it is for irrigation system, if this fails somehow, pump wont work and plants die. That is not my main concern. The main concern is if it fails and "alarmOut" is HIGH for a long time, pump will work without water until I realise it which creates some safety concerns. So your input is highly appreciated.

One thing i would do in that situation, besides your coding. Is to put a water pressure sensor inline with your pump.... similar to what they use on a hot tub, which makes sure there is water pressure on the pump outlet before the heating element comes on to keep it from burning up. you could code it so that when your pump comes on, if it doesn't detect water pressure within a couple seconds, it turns off the pump and then sends you a flag or warning so you know somethings not right. But you wouldn't have to worry about it burning up your pump from running dry.

Functions you shouldn't call from within an interrupt:

delay()
Serial.xxxx()

Things you should never do from within an interrupt:

wait for something to happen that's not guaranteed to happen very very soon (microseconds)

You need to be aware of the maximum time an interrupt handler can take, since that will limit
the responsiveness of everything else (including millis(), micros()). If you can keep an
interrupt handler down to a few tens of microseconds that will be great, a few hundred is
less great, and if more than 500µs expect issues with millis()/micros() and delay().

If using the Servo library you really need to keep any interrupt routines to the bare minimum
to reduce servo jitter.