/*********************************************************************** 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 #include // 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); }