Using the DS3231 Real Time Clock alarm with the Adafruit RTClib library

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:
setAlarm1(DateTime, alarm_mode)
setAlarm2(DateTime, alarm_mode)

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:
now + TimeSpan:now + TimeSpan(days, hours, minutes, seconds)

Using unixtime:
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.

Examples

Set to an explicit time

setAlarm1(DateTime(2020, 6, 25, 15, 34, 0), DS3231_A1_Hour)

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.

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.

setAlarm1(now + TimeSpan(0, 0, 0, 10), DS3231_A1_Second)
setAlarm1(now.unixtime() + 10, DS3231_A1_Second)

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.

Using alarmFired

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.

Examples

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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s