101 lines
3.9 KiB
C++
101 lines
3.9 KiB
C++
/***********************************************************************
|
|
|
|
Combining RTClib with the avr-libc timing functions
|
|
===================================================
|
|
|
|
The standard way of getting the current time and date with RTClib is to
|
|
call the now() method of the appropriate RTC class. This, however, is
|
|
somewhat slow, as it involves communicating with the RTC through the I2C
|
|
bus. An alternative, more lightweight method involves configuring the
|
|
RTC to deliver one pulse per second to an interrupt pin, and counting
|
|
the seconds in the interrupt handler. The timekeeping is then entirely
|
|
handled in the Arduino, with no I2C communication with the RTC other
|
|
than during the initialization phase.
|
|
|
|
On AVR-based Arduinos (Uno, Nano, Micro, ...), the Arduino core library
|
|
is built on top of avr-libc, which is an implementation of the standard
|
|
C library for the AVR platform. This library provides the standard C
|
|
functions for handling time:[1] time(), gmtime(), mktime(), etc. The
|
|
time() function is normally used to retrieve the current time from the
|
|
operating system, but since we have no operating system, the avr-libc
|
|
provides its own non-standard functions for implementing a time source:
|
|
|
|
- set_system_time() initializes the library's idea of the current time
|
|
- system_tick() steps the system time by one second.
|
|
|
|
This sketch demonstrates how to combine RTClib and avr-libc in order to
|
|
handle the timekeeping entirely on the Arduino from an interrupt
|
|
delivered by the RTC:
|
|
|
|
- RTClib is used to configure the RTC and retrieve the initial time
|
|
- avr-libc is used for regular timekeeping
|
|
|
|
This sketch only works on AVR-based Arduinos, as it relies on
|
|
non-standard functions provided by avr-libc.
|
|
|
|
[1] https://www.nongnu.org/avr-libc/user-manual/group__avr__time.html
|
|
|
|
***********************************************************************/
|
|
|
|
#include <RTClib.h>
|
|
#include <time.h> // standard C timing functions
|
|
|
|
// Pin receiving the one-pulse-per-second signal from the RTC.
|
|
// This should be an interrupt-capable pin.
|
|
const uint8_t pin1pps = 2;
|
|
|
|
// We will use the PCF8523 RTC, which has the handy "Second Timer".
|
|
// Other RTCs could be used with their "square wave" output configured
|
|
// to 1 Hz.
|
|
RTC_PCF8523 rtc;
|
|
|
|
void setup() {
|
|
|
|
// Initialize the serial port.
|
|
Serial.begin(57600);
|
|
while (!Serial); // wait for serial port to connect. Needed for native USB
|
|
|
|
// Initialize the RTC.
|
|
if (! rtc.begin()) {
|
|
Serial.println("Couldn't find RTC");
|
|
Serial.flush();
|
|
while (1) delay(10);
|
|
}
|
|
if (!rtc.initialized() || rtc.lostPower()) {
|
|
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
|
}
|
|
rtc.deconfigureAllTimers(); // undo previous configuration, if any
|
|
|
|
// Initialize the system time from the RTC time. Both avr-libc and
|
|
// DateTime::secondstime() use the start of year 2000 as their
|
|
// reference "epoch".
|
|
set_system_time(rtc.now().secondstime());
|
|
|
|
// Keep the time in sync using the one-pulse-per-second output of the
|
|
// RTC as an interrupt source and calling system_tick() from the
|
|
// interrupt service routine.
|
|
pinMode(pin1pps, INPUT_PULLUP);
|
|
rtc.enableSecondTimer();
|
|
attachInterrupt(digitalPinToInterrupt(pin1pps), system_tick, FALLING);
|
|
}
|
|
|
|
void loop() {
|
|
|
|
// From here on, we only use the standard C timing functions.
|
|
// time() returns the current time as a single number of type time_t,
|
|
// this is the number of seconds elapsed since a reference "epoch".
|
|
time_t now = time(nullptr);
|
|
|
|
// gmtime() converts the time to a broken-down form (year, month...)
|
|
// similar to the DateTime class. Unlike localtime(), it doesn't
|
|
// attempt timezone conversions.
|
|
struct tm *broken_down_time = gmtime(&now);
|
|
|
|
// asctime() returns a textual representation of the date and time as
|
|
// a C string (pointer to a character array). The format is similar to
|
|
// the DateTime::toString() format "DDD MMM DD hh:mm:ss YYYY".
|
|
Serial.println(asctime(broken_down_time));
|
|
|
|
delay(1000);
|
|
}
|