I use Arduino MKR1010, and I want to capture the sensor's data every second and assign the timestamp. I use the RTCZero and NTP libraries. Once the Arduino starts, it requests the timestamp from an NTP server (pool.ntp.org), then it converts it to epoch time and finally feeds the RTC with that epoch time.
void RTC_init(void)
{
unsigned long epochTime = 0; //variable to store the UNIX time
sendNTPpacket(NTP_SERVER, NTP_PACKET_SIZE, packetBuffer);
delay(1000); // wait to receive reply from the NTP server. If you ommit this delay, then there is no time for the NTP server to respond
epochTime = UDP_parseData(NTP_PACKET_SIZE, packetBuffer); // Unix Time Stamp acquisition
rtc.setEpoch(epochTime); // provide the epoch time to RTC
}
I have a non-blocking timer based on millis() function that expires every 1s to poll the sensor and capture the epoch time from the RTC.
My problem is that RTC skips 1s occasionally, as you can see from the picture below. I do not believe that this is due to RTC resolution and drifts. Could this be related to RTC roundings? Does anyone have experience on that issue? Any workaround solution?
Since the oscillator that runs millis() timing is independent of (and asynchronous to), the oscillator that runs the RTC, I'm thinking there's still a chance you could occasionally observe a reading with an increment of 0 or 2.
I hope the OP takes note of that, because it's absolutely correct - sampling a one-second signal every second will experience doubles or noughts every so often unless the two timebases are exactly synchronised.
@UKHeliBob's solution is how it should be done, of course.
Seems like a lot of thrashing around on the I2C bus to read the RTC 1000 times / second. Don't many RTCs have the option for a 1Hz square wave output?
If so, I'd poll it in loop() for the rising or falling edge (i.e. State Change). I'd also maintain an int32_t variable whose value was set to Epoch time when first obtained. Then increment it every second as the RTC 1Hz edge is detected.
EDIT:
OK, my bad. I just looked up the RTCZero library. It's for accessing the processor's internal RTC. My comments above don't apply.
I am confused, @UKHeliBob suggests reading the RTC frequently and taking action based on the RTC rate of change (e.g., 1s). Am I doing something wrong?
Please, guys if you have any working example, I would appreciate it.
I don't see any reason to read the clock at a high rate. I see that you found that the problem was blocking from other code. Once that is resolved, millis should do what you need. If blocking remains, reading the RTC won't help you.
The problem is the RTC running asynchronously to the oscillator that times the CPU and millis(). So, one second as timed by millis() will be different than one second as timed by the RTC. So, if you measure one second with the former, the latter will occasionally increment by 0 or 2 rather than 1 second during the same period.
I agree that's a good option. But, beware the callback will be running in interrupt context. Best to just set a volatile flag in the callback that will be picked up (and cleared) in loop() where any heavy lifting should be done.