Resuming loop after ISR function - RESOLVED

Hi
I'm a complete beginner with Arduino programming, so apologies in advance if anything below isn't clear. I'm trying to build a device for an automatic feeder that activates a solenoid via a relay every day at a specific time. It's battery powered, so I'm using a DS3231 RTC to wake it from a powered down state and trigger the relay, before going back to powered down.

I've put together the code below, and have managed to get the alarm to close the relay switch at the set time and activate the solenoid. However, instead of then opening the switch after a second, the relay stays closed and the solenoid activated.

My understanding is that it should return to line 90 after executing activateRelay.

Any help appreciated.

//SPECIFIC TIME TRIGGER SOLENOID
//low power - alarm wakes up - activate relay (on then off after 1000ms) loop to start
#include <DS3231.h>
#include <Wire.h>
#include <LowPower.h>

#define wakeUpPin 2
#define relayPin 4


DS3231 Clock;

byte alarmDay;
byte alarmHour;
byte alarmMinute;
byte alarmSecond;
byte alarmBits;
bool alarmDayIsDay; 
bool alarmH12;
bool alarmPM;


void setup() {
  Serial.begin(57600);
  Serial.println("Hello");
  //rtc.begin();
  //not needed
  pinMode(relayPin, OUTPUT);
  pinMode(wakeUpPin, INPUT);
  
  Wire.begin();

alarmDay = 0;
alarmHour = 12;
alarmMinute = 51;
alarmSecond = 0;
alarmBits = 0b00001000; 
alarmDayIsDay = false;
alarmH12 = false;
alarmPM = false;  

Serial.println("Setting alarm for");
Serial.println(alarmHour);
Serial.println(alarmMinute);
Clock.turnOffAlarm(1);
Clock.setA1Time(
       alarmDay, alarmHour, alarmMinute, alarmSecond,
       alarmBits, alarmDayIsDay, alarmH12, alarmPM);
    // enable Alarm 1 interrupts
Clock.turnOnAlarm(1);
    // clear Alarm 1 flag
Clock.checkIfAlarm(1);
Serial.println("Alarm set");

Clock.turnOffAlarm(2);

pinMode(wakeUpPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), activateRelay, LOW); 
  //byte ALRM2_SET =  ALRM2_MATCH_HR_MIN;

 // int ALARM_BITS = ALRM2_SET;
  //ALARM_BITS <<= 4;
  //ALARM_BITS |= ALRM2_SET;

  // Prevent Alarm 2 altogether by assigning a 
    // nonsensical alarm minute value that cannot match the clock time,
    // and an alarmBits value to activate "when minutes match".
    //alarmMinute = 0xFF; // a value that will never match the time
    //alarmBits = 0b01100000; // Alarm 2 when minutes match, i.e., never
    
    // Upload the parameters to prevent Alarm 2 entirely
    //Serial.println("Clearing alarm 2");
    //Clock.setA2Time(
       // alarmDay, alarmHour, alarmMinute,
       // alarmBits, alarmDayIsDay, alarmH12, alarmPM);
    // disable Alarm 2 interrupt
    //Clock.turnOffAlarm(2);
    // clear Alarm 2 flag
   // Clock.checkIfAlarm(2);
   // Serial.println("Alarm 2 cleared");
    // NOTE: both of the alarm flags must be clear
    // to enable output of a FALLING interrupt
  
 
}

void loop() {
   
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  Serial.println("Waking up");
  delay(1000);
  digitalWrite(relayPin, LOW);
  detachInterrupt(wakeUpPin);
}

 void activateRelay(){ 
  
  digitalWrite(relayPin, HIGH);
   
  
}
  
    

I don't see an obvious problem with the code, and suspect that the relay is the problem. Please post a link to the relay product page or data sheet.

To test program function, replace the relay with an LED in series with a resistor (e.g. 1K).

That is wrong understanding. The interrupt function will return to what ever code was interrupted when the signal occurred.

1 Like

@donaldosaurus
are the code not intending to waking up more than once?
You do not setup waking interrupt again after first cycle...

About the issue - did you try to add a delay before next powerdown?

void loop() {
   
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  Serial.println("Waking up");
  delay(1000);
  digitalWrite(relayPin, LOW);
  delay(300);   //     <<< 
// detachInterrupt(wakeUpPin);  // do not detach the interrupt, otherwise your arduino will sleeps forever
}

I don't understand why you detach the interrupt here.

IDK if it is line 90, but it should do the interrupt and resume

  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  Serial.println("Waking up");
  delay(1000);

to say "Walking up".

Do you see the printing you expect?

An example loop from the documentation shows how and when to attach and detach the interrupt:

void loop() 
{
    // Allow wake up pin to trigger interrupt on low.
    attachInterrupt(0, wakeUp, LOW);
    
    // Enter power down state with ADC and BOD module disabled.
    // Wake up when wake up pin is low.
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 
    
    // Disable external pin interrupt on wake up pin.
    detachInterrupt(0); 
    
    // Do something here
    // Example: Read sensor, data logging, data transmission.
}

TBH I've never understood attaching and detaching alla time, but everyone does it, so.

See

HTH

a7

The LED stays on as well, so it looks like it's a problem in the code.

Yes, I spotted that shortly after posting - I've now moved

pinMode(wakeUpPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(2), activateRelay, LOW);

to the start of the loop.

Adding a delay after setting the relay low doesn't seem to help.

Please show your actual code as a new post

People do silly things, and others copy the example.

I have a separate problem with the Serial printer - it shows fragments of the text, but also random ASCII symbols (questions marks and boxes mostly). The monitor is set to 57600 baud, so I'm not sure why it does that.

I've moved the attach interrupt into the loop, so it's now:

void loop() {

  pinMode(wakeUpPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), activateRelay, LOW);  
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  Serial.println("Waking up");
  delay(1000);
  digitalWrite(relayPin, LOW);
  delay(300);
  detachInterrupt(wakeUpPin);
}

but unfortunately still have the same issue.

Serial is interrupt driven, and if you put the Arduino to sleep before allowing the output buffer to empty, problems can arise upon wakeup.

Use Serial.flush() to make sure all printing is finished before commanding sleep mode, and do not attempt to print immediately after waking up.

I would slightly rearrange your code, moving relay switching to the loop and detaching IRQ to irq handler:

void loop() {

  pinMode(wakeUpPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), activateRelay, LOW);  
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  delay(500);
  digitalWrite(relayPin, HIGH);
  Serial.println("Waking up");
  delay(1000);
  digitalWrite(relayPin, LOW);
  delay(300);
  
}

void activateRelay(){ 
  
  detachInterrupt(wakeUpPin);
}

Thanks, adding that has resolved the issue with the monitor - I can now see that it is just repeating "Waking up" over and over, but doesn't set the relay pin to low.

Post the revised code.

Forgive the noob question, but in a separate post or in this one? Here is the current code in any case. Serial monitor alternately prints "Waking up" "Deactiviting"

//SPECIFIC TIME TRIGGER SOLENOID
//low power - alarm wakes up - activate relay (on then off after 1000ms) loop to start
#include <DS3231.h>
#include <Wire.h>
#include <LowPower.h>

#define wakeUpPin 2
#define relayPin 4


DS3231 Clock;

byte alarmDay;
byte alarmHour;
byte alarmMinute;
byte alarmSecond;
byte alarmBits;
bool alarmDayIsDay; 
bool alarmH12;
bool alarmPM;


void setup() {
  Serial.begin(57600);
  Serial.println("Hello");
  //rtc.begin();
  //not needed
  pinMode(relayPin, OUTPUT);
  pinMode(wakeUpPin, INPUT);
  
  Wire.begin();

alarmDay = 0;
alarmHour = 14;
alarmMinute = 37;
alarmSecond = 00;
alarmBits = 0b00001000; 
alarmDayIsDay = false;
alarmH12 = false;
alarmPM = false;  

Serial.println("Setting alarm for");
Serial.println(alarmHour);
Serial.println(alarmMinute);
Clock.turnOffAlarm(1);
Clock.setA1Time(
       alarmDay, alarmHour, alarmMinute, alarmSecond,
       alarmBits, alarmDayIsDay, alarmH12, alarmPM);
    // enable Alarm 1 interrupts
Clock.turnOnAlarm(1);
    // clear Alarm 1 flag
Clock.checkIfAlarm(1);
Serial.println("Alarm set");

Clock.turnOffAlarm(2);


  
  //byte ALRM2_SET =  ALRM2_MATCH_HR_MIN;

 // int ALARM_BITS = ALRM2_SET;
  //ALARM_BITS <<= 4;
  //ALARM_BITS |= ALRM2_SET;

  // Prevent Alarm 2 altogether by assigning a 
    // nonsensical alarm minute value that cannot match the clock time,
    // and an alarmBits value to activate "when minutes match".
    //alarmMinute = 0xFF; // a value that will never match the time
    //alarmBits = 0b01100000; // Alarm 2 when minutes match, i.e., never
    
    // Upload the parameters to prevent Alarm 2 entirely
    //Serial.println("Clearing alarm 2");
    //Clock.setA2Time(
       // alarmDay, alarmHour, alarmMinute,
       // alarmBits, alarmDayIsDay, alarmH12, alarmPM);
    // disable Alarm 2 interrupt
    //Clock.turnOffAlarm(2);
    // clear Alarm 2 flag
   // Clock.checkIfAlarm(2);
   // Serial.println("Alarm 2 cleared");
    // NOTE: both of the alarm flags must be clear
    // to enable output of a FALLING interrupt
  
 
}

void loop() {

  pinMode(wakeUpPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), activateRelay, LOW);  
  Serial.flush();
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  delay(300);
  Serial.println("Waking up");
  delay(1000);
  Serial.println("Deactivating");
  digitalWrite(relayPin, LOW);
  delay(300);
  detachInterrupt(wakeUpPin);
}

 void activateRelay(){ 
  
  digitalWrite(relayPin, HIGH);
   
  
}
  

in a new post in the same thread.
You did it right

Try to swap of relay switching and detach command as I did in #12

Now the LED cycles on and off, looks to be about 300ms for each.

//SPECIFIC TIME TRIGGER SOLENOID
//low power - alarm wakes up - activate relay (on then off after 1000ms) loop to start
#include <DS3231.h>
#include <Wire.h>
#include <LowPower.h>

#define wakeUpPin 2
#define relayPin 4


DS3231 Clock;

byte alarmDay;
byte alarmHour;
byte alarmMinute;
byte alarmSecond;
byte alarmBits;
bool alarmDayIsDay; 
bool alarmH12;
bool alarmPM;


void setup() {
  Serial.begin(57600);
  Serial.println("Hello");
  //rtc.begin();
  //not needed
  pinMode(relayPin, OUTPUT);
  pinMode(wakeUpPin, INPUT);
  
  Wire.begin();

alarmDay = 0;
alarmHour = 15;
alarmMinute = 12;
alarmSecond = 00;
alarmBits = 0b00001000; 
alarmDayIsDay = false;
alarmH12 = false;
alarmPM = false;  

Serial.println("Setting alarm for");
Serial.println(alarmHour);
Serial.println(alarmMinute);
Clock.turnOffAlarm(1);
Clock.setA1Time(
       alarmDay, alarmHour, alarmMinute, alarmSecond,
       alarmBits, alarmDayIsDay, alarmH12, alarmPM);
    // enable Alarm 1 interrupts
Clock.turnOnAlarm(1);
    // clear Alarm 1 flag
Clock.checkIfAlarm(1);
Serial.println("Alarm set");

Clock.turnOffAlarm(2);


  
  //byte ALRM2_SET =  ALRM2_MATCH_HR_MIN;

 // int ALARM_BITS = ALRM2_SET;
  //ALARM_BITS <<= 4;
  //ALARM_BITS |= ALRM2_SET;

  // Prevent Alarm 2 altogether by assigning a 
    // nonsensical alarm minute value that cannot match the clock time,
    // and an alarmBits value to activate "when minutes match".
    //alarmMinute = 0xFF; // a value that will never match the time
    //alarmBits = 0b01100000; // Alarm 2 when minutes match, i.e., never
    
    // Upload the parameters to prevent Alarm 2 entirely
    //Serial.println("Clearing alarm 2");
    //Clock.setA2Time(
       // alarmDay, alarmHour, alarmMinute,
       // alarmBits, alarmDayIsDay, alarmH12, alarmPM);
    // disable Alarm 2 interrupt
    //Clock.turnOffAlarm(2);
    // clear Alarm 2 flag
   // Clock.checkIfAlarm(2);
   // Serial.println("Alarm 2 cleared");
    // NOTE: both of the alarm flags must be clear
    // to enable output of a FALLING interrupt
  
 
}

/*void loop() {

  pinMode(wakeUpPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), activateRelay, LOW);  
  Serial.flush();
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  delay(300);
  Serial.println("Waking up");
  delay(1000);
  Serial.println("Deactivating");
  digitalWrite(relayPin, LOW);
  delay(300);
  detachInterrupt(digitalPinToInterrupt(2));
}

 void activateRelay(){ 
  
  digitalWrite(relayPin, HIGH);
   
  
}*/
  
    void loop() {

  pinMode(wakeUpPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), activateRelay, LOW);  
  Serial.flush();
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  delay(500);
  digitalWrite(relayPin, HIGH);
  Serial.println("Waking up");
  delay(1000);
  digitalWrite(relayPin, LOW);
  delay(300);
  
}

void activateRelay(){ 
  
  detachInterrupt(wakeUpPin);
}


Cycles on and off repeatedly, I should say.

With this setting, interrupts will keep firing as long as input pin 2 is LOW. Perhaps you should immediately reset the RTC alarm.