Using DS3231 Alarms

I am trying to develop an Arduino based alarm using the DS3231.
I found this code on the web, not sure location as not commented.
The program works fine using the A1 alarm, but I figured out that by renaming the alarms and flags I could use tboth alarms, so I called alarm 1= a1 and alarm 2= a2 and changed the corresponding flags flags1 and flags2.
When the time gets to the values set for alarm1 it displays the message that the alarm has been triggered, but does not make INT/SQW go LOW. When it reaches the alarm2 time, it does not do anything.

I guess that its something to do with the if statements, but as I am still learning, I am not clever enough to work out how to correct this.

Can anyone help?
Here is the Code:

// during an alarm the INT pin of the RTC is pulled low
//
// this is handy for minimizing power consumption for sensor-like devices, 
// since they can be started up by this pin on given time intervals.

#include <Wire.h>
#include "ds3231.h"

#define BUFF_MAX 256

// time when to wake up
uint8_t wake1_HOUR = 18;
uint8_t wake1_MINUTE = 03;
uint8_t wake1_SECOND = 00;

uint8_t wake2_HOUR = 18;
uint8_t wake2_MINUTE = 04;


// how often to refresh the info on stdout (ms)
unsigned long prev = 5000, interval = 5000;

void set_alarm(void)
{

    // flags define what calendar component to be checked against the current time in order
    // to trigger the alarm - see datasheet
    // A1M1 (seconds) (0 to enable, 1 to disable)
    // A1M2 (minutes) (0 to enable, 1 to disable)
    // A1M3 (hour)    (0 to enable, 1 to disable) 
    // A1M4 (day)     (0 to enable, 1 to disable)
    // DY/DT          (dayofweek == 1/dayofmonth == 0)
    uint8_t flags1[5] = { 0, 0, 0, 1, 1 };
    
    // A2M1 (seconds) (0 to enable, 1 to disable)
    // A2M2 (minutes) (0 to enable, 1 to disable)
    // A2M3 (hour)    (0 to enable, 1 to disable) 
    // A2M4 (day)     (0 to enable, 1 to disable)
    // DY/DT          (dayofweek == 1/dayofmonth == 0)
    uint8_t flags2[5] = { 1, 0, 0, 0, 1 };
    
    // set Alarm1
    DS3231_set_a1(wake1_SECOND, wake1_MINUTE, wake1_HOUR, 0, flags1);

    // activate Alarm1
    DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);
    
     // set Alarm2
    DS3231_set_a2(wake2_MINUTE, wake2_HOUR, 0, flags2);

    // activate Alarm
    DS3231_set_creg(DS3231_INTCN | DS3231_A2IE);
}

void setup()
{
    Serial.begin(9600);
    Wire.begin();
    DS3231_init(DS3231_INTCN);
    DS3231_clear_a1f();
    set_alarm();
}

void loop()
{
    char buff[BUFF_MAX];
    unsigned long now = millis();
    struct ts t;

    // once a while show what is going on
    if ((now - prev > interval) && (Serial.available() <= 0)) {
        DS3231_get(&t);

        // display current time
        snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d", t.year,
             t.mon, t.mday, t.hour, t.min, t.sec);
        Serial.println(buff);

        // display a1 debug info
        DS3231_get_a1(&buff[0], 59);
        Serial.println(buff);

        if (DS3231_triggered_a1()) {
            // INT/SQW has been pulled low
            Serial.println(" -> alarm1 has been triggered");
            // clear a1 alarm flag and let INT go into hi-z
            //DS3231_clear_a1f();
        }
        
        if (DS3231_triggered_a2()) {
            // INT/SQW has been pulled low
            Serial.println(" -> alarm has been triggered");
            // clear a1 alarm flag and let INT go into hi-z
            DS3231_clear_a1f();
        }
        
        prev = now;
    }
}

I have found a way of keeping the SQW pin low for a period of time by adding a delay, but that has implications!
The serial print has started to onnly refresh every 60 secs.
I want to make the relaypin go high when it loops through the if statement that clears the alarm on SQWpin, but that does not work. I put the digitalWrite(relaypin, HIGH) before the delay(60000) and put digitalWrite(relaypin, LOW) after the alarm1 is cleared.
This did not work as I thought it would, the relayPin stayed LOW through the ON period I set.

Asyou will notice I have at this stage abandoned the use of alarm2, but I would like to get that working so that I can have 2 periods where I can operate a relay.

Heris the code:

// during an alarm the INT pin of the RTC is pulled low
//SDA - pin A4
// SCL - pin A5
// this is handy for minimizing power consumption for sensor-like devices, 
// since they can be started up by this pin on given time intervals.

#include <Wire.h>
#include "ds3231.h"

#define BUFF_MAX 256
int relaypin = 10;
int SQWpin = 8;
// time when to wake up
uint8_t wake1_HOUR = 17;
uint8_t wake1_MINUTE = 02;
uint8_t wake1_SECOND = 00;

// how often to refresh the info on stdout (ms)
unsigned long prev = 5000, interval = 5000;

void set_alarm(void)
{

    // flags define what calendar component to be checked against the current time in order
    // to trigger the alarm - see datasheet
    // A1M1 (seconds) (0 to enable, 1 to disable)
    // A1M2 (minutes) (0 to enable, 1 to disable)
    // A1M3 (hour)    (0 to enable, 1 to disable) 
    // A1M4 (day)     (0 to enable, 1 to disable)
    // DY/DT          (dayofweek == 1/dayofmonth == 0)
    uint8_t flags1[5] = { 0, 0, 0, 1, 1 };
    
    // set Alarm1
    DS3231_set_a1(wake1_SECOND, wake1_MINUTE, wake1_HOUR, 0, flags1);

    // activate Alarm1
    DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);
    

}

void setup()
{
    Serial.begin(9600);
    Wire.begin();
    pinMode(SQWpin, INPUT);
    pinMode(relaypin, OUTPUT);
    DS3231_init(DS3231_INTCN);
    DS3231_clear_a1f();
    set_alarm();
}

void loop()
{

    char buff[BUFF_MAX];
    unsigned long now = millis();
    struct ts t;

    // once a while show what is going on
    if ((now - prev > interval) && (Serial.available() <= 0)) {
        DS3231_get(&t);

        // display current time
        snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d", t.year,
             t.mon, t.mday, t.hour, t.min, t.sec);
        Serial.println(buff);

        // display a1 debug info
        DS3231_get_a1(&buff[0], 59);
        Serial.println(buff);

        if (DS3231_triggered_a1()) {
            // INT/SQW has been pulled low
            Serial.println(" -> alarm1 has been triggered");
          digitalWrite(relaypin, HIGH);
        }
            delay(60000);
            // clear a1 alarm flag and let INT go into hi-z
            DS3231_clear_a1f();
          digitalWrite(relaypin, LOW);  
        }
        
       prev = now;
    }

Your help would be appreciated.

You are doing fine! However, the Arduino can't do anything else while it is in delay().

Study the "blink without delay" example that comes with the Arduino IDE to learn how to get around this problem.

Thankyou jremington
Three more things:-

  • The year part displays 1916 intead of 2016. I used a separate program to set the RTC time and that shows 2016! From the DS3231 datasheet, bit 7 of the month register (address = 05h) is used to set the century, so why does this program think it is 1916?
  • How can I use the Alarm 2, for another period later on?
  • How can I enter a new alarm time from the serial port?

Thanking you in anticipation.

Hi
I have been trying a few things to use alarm2.
If I set alarm2 as I explained in the initial post, it sets the alarm for alarm1, but ignores alarm2.
I think the way it is laid out is probabily wrong, but being a beginner I am still strugling with the syntax.
can some point out where I am going wrong?
Here is the modified code:

// during an alarm the INT pin of the RTC is pulled low
//SDA - pin A4
// SCL - pin A5
// this is handy for minimizing power consumption for sensor-like devices, 
// since they can be started up by this pin on given time intervals.

#include <Wire.h>
#include "ds3231.h"

#define BUFF_MAX 256
// time when to wake up
uint8_t wake1_HOUR = 18;
uint8_t wake1_MINUTE = 16;
uint8_t wake1_SECOND = 00;

uint8_t wake2_HOUR = 18;
uint8_t wake2_MINUTE = 20;



 // how often to refresh the info on stdout (ms)
unsigned long prev = 1000, interval = 1000;

int relaypin = 10;
int SQWpin = 8;
// Variables will change :
int relayState = LOW;             // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change :
const long interval1 = 60000;           // interval at which to blink (milliseconds)
void set_alarm(void){
    // flags define what calendar component to be checked against the current time in order
    // to trigger the alarm - see datasheet
    // A1M1 (seconds) (0 to enable, 1 to disable)
    // A1M2 (minutes) (0 to enable, 1 to disable)
    // A1M3 (hour)    (0 to enable, 1 to disable) 
    // A1M4 (day)     (0 to enable, 1 to disable)
    // DY/DT          (dayofweek == 1/dayofmonth == 0)
    uint8_t flags1[5] = { 0, 0, 0, 1, 1 };
    
    uint8_t flags2[5] = { 1, 0, 0, 1, 1 };
    
    // set Alarm1
    DS3231_set_a1(wake1_SECOND, wake1_MINUTE, wake1_HOUR, 0, flags1);

    // activate Alarm1
    DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);
    
    // set Alarm2
    DS3231_set_a2(wake2_MINUTE, wake2_HOUR, 0, flags2);

    // activate Alarm2
    DS3231_set_creg(DS3231_INTCN | DS3231_A2IE);
    
}
void setup() {


    Serial.begin(9600);
    Wire.begin();
    pinMode(SQWpin, INPUT);
    pinMode(relaypin, OUTPUT);
    DS3231_init(DS3231_INTCN);
    DS3231_clear_a1f();
    set_alarm();
}

void loop()
{

    char buff[BUFF_MAX];
    unsigned long now = millis();
    struct ts t;

    // once a while show what is going on
    if ((now - prev > interval) && (Serial.available() <= 0)) {
        DS3231_get(&t);

        // display current time
        snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d", t.year,
             t.mon, t.mday, t.hour, t.min, t.sec);
        Serial.println(buff);

        // display a1 debug info
      //  DS3231_get_a1(&buff[0], 59);
      //  Serial.println(buff);

        if (DS3231_triggered_a1()) {
            // INT/SQW has been pulled low
            Serial.println(" -> alarm1 has been triggered");
          digitalWrite(relaypin, HIGH);
 }
           // check to see if it's time to switch the port; 
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis >= interval1) {
    // save the last time you switched the LED 
    previousMillis = currentMillis;   

    // if the relay is off turn it on and vice-versa:
    if (relayState == LOW)
      relayState = HIGH;
    else
      relayState = LOW;
            // clear a1 alarm flag and let INT go into hi-z
            DS3231_clear_a1f();
          digitalWrite(relaypin, LOW);  
        }
if (DS3231_triggered_a2()) {
            // INT/SQW has been pulled low
            Serial.println(" -> alarm2 has been triggered");
          digitalWrite(relaypin, HIGH);
 }
           // check to see if it's time to switch the port; 

 
  if(currentMillis - previousMillis >= interval1) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (relayState == LOW)
      relayState = HIGH;
    else
      relayState = LOW;
            // clear a1 alarm flag and let INT go into hi-z
            DS3231_clear_a2f();
          digitalWrite(relaypin, LOW);  
        }       
       prev = now;
    }
}

By the way it does compile and run OK.

I have now been able to get Alarm 2 to trigger, but for alarm 1, I set a delay by using the code simular to 'Blink without Delay'.
At first I could only get Alarm 1 to trigger and by studying the datasheet and the header file I found that I was setting too many flags.
Then when it came to Alarm 2 it would say it's triggered one time only, whereas for Alarm 1 it would repeat the message for the period of the delay.
I then thought that the delay code may have been upsetting the second delay period, so I altered all of the variables to have a 1 or 2 suffixing the variable name.
This did not alter anything.
I also observed that the time period was wrong for Alarm 1, it switched off sooner than I had set.
Can anybody see where I am going wrong?
I feel I have nearly solved this problem, but I could do with some help to crack this last problem.
Here is the code so far:

// during an alarm the INT pin of the RTC is pulled low
//SDA - pin A4
// SCL - pin A5
// this is handy for minimizing power consumption for sensor-like devices, 
// since they can be started up by this pin on given time intervals.

#include <Wire.h>
#include "ds3231.h"
#define BUFF_MAX 256
// time when to wake up
uint8_t wake1_HOUR = 17;
uint8_t wake1_MINUTE = 44;
uint8_t wake1_SECOND = 00;

uint8_t wake2_HOUR = 17;
uint8_t wake2_MINUTE = 46;



 // how often to refresh the info on stdout (ms)
unsigned long prev = 1000, interval = 1000;

int relaypin = 10;
int SQWpin = 8;
// Variables will change :
int relayState = LOW;             // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis1 = 0;        // will store last time relay was updated
unsigned long previousMillis2 = 0; 
// constants won't change :
const long interval1 = 60000;           // interval at which to keep relay on for (milliseconds)
const long interval2 = 60000;
void set_alarm(void){
    // flags define what calendar component to be checked against the current time in order
    // to trigger the alarm - see datasheet
    // A1M1 (seconds) (0 to enable, 1 to disable)
    // A1M2 (minutes) (0 to enable, 1 to disable)
    // A1M3 (hour)    (0 to enable, 1 to disable) 
    // A1M4 (day)     (0 to enable, 1 to disable)
    // DY/DT          (dayofweek == 1/dayofmonth == 0)
    uint8_t flags1[5] = { 0, 0, 0, 1, 1 };
    
    // A2M2 (minutes) (0 to enable, 1 to disable)
    // A2M3 (hour)    (0 to enable, 1 to disable) 
    // A2M4 (day)     (0 to enable, 1 to disable) 
    uint8_t flags2[3] = {0, 0, 1};
    
    // set Alarm1
    DS3231_set_a1(wake1_SECOND, wake1_MINUTE, wake1_HOUR, 0, flags1);

    // activate Alarm1
    DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);
    
    // set Alarm2
    DS3231_set_a2(wake2_MINUTE, wake2_HOUR, 0, flags2);

    // activate Alarm2
    DS3231_set_creg(DS3231_INTCN | DS3231_A2IE);
    
}
void setup() {


    Serial.begin(9600);
    Wire.begin();
    pinMode(SQWpin, INPUT);
    pinMode(relaypin, OUTPUT);
    DS3231_init(DS3231_INTCN);
    DS3231_clear_a1f();
    DS3231_clear_a2f();
    set_alarm();
}

void loop()
{

    char buff[BUFF_MAX];
    unsigned long now = millis();
    struct ts t;

    // once a while show what is going on
    if ((now - prev > interval) && (Serial.available() <= 0)) {
        DS3231_get(&t);

        // display current time
        snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d", t.year,
             t.mon, t.mday, t.hour, t.min, t.sec);
        Serial.println(buff);

        // display a1 debug info
      //  DS3231_get_a1(&buff[0], 59);
      //  Serial.println(buff);

        if (DS3231_triggered_a1()) {
            // INT/SQW has been pulled low
            Serial.println(" -> alarm1 has been triggered");
          digitalWrite(relaypin, HIGH);
 
    
           // check to see if it's time to switch the port; 
  unsigned long currentMillis1 = millis();
 
  if(currentMillis1 - previousMillis1 >= interval1) {
    // save the last time you switched the relay 
    previousMillis1 = currentMillis1;   

    // if the relay is off turn it on and vice-versa:
    if (relayState == LOW)
      relayState = HIGH;
    else
      relayState = LOW;
            // clear a1 alarm flag and let INT go into hi-z
            DS3231_clear_a1f();
          digitalWrite(relaypin, LOW);  
        }
        }
if (DS3231_triggered_a2()) {
            // INT/SQW has been pulled low
            Serial.println(" -> alarm2 has been triggered");
          digitalWrite(relaypin, HIGH);
 
           // check to see if it's time to switch the port; 
  unsigned long currentMillis2 = millis();

  if(currentMillis2 - previousMillis2 >= interval2) {
    // save the last time you switched the relay 
    previousMillis2 = currentMillis2;   

    // if the LED is off turn it on and vice-versa:
    if (relayState == LOW)
      relayState = HIGH;
    else
      relayState = LOW;
            // clear a1 alarm flag and let INT go into hi-z
            DS3231_clear_a2f();
          digitalWrite(relaypin, LOW);  
        }
}       
       prev = now;
    }
}

Any help would be greatly appreciated!