I love the DS3231 RTC module and have used it in a couple of projects without a library using code based on Ralph Bacon’s example. It worked well, but I wanted to use the alarm and working out how to do that was a step too far for me. There doesn’t seem to be a shortage of libraries and I found it challenging to choose one.
I tried the Adafruit RTClib library which I liked but the documentation I looked at didn’t mention support for the alarm, but I found this closed issue in the libraries Github repository Add support for Alarm on DS3231 #94, so it seems it does have support for it. After many hours of twiddling and tweaking here are some notes and example from my experiments of what I believe is correct info. I’m not an expert so let me know if you believe any of it is incorrect or can be improved.
Setting the alarm
This is what I had most trouble with. There are two alarms. The commands to set the alarms time are:
The alarms can be set to a specific time using DateTime or to a set amount from the current time using TimeSpan. Some formats I used are:
For a specific time use DateTime:
DateTime(Year, Month, Day, Hour, Minute, Second)
For a number of seconds, minutes, hours, etc from the current time using TimeSpan:
now + TimeSpan(days, hours, minutes, seconds)
now.unixtime() + seconds
The second part of setAlarm is alarm_mode. This sets what needs to match for the alarm to trigger. The modes are:
Alarm modes for alarm 1 DS3231_A1_PerSecond Once per second DS3231_A1_Second When seconds match DS3231_A1_Minute When minutes and seconds match DS3231_A1_Hour When hours, minutes, and seconds match DS3231_A1_Date When date, hours, minutes, and seconds match (day of month) DS3231_A1_Day When day, hours, minutes, and seconds match (day of week) Alarm modes for alarm 2 DS3231_A2_PerMinute Once per minute (00 seconds of every minute) DS3231_A2_Minute When minutes and seconds match DS3231_A2_Hour When hours, minutes, and seconds match DS3231_A2_Date When date, hours, minutes, and seconds match DS3231_A2_Day When day, hours, minutes, and seconds match
Alarm 2 is slightly different in that it can’t be set to trigger on anything smaller other than 00 seconds, that is triggering on the minute is the smallest amount.
The trick for me was working out what how the relationship between time and mode. If a suitable mode is not chosen it can (and did) result in unexpected results. For example setting the time for 7:00am the next day, but choosing DS3231_A1_Minute will result in the alarm triggering on the next hour after setting as only minutes and seconds are being used in the mode. Hours and days are ignored.
Set to an explicit time
The alarm will trigger when seconds, minutes and hours match, resulting in triggering once per day, every day at (15:34:00). The date, month and year are all ignored.
rtc.setAlarm1(DateTime(2020, 6, 25, 15, 34, 0), DS3231_A1_Hour)
When seconds at zero, that is every minute
rtc.setAlarm1(DateTime(0, 0, 0, 0, 0, 0), DS3231_A1_Second)
When the minutes and seconds are at zero, that is, every hour
rtc.setAlarm1(DateTime(0, 0, 0, 0, 0, 0), DS3231_A1_Minute)
When the minutes are at 1 and seconds are at 10, that is 1 minute and 10 seconds past the hour
rtc.setAlarm1(DateTime(0, 0, 0, 0, 1, 10), DS3231_A1_Minute)
At 10:00 o’clock every day
rtc.setAlarm1(DateTime(0, 0, 0, 10, 0, 0), DS3231_A1_Hour)
At 10:18 every day
rtc.setAlarm1(DateTime(0, 0, 0, 10, 18, 0), DS3231_A1_Hour)
Using TimeSpan or unixtime to set to an amount from the current time
The current time needs to be called before setting the remaining examples as it is needed to calculate the end time. These examples set the alarm to 10 seconds from the current time.
rtc.setAlarm1(setAlarm1(rtc.now + TimeSpan(0, 0, 0, 10), DS3231_A1_Second)
rtc.setAlarm1(rtc.now() + TimeSpan(10), DS3231_A1_Second)
rtc.setAlarm1(rtc.now.unixtime() + 10, DS3231_A1_Second)
In 1 minutes time from now
rtc.setAlarm1(rtc.now() + TimeSpan(0, 0, 1, 0), DS3231_A1_Minute)
In 2 minutes and 10 seconds time from now
rtc.setAlarm1(rtc.now() + TimeSpan(0, 0, 2, 10), DS3231_A1_Minute)
In 1 hour and 5 minutes time from now
rtc.setAlarm1(rtc.now() + TimeSpan(0, 1, 5, 0), DS3231_A1_Hour)
Monitoring the alarm
So now it can be set, how do we know it has activated? There seems to be two ways to do this.
alarmFired() will return true if the alarm is firing and will continue to do so for at least some minutes(?) unless it is cleared. However, while the alarm can be cleared, it doesn’t appear that it can be disabled, so it will fire again when the alarm setting criteria is met again. So that needs to be considered in code. Also, I could only see how to do this by polling alarmFired, which if true looks like this method rules it out for use with sleep modes that I want to use.
Using the SQW pin
This SQW pin can be used to output square waves. It can also be used by the alarm. Its output goes low when the alarm is triggered. This opens up the possibility of using it for use with an interrupt so can be used to wake an Arduino from sleep.
Update 9 July 2022
Since I wrote this post later versions of RTClib have included an example sketch for the alarm. That sketch is more sophisticated than my examples so you should check it out.
I have added some more examples above for formatting setting the alarm time.
I have also added another sketch to my Github repository DS3231-_RTClib-Adafruit-Alarm-SetTest. It is based on the example that now comes with the library. I made it just so that I could test setAlarm times. It monitors the SQW pin and simply displays the current time and then when the alarm is triggered it displays the time it was triggered.
My Github repository has a few examples:
Setting an alarm and polling the SQW pin – DS3231-RTClib-Adafruit-Alarm-Poll-SQW.ino https://github.com/garrysblog/DS3231-Alarm-With-Adafruit-RTClib-Library/blob/master/DS3231-RTClib-Adafruit-Alarm-Poll-SQW/DS3231-RTClib-Adafruit-Alarm-Poll-SQW.ino
Setting an alarm and polling using alarmFired – DS3231-RTClib-Adafruit-Alarm-Poll-alarmFired.ino https://github.com/garrysblog/DS3231-Alarm-With-Adafruit-RTClib-Library/blob/master/DS3231-RTClib-Adafruit-Alarm-Poll-alarmFired/DS3231-RTClib-Adafruit-Alarm-Poll-alarmFired.ino
Sending the Arduino to sleep and waking it using the alarm and SQW pin – DS3231-_RTClib-Adafruit-Alarm-Sleep.ino https://github.com/garrysblog/DS3231-Alarm-With-Adafruit-RTClib-Library/blob/master/DS3231-_RTClib-Adafruit-Alarm-Sleep/DS3231-_RTClib-Adafruit-Alarm-Sleep.ino
I hope this is useful and doesn’t have too much incorrect info. Let me know your feedback.