Scheduling reading and sending data in certain hour minutes on Mbili

Dear forum users.
I tried to modify the following example sketch

http://support.sodaq.com/adding-a-gprs-connection-to-upload-data/

In the above sketch on a power boot of the Mbili you get a first reading and sending of data, and after that you get the reading and sending every READ_DELAY since a power boot…

What I tried to do is to schedule a first interval of reading and sending so that is done in a certain minutes of a hour, and after a first sending to repate the reading and sending every READ_DELAY (eg. if now is 21:34, and I defined to send a data at a 0 minutes of a hour, and to repeat the sending every 3600 ms, I wanted to send a first data at 22:00, and after that at 23:00 and every repetitively every hour at 0 minutes).

I tried to compare the actual minutes

rtc.now().minute();

to the defined minutes of sending. Then I set the new variable “FIRST_READ_DELAY”, and configured the timer by the flowing line

timer.every("FIRST_READ_DELAY, takeReading);

This line is executed only once (before a first sending), and after that I re-configure the timer by the following line

timer.every("READ_DELAY, takeReading);

The problem is that the program don’t work as I wanted and after a first reading and sending instead to send every READ_DELAY the Mbili is sending randomly every minute to 45 seconds…

What I’m doing wrong? What is the easiest way to achieve what I wanted? Do you have any example so I can get a clue? Any help is appreciated.

Best regards, Paolo

The RTCTimer::every() method has an optional third parameter. This parameter is the number of executions/repetitions and defaults to -1 which signifies infinite. In your example, I believe you are actually scheduling two different calls to takeReading one at an interval of FIRST_READ_DELAY and the other at an interval of READ_DELAY.

To correct this, you should pass a third parameter of 1 to the first call to RTCTimer::every(). This will delete the scheduled call after it is called once. You can then reschedule it after that first execution, to run infinitely with an interval of READ_DELAY.

Dear Gabriel,
thank you for a replay and for a hint.
I managed to do what I wanted after changing a code as you suggested, but in addition I added a timer.update(); command, because without them I didn’t had a correct infinitely timer schedule.

BTW, can you explain me what is a purpose of a command rtc.clearINTStatus();
Best regards, Paolo

Hi Paolo,

If you setup the RTC to provide a periodic interrupt [EverySecond, EveryMinute, EveryHour], the DS3231 will generate an interrupt with that period. Providing solder jumper SJ8 is closed, the DS3231 will pull the A7 pin low at the specified interval. You can capture this interrupt using a pin change interrupt on A7, with A7 setup as input pullup.

You must call rtc.clearINTStatus() after each interrupt, this clears a flag on the RTC chip. If you don’t clear this flag, the next interrupt will not be generated even after the specified time period has elapsed.

If you are using this interrupt to wake the board from sleep, you probably want to clear this flag immediately before entering sleep to ensure the next wake interrupt is generated.

Dear Gabriel,
thank you for the explanation.

Paolo

Hi Gabriel,

Sorry for bringing up old topic. I did what you suggested (shorted SJ8) and now I’m getting interrupts every second as expected. Snippets from the code (some lines are skipped):

#define RTC_PIN A7

void setup() {
   rtc.begin();
   PcInt::attachInterrupt(RTC_PIN, INT0_ISR);
   rtc.enableInterrupts(EverySecond);
}

void INT0_ISR() {
   Serial.println("Interrupt detected");
}

void loop() {
   rtc.clearINTStatus();
}

How can I tell RTC to generate interrupt not EverySecond, EveryMinute or EveryHour but any time I want, e.g. every 30sec, 15min or 6 hours?

I see there are two methods inside Sodaq_DS3231 - one that accepts these three constans as inputs and one that accepts exact time (hh, mm, ss):

void enableInterrupts(uint8_t periodicity);
void enableInterrupts(uint8_t hh24, uint8_t mm,uint8_t ss);

I need the first one to accept any number I want, not only these three constants:

// These are the constants for periodicity of enableInterrupts() below.
#define EverySecond     0x01
#define EveryMinute     0x02
#define EveryHour       0x03

Is the right way to do it to ignore certain amount of interrupts until the desired sleep time is met? E.g. if I want to be in power down sleep for 30sec I should ignore 29 “EverySecond” interrupts and just re-enter sleep for another second? Or is there a simpler way to do it?

Sorry if the question is too novice, I’m a beginner in SW/HW dev. all together.

Thanks.

The RTC (and library) supports regular interrupts at intervals of every second, minute or hour.

Additionally, you can create a once per day interrupt using the second form of the enableInterrupts() method.

If you want to create a regular interrupt with a custom period, it will require a few more steps. Effectively, you will need to use the daily interrupt method and reschedule the alarm interrupt during every wake cycle.

You may find the DateTime class (found within that library) useful as you can convert a specific date and time into a quantity of seconds (Unix Epoch or 2k Epoch). You can then add a certain number of seconds to that value and then convert it back into a time and date.