DS3231 Sleep-Wake stops loop when Minutes = 0

Hello!

We built an ultrasonic sensor attached to an Arduino Uno that sleeps and wake every 1 minute to measure distance by the minute. However, results show that the loop ends at 00:59:00 (59th minute) regardless of the date and the hour. This happens both when the Arduino is connected to the computer, and to a separate power source. Attached is our code below.

If you have any ideas to prevent the code from ending the loop and instead continuing indefinitely, please inform us.

Thanks in advance!

//-------------PIN ASSIGNMENTS----------------
/*
  SD CARD:
  MOSI: PIN 11
  MISO: PIN 12
  CLK:  PIN 13
  CS:   PIN 4

  ULTRASONIC SENSOR:
  TRIGGER: PIN 7
  ECHO:    PIN 6

  RTC:
  SQW:  PIN 2
  SCL:  PIN A5
  SDA:  PIN A4
*/

//----------------SLEEP CODE------------------
#include <avr/sleep.h>                //this AVR library contains the methods that controls the sleep modes
#define interruptPin 2                //Pin we are going to use to wake up the Arduino
#include <DS3232RTC.h>                //RTC Library https://github.com/JChristensen/DS3232RTC
const int time_interval = 1;          // Sets the wakeup intervall in minutes

//----------------RTC CODE--------------------
#include <Wire.h>
#include "RTClib.h"                   // Date and time functions using a DS3231 RTC connected via I2C and Wire lib
RTC_DS3231 rtc;
//char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

//-----------ULTRASONIC SENSOR CODE-----------
const int pingPin = 7;                // Trigger Pin of Ultrasonic Sensor
const int echoPin = 6;                // Echo Pin of Ultrasonic Sensor

//--------------SD LIBRARIES------------
#include <SPI.h>
#include <SD.h>
char fname[] = "trial.txt";

void setup() {
  Serial.begin(9600);//Start Serial Comunication
  pinMode(LED_BUILTIN, OUTPUT);                 //We use the led on pin 13 to indecate when Arduino is A sleep
  pinMode(interruptPin, INPUT_PULLUP);          //Set pin d2 to input using the builtin pullup resistor
  digitalWrite(LED_BUILTIN, HIGH);              //turning LED on

  //------------INITIALIZE SD CARD------------
  Serial.print("Initializing SD card...");
  if (!SD.begin()) {
    Serial.println("Initialization failed!");
    while (1);
  }
  Serial.println("SD card initialized.");

  //------------INITIALIZE RTC------------
#ifndef ESP8266
  while (!Serial); // for Leonardo/Micro/Zero
#endif

  delay(1000);                                  // wait for console opening
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }

  //------------INITIALIZE SLEEP-WAKE-----------
  // 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);

  time_t t; //create a temporary time variable so we can set the time and read the time from the RTC
  t = RTC.get(); //Gets the current time of the RTC
  RTC.setAlarm(ALM1_MATCH_MINUTES , 0, minute(t) + time_interval, 0, 0); // Setting alarm 1 to go off 5 minutes from now
  // clear the alarm flag
  RTC.alarm(ALARM_1);
  // configure the INT/SQW pin for "interrupt" operation (disable square wave output)
  RTC.squareWave(SQWAVE_NONE);
  // enable interrupt output for Alarm 1
  RTC.alarmInterrupt(ALARM_1, true);

  ///----------------
}

void loop() {
  delay(1000);//wait 5 seconds before going to sleep. In real senairio keep this as small as posible
  Going_To_Sleep();
}

//---------------SLEEP FXN-------------------
void Going_To_Sleep() {
  sleep_enable();                                     //Enabling sleep mode
  attachInterrupt(0, wakeUp, LOW);                    //attaching a interrupt to pin d2
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);                //Setting the sleep mode, in our case full sleep
  digitalWrite(LED_BUILTIN, LOW);                     //turning LED off
  time_t t;                                           // creates temp time variable
  t = RTC.get();                                      //gets current time from rtc
  Serial.println("Sleep  Time: " + String(hour(t)) + ":" + String(minute(t)) + ":" + String(second(t))); //prints time stamp on serial monitor
  delay(1000);                                        //wait a second to allow the led to be turned off before going to sleep
  sleep_cpu();                                        //activating sleep mode
  Serial.println("Just woke up!");//next line of code executed after the interrupt
  digitalWrite(LED_BUILTIN, HIGH);                    //turning LED on
  uSonic();                                           //includes real-time, data, and file saving.
  t = RTC.get();
  Serial.println("WakeUp Time: " + String(hour(t)) + ":" + String(minute(t)) + ":" + String(second(t))); //Prints time stamp
  //Set New Alarm
  RTC.setAlarm(ALM1_MATCH_MINUTES , 0, minute(t) + time_interval, 0, 0);

  // clear the alarm flag
  RTC.alarm(ALARM_1);
}

//-----------------WAKE UP FXN-----------------
void wakeUp() {
  Serial.println("Interrrupt Fired");//Print message to serial monitor
  sleep_disable();                                    //Disable sleep mode
  detachInterrupt(0);                                 //Removes the interrupt from pin 2;
}

void uSonic() {
  //------------GET REAL TIME FXN-------------
  String dataString = "";
  String dTime = "";
  DateTime now = rtc.now();

  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.print("\t");

  //--------------GET DISTANCE FXN---------------
  long duration, inches, cm;
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(pingPin, LOW);
  pinMode(echoPin, INPUT);
  duration = pulseIn(echoPin, HIGH);
  cm = microsecondsToCentimeters(duration);
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();

  //--------------FILE SAVING--------------------
  File dataFile = SD.open(fname, FILE_WRITE);
  if (dataFile) {
    dataFile.print(now.year(), DEC);
    dataFile.print('/');
    dataFile.print(now.month(), DEC);
    dataFile.print('/');
    dataFile.print(now.day(), DEC);
    dataFile.print(" ");
    dataFile.print(" ");
    dataFile.print(now.hour(), DEC);
    dataFile.print(':');
    dataFile.print(now.minute(), DEC);
    dataFile.print(':');
    dataFile.print(now.second(), DEC);
    dataFile.print("\t");
    dataFile.println(cm);
    dataFile.close();
  }
  else {
    Serial.print("Error opening");
    Serial.print(fname);
  }
}

//--------------CONVERT ms TO cm---------------
long microsecondsToCentimeters(long microseconds) {
  return microseconds / 28 / 2;
}

You cannot put any Serial instruction in ISR routine.

  RTC.setAlarm(ALM1_MATCH_MINUTES , 0, minute(t) + time_interval, 0, 0);

If the time is 00:59:00 the above calculation sets the alarm time to 00:60:00 which is no valid time, the library won't detect that.

Right!!!

Use ALM1_MATCH_SECONDS against zero. When seconds are zero (every minute), the alarm firew. You have to wait to the next second instead the alarm will fire again.

@pylon and @zoomx,

We changed the code instead to match the time when seconds = 0 and it worked! Thank you so much!

pylon:

  RTC.setAlarm(ALM1_MATCH_MINUTES , 0, minute(t) + time_interval, 0, 0);

If the time is 00:59:00 the above calculation sets the alarm time to 00:60:00 which is no valid time, the library won't detect that.

Hello! I have exactly the same problem that program Loop ends 00:59:00. I would like to fire the code every 15 minutes. Maybe adding % 60 would remove the problem, like this:

const int time_interval = 15;
RTC.setAlarm(ALM1_MATCH_MINUTES, 0, (minute(t) + time_interval) % 60, 0, 0);

Depending on your needs this may be fine. Did you try it?

Yes, sorry for not replying here...
Got this working:

sum_time = minute(t)+time_interval;

if (sum_time >= 59) {
sum_time = sum_time - 60;
}
else {
sum_time = sum_time;
}

RTC.setAlarm(ALM1_MATCH_MINUTES , 0, sum_time, 0, 0);

Thank you for your previous explanation about 00:60:00 being not valid time.