DS3231 and RTClibExtended.h: alarm performance issue

The purpose of alarms in this case is to wake up a microcontroller every 20 minutes at 00, 20 and 40 minutes past the hour.

In the setup the following is used:

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

..and in the routine right after every wake-up:

RTC.setAlarm(ALM1_MATCH_MINUTES, 0, ((now.minute()+20)%60), 0, 0);

So far all works well: every wake up is at 0 seconds and 0, or 20 or 40 minutes.

But to avoid having to wait a full hour in the case when the system is started at a few minutes past the hour a condition is inserted in the code for the alarm in the setup:

RTC.setAlarm(ALM1_MATCH_MINUTES, 0, (0 || 20 || 40), 0, 0);

However the issue here is that even with this code the system does not wake up until the 0 minute at the hour is reached. And instead of starting at 0, 20 and 40 minutes, it starts at 1, 21 and 41 minutes.

To test further the following was tried in the setup:

RTC.setAlarm(ALM1_MATCH_SECONDS, (0 || 20 || 40), 0, 0, 0);

Here the alarm starts at whatever the next seconds it is closest at, so works perfectly as expected! And this every time at either 0, 20 and 40 minutes past the hour.

Then the following was tried in the setup:

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

Again this works fine and the system wakes up at 30 seconds past 0 minutes on the hour.

So it seems as if the ALM1_MATCH_SECONDS does work well with conditions in the setup phase. And the ALM1_MATCH_MINUTES only works properly whan actual integers are used; as soon as OR functions are used for the setting of the minutes, odd behaviour results (when applied in the setup phase).

What is the reason?

And how can this be corrected?

0 || 20 || 40

is a logical expression that evaluates to true. Or 1, which explains everything you observed.

I don't think you can set multiple watch minute alarms in any manner like you are attempting. Certainly not with logical or.

a7

alto777:
0 || 20 || 40

is a logical expression that evaluates to true. Or 1, which explains everything you observed.

I don't think you can set multiple watch minute alarms in any manner like you are attempting. Certainly not with logical or.

a7

Fair enough. Yet this works when using the ALM1_MATCH_SECONDS function?!

And how should I program the ALM1_MATCH_MINUTES to get the wake-up at either 0 or 20 or at 40 minutes?

When the program first starts, set the wakeup for the next 20-minute mark in the FUTURE. For example, if the time at start up is 33 minutes after the hour, set the first wakeup for 40 minutes after the hour. Then every time you wake up, set the new wake-up time to the NEXT 20-minute mark.

You may also consider adding a little buffer in case you start up very close to a wake-up time. For example, if the program starts up and the current time is: 09:19:59, then maybe you want to set the first wake-up at 09:40:00 instead of 09:20:00.

Hi gfvalvo, I presume you mean to set this time manually?

I am thinking about some function that does this automatically, I know this is maybe more of a bother than it is worth?

Thought you had an RTC, doesn't your program KNOW what time it is when it starts?

Yes, there is an RTC DS3231; but now I am confused: how do I get from the program knowing what the time is to get it to not having to wait for the 0 minutes past the hour before starting with the wake-ups?
I'll have to give this a good thinking but I am afraid my mind is of on the wrong path :o

Unless I completely misunderstand what you’re trying to do .......

Your setup() function runs when the system first starts up. In there you can read the current time from the RTC. Then, you set the alarm for the FIRST wake-up using the method of Reply #3. Then you do whatever else you have to do during setup(). Then you go to sleep.

Best I can come up with given that you didn’t post complete code for your application.

I said that 40 || 20 || 0 evaluating to 1 explains everything, but it does not explain your assertion

Quote:

RTC.setAlarm(ALM1_MATCH_MINUTES, 0, (0 || 20 || 40), 0, 0);

However the issue here is that even with this code the system does not wake up until the 0 minute at the hour is reached. And instead of starting at 0, 20 and 40 minutes, it starts at 1, 21 and 41 minutes.

End Quote.

You said the same thing happened minutes or seconds?

Perhaps you have moved on, but are you sure this is what you saw? By examination of the library code, 40 || 20 || 0, equal to 1 (confirmed with a small sketch) and passed as a byte should have given, in seconds case or minutes case, only one alarm per 60 at precisely 1 second or minute.

Just want to ensure the integrity of the empirical process!

a7

alto777:
I said that 40 || 20 || 0 evaluating to 1 explains everything, but it does not explain your assertion

Quote:

RTC.setAlarm(ALM1_MATCH_MINUTES, 0, (0 || 20 || 40), 0, 0);

However the issue here is that even with this code the system does not wake up until the 0 minute at the hour is reached. And instead of starting at 0, 20 and 40 minutes, it starts at 1, 21 and 41 minutes.

End Quote.

You said the same thing happened minutes or seconds?

Perhaps you have moved on, but are you sure this is what you saw? By examination of the library code, 40 || 20 || 0, equal to 1 (confirmed with a small sketch) and passed as a byte should have given, in seconds case or minutes case, only one alarm per 60 at precisely 1 second or minute.

Just want to ensure the integrity of the empirical process!

a7

Hi alto777, you are correct: the OR function just returns a one, with subsequent results. Thank you for giving me that insight!

gfvalvo:
Unless I completely misunderstand what you’re trying to do .......

Your setup() function runs when the system first starts up. In there you can read the current time from the RTC. Then, you set the alarm for the FIRST wake-up using the method of Reply #3. Then you do whatever else you have to do during setup(). Then you go to sleep.

Best I can come up with given that you didn’t post complete code for your application.

Hi gfvalvo, thank you for your reply; I am just not sure if you mean I have to set the time manually in the setup function for the alarm.

In the setup I can read the actual current time: DateTime = RTC.now();
But from there to get the setup to come up with a value useable in the alarm setup so that the system wakes from sleep within the next 20 minutes instead of having to wait until the minutes value turns to 0, I am not so sure about.

No, not manually. Your code in setup() knows the current time. So, it can simply determine the time of the FIRST wake-up event.

For example, if the application starts running and the RTC says it’s 09:32:47, then your code will compute the FIRST wake-up time as 09:40:00 and provides that info to REC.setAlarm().

gfvalvo:
No, not manually. Your code in setup() knows the current time. So, it can simply determine the time of the FIRST wake-up event.

For example, if the application starts running and the RTC says it’s 09:32:47, then your code will compute the FIRST wake-up time as 09:40:00 and provides that info to REC.setAlarm().

ok, so this might then be done by a if condition: if now.minute < 40 then set minute at 40 etc..

((((now.minute()/20)+1)*20)%60)

Remember that, when using / (divide) on two ints, the result will also be an int.
Also remember that, in such a situation, any rounding is down.

19 / 20 will give 0

20 / 20 will give 1
21 / 20 will also give 1
39 / 20 will also give 1

40 / 20 will give 2

Yes ("if condition"), or you could just compute it:

nowMinutes = <read the RTC clock> however you read the clock

startMinutes = nowMinutes + 23;                  /* schedule first alarm */

startMinutes = ((startMinutes / 20) * 20) % 60;  /* on a pretty soon 20 minute boundary */

I think. Don't send this to the Moon without verifying.

BTW - I used an online C interpreter to develop that arithmetic, way faster than flashing my UNO and Serial printing. Especially if you are real-time testing, even with seconds as a minutes surrogate!

I am not proud of how much screwing around with % it took, but I say this is the right track.

"if" statements however offensive to the purist in me (!) may be a better clearer way to express and accomplish your intent.

there are others. It is often nice to get the heart of an algorithm functioning apart from all kindsa stuff you have to deal with when running the code on the UNO or whatever little computer you are flashing to.

a7

odometer:

((((now.minute()/20)+1)*20)%60)

Haha, good. It also looks like you just confidently wrote that. Nice.

Just add the "breathing room" to now.minute(), in my case 3 minutes! I can't say it is a big deal, this is gfvalvo's "little buffer".

a7

alto777:
Haha, good. It also looks like you just confidently wrote that. Nice.

Just add the "breathing room" to now.minute(), in my case 3 minutes! I can't say it is a big deal, this is gfvalvo's "little buffer".

a7

Thank you so much all of you: gfvalvo, alto777 and odometer: this is exactly what I had been looking for!!

Sorry for the late reply: at the time the Arduino forum servers were out and then I had left town for work for several weeks.