Alarm RTC DS3231 wake Arduino?

Hi, everyone, I was trying to put my DS3231 alarm to wake up my Arduino UNO every 6 hours, but I found in library that it's only possible to wake up every single hour. Do you guys have any trick to help me, please? Maybe editing the library? I don't know if it is smart.

I think that I can wake Arduino every hour and verify if that hour is a six multiple but, this way, I'll set Arduino to wake every hour, wasting energy, and this is just what I don't want. Because of this, I put it to sleep for long 6 hours. I don't know if I was clear... Thanks, some way.

Hello :)

You can setup the alarm whenever you want.

  • Alarm once per second
  • Alarm when seconds match
  • Alarm when minutes and seconds match
  • Alarm when hours, minutes, and seconds match
  • Alarm when date, hours, minutes, and seconds match
  • Alarm when day, hours, minutes, and seconds match

See datasheet for more informations.

I use this library https://github.com/JChristensen/DS3232RTC.

The way that you must specify an alarm in the DS3231 does not allow you to specify "every 6 hours". You would have to set up an alarm every hour. The interrupt routine would have to count the hourly interrupts until 6 of them had occurred which then triggers the execution of whatever function is required.

Pete

This is wrong…

Here is an example to setup the alarm every 5 seconds (just change some variables for every 6 hours):

#include <DS3232RTC.h>
#include <Wire.h>

DS3232RTC rtc;

void setup()
{
    Serial.begin( 115200 );
    Wire.begin();
    rtc.alarm( ALARM_1 ); // makes sure A1F is cleared (see datasheet p.14)
    rtc.setAlarm( ALM1_MATCH_SECONDS, 0, 0, 0, 0 );
}

void loop()
{
    if ( rtc.alarm( ALARM_1 ) )
    {
        tmElements_t tm;
        rtc.read( tm );
        rtc.setAlarm( ALM1_MATCH_SECONDS, ( tm.Second + 5 ) % 60, 0, 0, 0 );
        time_t now = makeTime( tm );
        Serial.println( now );
    }
}

The first alarm will be triggered when seconds == 0, and then every 5 seconds. You can add code in setup (or elsewhere), to set the first alarm whenever you need it… This was just an example.

You've only proved my point. You can't set an (i.e. ONE) alarm which will trigger an interrupt every 6 hours. One way or another, you have to work around this. I do like your method though.

Pete

This is how I use the interrupt pin

include <Wire.h>
#include <DS3232RTC.h>

DS3232RTC rtc;
const uint8_t rtcInterruptPin = D7;
volatile bool rtcInterrupt = false;
void rtcISR() { rtcInterrupt = true; }

void setup()
{
    Serial.begin( 115200 );
    rtc.alarm( ALARM_1 );
    rtc.alarmInterrupt( ALARM_1, true );
    rtc.setAlarm( ALM1_EVERY_SECOND, 0, 0, 0, 0 );
    pinMode( rtcInterruptPin, INPUT_PULLUP );
    attachInterrupt( digitalPinToInterrupt( rtcInterruptPin ), rtcISR, FALLING );
}

void loop()
{
    if ( rtcInterrupt )
    {
        rtcInterrupt = false;
        rtc.alarm( ALARM_1 );
        tmElements_t tm;
        rtc.read( tm );
        rtc.setAlarm( ALM1_MATCH_SECONDS, ( tm.Second + 5 ) % 60, 0, 0, 0 );
        time_t now = makeTime( tm );
        Serial.println( now );
    }
}

No sleep code because I use another platform (NodeMCU)

guix:
This is wrong…

Here is an example to setup the alarm every 5 seconds (just change some variables for every 6 hours):

#include <DS3232RTC.h>

#include <Wire.h>

DS3232RTC rtc;

void setup()
{
   Serial.begin( 115200 );
   Wire.begin();
   rtc.alarm( ALARM_1 ); // makes sure A1F is cleared (see datasheet p.14)
   rtc.setAlarm( ALM1_MATCH_SECONDS, 0, 0, 0, 0 );
}

void loop()
{
   if ( rtc.alarm( ALARM_1 ) )
   {
       tmElements_t tm;
       rtc.read( tm );
       rtc.setAlarm( ALM1_MATCH_SECONDS, ( tm.Second + 5 ) % 60, 0, 0, 0 );
       time_t now = makeTime( tm );
       Serial.println( now );
   }
}




The first alarm will be triggered when seconds == 0, and then every 5 seconds. You can add code in setup (or elsewhere), to set the first alarm whenever you need it... This was just an example.

Nice method. Thank you!
I will try some around this.

@guix it woked!
But now, when I put Arduino to sleep, the alarm that I set to wake every 5 minutes, just works one time. If a set a second alarm, every minute, it works…

The code that works:

void loop(void)
{ 
  if (RTC.alarm(ALARM_1))
  {
    RTC.read(tm);
    RTC.setAlarm(ALM1_MATCH_MINUTES, 0, (tm.Minute + 5) % 60, 0, 0);
    t = now();                                        
    Serial.println(" ");
    Serial.println("Alarm 1");
    Serial.print(hour(t));                        
    Serial.print(":");
    Serial.print(minute(t));                      
    Serial.print(":");
    Serial.println(second(t));
    digitalWrite(led, LOW);
  }
  if (RTC.alarm(ALARM_2))                         
  {
    sleep_disable();
    t = now();                                        
    Serial.println(" ");
    Serial.println("Alarm 2");
    Serial.print(hour(t));                        
    Serial.print(":");
    Serial.print(minute(t));                      
    Serial.print(":");
    Serial.println(second(t));
    delay(100);
    sleep_enable();
    attachInterrupt(0, wake, LOW);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_mode();
  }
}

Doesn’t:

void loop(void)
{ 
  if (RTC.alarm(ALARM_1))
  {
    sleep_disable();
    RTC.read(tm);
    RTC.setAlarm(ALM1_MATCH_MINUTES, 0, (tm.Minute + 5) % 60, 0, 0);
    t = now();                                        
    Serial.println(" ");
    Serial.println("Alarm 1");
    Serial.print(hour(t));                        
    Serial.print(":");
    Serial.print(minute(t));                      
    Serial.print(":");
    Serial.println(second(t));
    digitalWrite(led, LOW);
    delay(100);
    sleep_enable();
    attachInterrupt(0, wake, LOW);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_mode();
  }
  if (RTC.alarm(ALARM_2))                         
  {
    t = now();                                        
    Serial.println(" ");
    Serial.println("Alarm 2");
    Serial.print(hour(t));                        
    Serial.print(":");
    Serial.print(minute(t));                      
    Serial.print(":");
    Serial.println(second(t));
  }
}

Your code has not set an alarm interrupt, it is only polling the alarm bit. When the processor goes to sleep, the polling stops.
There is an alarmInterrupt function in the library to set or clear an alarm interrupt but I have never used this library.

Pete

@el_supremo I'll try. Thank you!

If you want an alarm every 6 hours I imagine you just need to set the alarm date and time at 6 hours in the future and set the alarm type to date time. Then reset the alarm date and time after each alarm.

@guix I wanted to thank you for your solution on how to increase the interrupt interval for the DS3232RTC library. I was struggling to figure out a way to accomplish this!

In your code I noticed that you instantiate a new “rtc” object. Did you know that the DS3232RTC library by default instantiates an “RTC” object?

In case anyone is curious, I’ll include how I incorporated @guix’s solution with the LowPower.h library. My sleep interval in the example below is set to 15 minutes.

Cheers,
Adam

#include <DS3232RTC.h>
#include <TimeLib.h>
#include <Wire.h>
#include <LowPower.h>

tmElements_t tm;
const byte rtcAlarmPin = 3; // External interrupt on pin D3

void setup()
{
  Serial.begin(9600);
  Serial.println("DS3231RTC Alarm Test");
  TimeDateDisplay();
  delay(100);

  pinMode(rtcAlarmPin, INPUT_PULLUP); // Set interrupt pin
  RTC.squareWave(SQWAVE_NONE); // Disable the default square wave of the SQW pin

  // setAlarm Syntax (RTC.setAlarm(alarmType, seconds, minutes, hours, dayOrDate);)
  RTC.setAlarm(ALM1_MATCH_SECONDS, 0, 0, 0, 0 );
  RTC.alarm(ALARM_1);
  RTC.alarmInterrupt(ALARM_1, true); // Enable alarm 1 interrupt A1IE
}

// Interrupt Service Routine (ISR) function
void wake ()
{
  detachInterrupt (digitalPinToInterrupt (3)); // Disable interrupts on D3
}

void sleepNow ()
{
  noInterrupts (); // Disable interrupts before entering sleep
  attachInterrupt (digitalPinToInterrupt(3), wake, FALLING);  // Wake on falling edge of D3
  interrupts (); // Enable interrupts to ensure next instruction is executed
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
}

void loop()
{
  Serial.println("Entering sleep");
  delay(100);

  sleepNow(); // Enter sleep

  Serial.println("Awake...");
  if (RTC.alarm(ALARM_1))
  {
    RTC.read(tm);
    RTC.setAlarm(ALM1_MATCH_MINUTES, 0, (tm.Minute + 15) % 60, 0, 0);
    TimeDateDisplay();
  }
}

void TimeDateDisplay()
{
  RTC.read(tm);
  char dateBuffer[19];
  sprintf(dateBuffer, "%04u-%02u-%02u %02u:%02u:%02u", (tm.Year + 1970), tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
  Serial.println(dateBuffer);
}

guix:
This is wrong…

Here is an example to setup the alarm every 5 seconds (just change some variables for every 6 hours):

#include <DS3232RTC.h>

#include <Wire.h>

DS3232RTC rtc;

void setup()
{
   Serial.begin( 115200 );
   Wire.begin();
   rtc.alarm( ALARM_1 ); // makes sure A1F is cleared (see datasheet p.14)
   rtc.setAlarm( ALM1_MATCH_SECONDS, 0, 0, 0, 0 );
}

void loop()
{
   if ( rtc.alarm( ALARM_1 ) )
   {
       tmElements_t tm;
       rtc.read( tm );
       rtc.setAlarm( ALM1_MATCH_SECONDS, ( tm.Second + 5 ) % 60, 0, 0, 0 );
       time_t now = makeTime( tm );
       Serial.println( now );
   }
}




The first alarm will be triggered when seconds == 0, and then every 5 seconds. You can add code in setup (or elsewhere), to set the first alarm whenever you need it... This was just an example.

@guix
could you explain me, why the divider %60 is necessary?

  • Do I have to use ‘( tm.Hour + 5 ) % 24’ if i want an alarm every 5 hours?
  • What i have to use when i want an alarm all 28 days?

DanielRaetz: @guix could you explain me, why the divider %60 is necessary? - Do I have to use '( tm.Hour + 5 ) % 24' if i want an alarm every 5 hours? - What i have to use when i want an alarm all 28 days?

Hi Daniel,

The "%" is called the modulo operator. I highly suggest giving this link a read and trying out some of the code yourself. It really helped me to understand the concept. Basically, it's going to make sure that the value you enter stays within a certain range, as well as helping with minute, hour, and day rollovers. For example, if the time is 23:00, and your alarm is:

rtc.setAlarm(ALM1_MATCH_HOURS, 0, 0, (tm.Hour + 5) % 24, 0 );

The modulo operator will make sure the value does not exceed 24 and your result will be 4, or 4:00.

You are correct in that is how you would structure an alarm to occur every 5 hours. You'll need to make sure that you do a RTC.read(tm); every time your alarm triggers so you have the current time with which to make the calculations with.

Regarding the 28 day alarm, this is more tricky. Did you mean you'd like an alarm every 28 days, or on every 28th day of the month. There's a difference. If you look at Jack Christensen's alarm_ex3 in his DS3232RTC GitHub, you'll see he provides a way to have a rolling alarm based on a time value in seconds. You could in theory set the alarm to occur every 28*86400 or 2419200 seconds (28 days). I'm also sure there's probably many other ways to do this.

Cheers, Adam

@ adam_g

HI Adam,

thanks a lot for the provided links, that helped me.
Now i made a mix between the example from Christensen’s alarm_ex3 and the above provided code with the LowPower library:

#include <DS3232RTC.h>        // https://github.com/JChristensen/DS3232RTC
//#include <Streaming.h>        // http://arduiniana.org/libraries/streaming/
#include <LowPower.h>

const time_t ALARM_INTERVAL(10);    // alarm interval in seconds

tmElements_t tm;
const byte rtcAlarmPin = 3; // External interrupt on pin D3

void setup()
{
  Serial.begin(9600);
  pinMode(rtcAlarmPin, INPUT_PULLUP); // Set interrupt pin
  // initialize the alarms to known values, clear the alarm flags, clear the alarm interrupt flags
  RTC.setAlarm(ALM1_MATCH_DATE, 0, 0, 0, 1);
  RTC.setAlarm(ALM2_MATCH_DATE, 0, 0, 0, 1);
  RTC.alarm(ALARM_1);
  RTC.alarm(ALARM_2);
  RTC.alarmInterrupt(ALARM_1, false);
  RTC.alarmInterrupt(ALARM_2, false);
  RTC.squareWave(SQWAVE_NONE);

  // tmElements_t tm;
  /* tm.Hour = 00;                   // set the RTC to an arbitrary time
    tm.Minute = 00;
    tm.Second = 00;
    tm.Day = 16;
    tm.Month = 9;
    tm.Year = 2017 - 1970;   // tmElements_t.Year is the offset from 1970
  */
  RTC.read(tm);
 //TimeDateDisplay();
  time_t t = makeTime(tm);        // change the tm structure into time_t (seconds since epoch)
  time_t alarmTime = t + ALARM_INTERVAL;    // calculate the alarm time

  // set the current time
  // RTC.set(t);
  // set the alarm
  RTC.setAlarm(ALM1_MATCH_HOURS, second(alarmTime), minute(alarmTime), hour(alarmTime), 0);
  // clear the alarm flag
  RTC.alarm(ALARM_1);
  RTC.alarmInterrupt(ALARM_1, true); // Enable alarm 1 interrupt A1IE

  //TimeDateDisplay();
}

void loop()
{
 
Serial.println("Entering sleep");
  delay(100);

  sleepNow(); // Enter sleep

  Serial.println("Awake...");
  
  if ( RTC.alarm(ALARM_1) )
  {
    Serial.println("Alarm..");
    //TimeDateDisplay();
   
     RTC.read(tm);
     
  
  time_t t = makeTime(tm);        // change the tm structure into time_t (seconds since epoch)
  time_t alarmTime = t + ALARM_INTERVAL;    // calculate the alarm time
    // set the alarm
    RTC.setAlarm(ALM1_MATCH_HOURS, second(alarmTime), minute(alarmTime), hour(alarmTime), 0);

  }
}

/*void printDateTime(time_t t)
  {
    Serial << ((day(t)<10) ? "0" : "") << _DEC(day(t));
    Serial << monthShortStr(month(t)) << _DEC(year(t)) << ' ';
    Serial << ((hour(t)<10) ? "0" : "") << _DEC(hour(t)) << ':';
    Serial << ((minute(t)<10) ? "0" : "") << _DEC(minute(t)) << ':';
    Serial << ((second(t)<10) ? "0" : "") << _DEC(second(t));
  }*/

void TimeDateDisplay() //Zeitanzeige
{
  RTC.read(tm);
  char dateBuffer[19];
  sprintf(dateBuffer, "%04u-%02u-%02u %02u:%02u:%02u", (tm.Year + 1970), tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second);
  Serial.println(dateBuffer);
}
// Interrupt Service Routine (ISR) function
void wake ()
{
  detachInterrupt (digitalPinToInterrupt (3)); // Disable interrupts on D3
  
}

void sleepNow ()
{
  noInterrupts (); // Disable interrupts before entering sleep
  attachInterrupt (digitalPinToInterrupt(3), wake, FALLING);  // Wake on falling edge of D3
  interrupts (); // Enable interrupts to ensure next instruction is executed
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
}

I don’t want to use the Streaming library, because of that i can’t use the funcion printDateTime(time_t t). I’d like to use the function TimeDateDisplay(), but i noticed when i use the TimeDateDisplay(), the Alarm1 doesn’t repeat anymore. When i don’t use TimeDateDisplay() as in my code, it works fine. If i use a seperate instance of tmElements_t xx (not tm) for TimeDateDisplay(), then it works also.
Do you have any idea why that is?

DanielRaetz:
@ adam_g

HI Adam,

thanks a lot for the provided links, that helped me.
Now i made a mix between the example from Christensen’s alarm_ex3 and the above provided code with the LowPower library:

I don’t want to use the Streaming library, because of that i can’t use the funcion printDateTime(time_t t). I’d like to use the function TimeDateDisplay(), but i noticed when i use the TimeDateDisplay(), the Alarm1 doesn’t repeat anymore. When i don’t use TimeDateDisplay() as in my code, it works fine. If i use a seperate instance of tmElements_t xx (not tm) for TimeDateDisplay(), then it works also.
Do you have any idea why that is?

Hi Daniel,

I learned, after much troubleshooting, that using a function like the TimeDateDisplay() can cause unexpected problems. This is because each time you call the function, you’re entering new values into the tm object (minute, hour, day, etc.). If you’re also using the tm object to set all of your alarms, you’ll have to be careful exactly when you’re calling the function.

My solution was to only use RTC.read™ for alarm related operations and I simply replaced the Streaming.h Serial << code with Serial.print(), as shown below:

// Print current time and date
void printDateTime(time_t t)
{
  Serial.print((day(t) < 10) ? "0" : ""); Serial.print(day(t), DEC); Serial.print('/');
  Serial.print((month(t) < 10) ? "0" : ""); Serial.print(month(t), DEC); Serial.print('/');
  Serial.print(year(t), DEC); Serial.print(' ');
  Serial.print((hour(t) < 10) ? "0" : ""); Serial.print(hour(t), DEC); Serial.print(':');
  Serial.print((minute(t) < 10) ? "0" : ""); Serial.print(minute(t), DEC); Serial.print(':');
  Serial.print((second(t) < 10) ? "0" : ""); Serial.println(second(t), DEC);
}

You can customize the order and format of how the date and time is printed as you see fit.

Hope that helps!

Cheers,
Adam

@adam_g

Hi Adam,

thx for the customized function printDateTime(time_t t).
I came across another problem. I tried out an alarminterval of 20 hours (206060 sec). Before setting the alarm i printed out the current time. After setting the alarm time as shown below, i printed out also the alarmTime with printDateTime(alarmTime) to see, if the time is set correctly.

time_t alarmTime = t + ALARM_INTERVAL;

I figured out, using an alarminterval over 18 hours, the alarmTime is set incorrectly. Up to 18 hours it works, also the day rollover.
Serial Output from the faulty case was like this (e.g. interval of 19hours):
DateTime now: 2018/05/28 20:30:00
DateTime alarmTime: 2018/05/28 20:35:15 (no day-rollover, incorrect hours, minutes, seconds)

Now i’m trying out another method using the additional library RTClib as shown below. I’ll try out some intervals of hours and days, till now it looks good.

    DateTime now = rtc.now();
    DateTime future (now + TimeSpan(0, 1, 0, 0)); //Days, Hours, Minutes, Seconds
    Serial.println(F("Alarm is set to: "));
    printDateTime(future);
    RTC.setAlarm(ALM1_MATCH_DATE, future.second(), future.minute(), future.hour(), future.day());

DanielRaetz: @adam_g

Hi Adam,

thx for the customized function printDateTime(time_t t). I came across another problem. I tried out an alarminterval of 20 hours (20*60*60 sec). Before setting the alarm i printed out the current time. After setting the alarm time as shown below, i printed out also the alarmTime with printDateTime(alarmTime) to see, if the time is set correctly.

I figured out, using an alarminterval over 18 hours, the alarmTime is set incorrectly. Up to 18 hours it works, also the day rollover. Serial Output from the faulty case was like this (e.g. interval of 19hours): DateTime now: 2018/05/28 20:30:00 DateTime alarmTime: 2018/05/28 20:35:15 (no day-rollover, incorrect hours, minutes, seconds)

Now i'm trying out another method using the additional library RTClib as shown below. I'll try out some intervals of hours and days, till now it looks good.

Hi Daniel,

I'm familiar with the RTClib library, which is also a good choice.

Please include your code that resulted in the 18 hour issue if you'd like me to take a look at what went wrong. I was setting the alarm to a value of 172800 seconds using this very same method just the other day. Was your ALARM_INTERVAL variable declared as an time_t or unsigned long? Also, did you input 72000 as a value or the actual calculation (20*60*60)? If the latter, you may need to add the U & L formatters to force the values to the correct data type i.e. (20UL*60*UL*60UL) .

Here's an bit of code showing you what I mean:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(57600);
  
  unsigned long ALARM_INTERVAL;
  ALARM_INTERVAL = 20*60*60;
  Serial.println(ALARM_INTERVAL);

  ALARM_INTERVAL = 20UL*60UL*60UL;
  Serial.println(ALARM_INTERVAL);
}

void loop() {
  // put your main code here, to run repeatedly:


}

The result are as follows: ALARM_INTERVAL = 20*60*60; = 6464 ALARM_INTERVAL = 20UL*60UL*60UL; = 72000

So, you can see how important the integer constant formatters are here when you're adding the ALARM_INTERVAL value to set your alarm.

Cheers, Adam

adam_g:
Hi Daniel,

I’m familiar with the RTClib library, which is also a good choice.

Please include your code that resulted in the 18 hour issue if you’d like me to take a look at what went wrong. I was setting the alarm to a value of 172800 seconds using this very same method just the other day. Was your ALARM_INTERVAL variable declared as an time_t or unsigned long? Also, did you input 72000 as a value or the actual calculation (206060)? If the latter, you may need to add the U & L formatters to force the values to the correct data type i.e. (20UL60UL*60UL) .

Hi Adam,

Yes, i declared the ALARM_INTERVAL variable as time_t. So i tested your advice with UL, it works!
(At least the alarm time is calculated correctly);
Now I have to choose between two variants that work both ; )

Here my code with the time_t variant:

#include <DS3232RTC.h>        // https://github.com/JChristensen/DS3232RTC
#include <LowPower.h>

//const time_t ALARM_INTERVAL(20 * 60 * 60); // 20 Hour - DOESN'T WORK-> use UL
unsigned long ALARM_INTERVAL=28UL*24UL*60UL*60UL; //28 Days - Works
tmElements_t tm;
const byte rtcAlarmPin = 3; // External interrupt on pin D3

void setup()
{
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  Serial.begin(9600);
  pinMode(rtcAlarmPin, INPUT_PULLUP); // Set interrupt pin
  // initialize the alarms to known values, clear the alarm flags, clear the alarm interrupt flags
  RTC.setAlarm(ALM1_MATCH_DATE, 0, 0, 0, 1);
  RTC.setAlarm(ALM2_MATCH_DATE, 0, 0, 0, 1);
  RTC.alarm(ALARM_1);
  RTC.alarm(ALARM_2);
  RTC.alarmInterrupt(ALARM_1, false);
  RTC.alarmInterrupt(ALARM_2, false);
  RTC.squareWave(SQWAVE_NONE);

  RTC.read(tm);
   time_t t = makeTime(tm);        // change the tm structure into time_t (seconds since epoch)
  Serial.println(F("Aktuelle Zeit t: "));
  printDateTime(t);
  
  time_t alarmTime = t + ALARM_INTERVAL;    // calculate the alarm time
  Serial.println(F("Alarm wird gesetzt auf: ")); 
  printDateTime(alarmTime);

  // set the current time
  // RTC.set(t);
  // set the alarm
  RTC.setAlarm(ALM1_MATCH_HOURS, second(alarmTime), minute(alarmTime), hour(alarmTime), 0);
  // clear the alarm flag
  RTC.alarm(ALARM_1);
  RTC.alarmInterrupt(ALARM_1, true); // Enable alarm 1 interrupt A1IE
}

void loop()
{
  // check to see if the alarm flag is set (also resets the flag if set)
  Serial.println("Entering sleep");
  delay(100);
  sleepNow(); // Enter slee
  setRTCagain();
}
// Interrupt Service Routine (ISR) function
void wake ()
{
  detachInterrupt (digitalPinToInterrupt (3)); // Disable interrupts on D3
}

void sleepNow ()
{
  noInterrupts (); // Disable interrupts before entering sleep
  attachInterrupt (digitalPinToInterrupt(3), wake, FALLING);  // Wake on falling edge of D3
  interrupts (); // Enable interrupts to ensure next instruction is executed
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
}

void setRTCagain() {
  Serial.println("Awake...");

  if ( RTC.alarm(ALARM_1) )
  {
    Serial.println("Alarm1 now..: ");
    RTC.read(tm);
    time_t t = makeTime(tm);        // change the tm structure into time_t (seconds since epoch)
    printDateTime(t);
    time_t alarmTime = t + ALARM_INTERVAL;    // calculate the alarm time
    Serial.println(F("Alarm is set to: "));
    printDateTime(alarmTime);
    // set the alarm
    RTC.setAlarm(ALM1_MATCH_HOURS, second(alarmTime), minute(alarmTime), hour(alarmTime), 0);
  }
}
// Print current time and date
void printDateTime(time_t t)
{
  Serial.print((day(t) < 10) ? "0" : ""); Serial.print(day(t), DEC); Serial.print('/');
  Serial.print((month(t) < 10) ? "0" : ""); Serial.print(month(t), DEC); Serial.print('/');
  Serial.print(year(t), DEC); Serial.print(' ');
  Serial.print((hour(t) < 10) ? "0" : ""); Serial.print(hour(t), DEC); Serial.print(':');
  Serial.print((minute(t) < 10) ? "0" : ""); Serial.print(minute(t), DEC); Serial.print(':');
  Serial.print((second(t) < 10) ? "0" : ""); Serial.println(second(t), DEC);
}

And here with the RTClib variant:
(Requires an additional function to use the alarm interval as a global variable - here not included)…

#include <DS3232RTC.h>        // https://github.com/JChristensen/DS3232RTC
#include <LowPower.h>
#include "RTClib.h"

RTC_DS3231 rtc;

const byte rtcAlarmPin = 3; // External interrupt on pin D3

void setup()
{
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  Serial.begin(9600);
  pinMode(rtcAlarmPin, INPUT_PULLUP); // Set interrupt pin
  // initialize the alarms to known values, clear the alarm flags, clear the alarm interrupt flags
  RTC.setAlarm(ALM1_MATCH_DATE, 0, 0, 0, 1);
  RTC.setAlarm(ALM2_MATCH_DATE, 0, 0, 0, 1);
  RTC.alarm(ALARM_1);
  RTC.alarm(ALARM_2);
  RTC.alarmInterrupt(ALARM_1, false);
  RTC.alarmInterrupt(ALARM_2, false);
  RTC.squareWave(SQWAVE_NONE);


  // set the alarm
  DateTime now = rtc.now();
  Serial.println(F("Current Time: "));
  printDateTime(now);
  DateTime future (now + TimeSpan(28, 0, 0, 0)); //Days, Hours, Minutes, Seconds
  Serial.println(F("Alarm is set to: "));
  printDateTime(future);


  RTC.setAlarm(ALM1_MATCH_DATE, future.second(), future.minute(), future.hour(), future.day());
  // clear the alarm flag
  RTC.alarm(ALARM_1);
  RTC.alarmInterrupt(ALARM_1, true); // Enable alarm 1 interrupt A1IE
}

void loop()
{
  // check to see if the alarm flag is set (also resets the flag if set)
  Serial.println("Entering sleep");
  delay(100);
  sleepNow(); // Enter slee
  setRTCagain();
}
// Interrupt Service Routine (ISR) function
void wake ()
{
  detachInterrupt (digitalPinToInterrupt (3)); // Disable interrupts on D3
}

void sleepNow ()
{
  noInterrupts (); // Disable interrupts before entering sleep
  attachInterrupt (digitalPinToInterrupt(3), wake, FALLING);  // Wake on falling edge of D3
  interrupts (); // Enable interrupts to ensure next instruction is executed
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
}

void setRTCagain() {
  Serial.println("Awake...");
  if ( RTC.alarm(ALARM_1) )
  {
    Serial.println("Now Alarm!");

    // set the alarm
    DateTime now = rtc.now();
    DateTime future (now + TimeSpan(28, 0, 0, 0)); //Days, Hours, Minutes, Seconds
    Serial.println(F("Alarm is set to: "));
    printDateTime(future);
    RTC.setAlarm(ALM1_MATCH_DATE, future.second(), future.minute(), future.hour(), future.day());
  }
}

void printDateTime(DateTime t)
{
  Serial.print((t.day() < 10) ? "0" : ""); Serial.print(t.day(), DEC); Serial.print('/');
  Serial.print((t.month() < 10) ? "0" : ""); Serial.print(t.month(), DEC); Serial.print('/');
  Serial.print(t.year(), DEC); Serial.print(' ');
  Serial.print((t.hour() < 10) ? "0" : ""); Serial.print(t.hour(), DEC); Serial.print(':');
  Serial.print((t.minute() < 10) ? "0" : ""); Serial.print(t.minute(), DEC); Serial.print(':');
  Serial.print((t.second() < 10) ? "0" : ""); Serial.println(t.second(), DEC);
}

The code below works with UNO to wake up the controller every 15s. But with the mega2560 board it doesn’t work anymore - I can’t figure out why…

The controller goes to sleep and doesn’t wake up anymore on RTC interrupt. I checked the level of interrupt pin - it goes after 15s from high to low, but the controller doesn’t react to this falling edge.

Has anyone an idea why?

#include <DS3232RTC.h>        // https://github.com/JChristensen/DS3232RTC
#include <LowPower.h>
#include "RTClib.h"

RTC_DS3231 rtc;

const byte rtcAlarmPin = 2; // External interrupt on pin D2

void setup()
{
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  Serial.begin(115200);
  pinMode(rtcAlarmPin, INPUT_PULLUP); // Set interrupt pin
  // initialize the alarms to known values, clear the alarm flags, clear the alarm interrupt flags
  RTC.setAlarm(ALM1_MATCH_DATE, 0, 0, 0, 1);
  RTC.setAlarm(ALM2_MATCH_DATE, 0, 0, 0, 1);
  RTC.alarm(ALARM_1);
  RTC.alarm(ALARM_2);
  RTC.alarmInterrupt(ALARM_1, false);
  RTC.alarmInterrupt(ALARM_2, false);
  RTC.squareWave(SQWAVE_NONE);


  // set the alarm
  DateTime now = rtc.now();
  Serial.println(F("Current Time: "));
  printDateTime(now);
  DateTime future (now + TimeSpan(0, 0, 0, 15)); //Tage, Stunden, Minuten, Sekunden
  Serial.println(F("Alarm is set to: "));
  printDateTime(future);


  RTC.setAlarm(ALM1_MATCH_DATE, future.second(), future.minute(), future.hour(), future.day());
  // clear the alarm flag
  RTC.alarm(ALARM_1);
  RTC.alarmInterrupt(ALARM_1, true); // Enable alarm 1 interrupt A1IE
  // ---Check Alarm Pin/Debug---//
  /*
    int val = digitalRead(2);
    Serial.println("Pin 2 ist: " + String(val));
  */
  // ---------------------//
}

void loop()
{
  // ---Check Alarm Pin/Debug---//
  /*
    int val=digitalRead(2);
    Serial.println("Pin 2 ist: " + String(val));
    delay(1000);
    if (val==0){
     setRTCagain();
     }
  */
  // ---------------------//
  //delay(100);
  digitalWrite(13, LOW);
  delay(200);
  sleepNow(); // Enter slee digitalPinToInterrupt(2)
  digitalWrite(13, HIGH);
  setRTCagain();
  delay(5000);
}
// Interrupt Service Routine (ISR) function
void wake ()
{
  detachInterrupt (digitalPinToInterrupt(rtcAlarmPin)); // Disable interrupts on D2
}

void sleepNow ()
{
  noInterrupts (); // Disable interrupts before entering sleep
  attachInterrupt (digitalPinToInterrupt(rtcAlarmPin), wake, FALLING);  // Wake on falling edge of D2
  interrupts (); // Enable interrupts to ensure next instruction is executed
  Serial.println("Entering sleep");
  delay(20);
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
}

void setRTCagain() {
  Serial.println("Awake...");
  if ( RTC.alarm(ALARM_1) )
  {
    Serial.println("Now Alarm!");

    // set the alarm
    DateTime now = rtc.now();
    DateTime future (now + TimeSpan(0, 0, 0, 15)); //Days, Hours, Minutes, Seconds
    Serial.println(F("Alarm is set to: "));
    printDateTime(future);
    RTC.setAlarm(ALM1_MATCH_DATE, future.second(), future.minute(), future.hour(), future.day());
  }
}

void printDateTime(DateTime t)
{
  Serial.print((t.day() < 10) ? "0" : ""); Serial.print(t.day(), DEC); Serial.print('/');
  Serial.print((t.month() < 10) ? "0" : ""); Serial.print(t.month(), DEC); Serial.print('/');
  Serial.print(t.year(), DEC); Serial.print(' ');
  Serial.print((t.hour() < 10) ? "0" : ""); Serial.print(t.hour(), DEC); Serial.print(':');
  Serial.print((t.minute() < 10) ? "0" : ""); Serial.print(t.minute(), DEC); Serial.print(':');
  Serial.print((t.second() < 10) ? "0" : ""); Serial.println(t.second(), DEC);
}