├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── githubci.yml ├── .gitignore ├── README.md ├── code-of-conduct.md ├── examples ├── DS3231_alarm │ └── DS3231_alarm.ino ├── customWire_DS3231onSAMD21 │ ├── .metro_m4.test.only │ └── customWire_DS3231onSAMD21.ino ├── datecalc │ └── datecalc.ino ├── ds1307 │ └── ds1307.ino ├── ds1307SqwPin │ └── ds1307SqwPin.ino ├── ds1307nvram │ └── ds1307nvram.ino ├── ds3231 │ └── ds3231.ino ├── interrupts1Hz │ ├── .leonardo.test.only │ ├── .mega2560.test.only │ ├── .uno.test.only │ └── interrupts1Hz.ino ├── pcf8523 │ └── pcf8523.ino ├── pcf8523Countdown │ └── pcf8523Countdown.ino ├── pcf8563 │ └── pcf8563.ino ├── pcf8563_interrupt │ └── pcf8563_interrupt.ino ├── softrtc │ └── softrtc.ino ├── timestamp │ └── timestamp.ino └── toString ├── keywords.txt ├── library.properties ├── license.txt └── src ├── RTC_DS1307.cpp ├── RTC_DS3231.cpp ├── RTC_Micros.cpp ├── RTC_Millis.cpp ├── RTC_PCF8523.cpp ├── RTC_PCF8563.cpp ├── RTClib.cpp └── RTClib.h /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for opening an issue on an Adafruit Arduino library repository. To 2 | improve the speed of resolution please review the following guidelines and 3 | common troubleshooting steps below before creating the issue: 4 | 5 | - **Do not use GitHub issues for troubleshooting projects and issues.** Instead use 6 | the forums at http://forums.adafruit.com to ask questions and troubleshoot why 7 | something isn't working as expected. In many cases the problem is a common issue 8 | that you will more quickly receive help from the forum community. GitHub issues 9 | are meant for known defects in the code. If you don't know if there is a defect 10 | in the code then start with troubleshooting on the forum first. 11 | 12 | - **If following a tutorial or guide be sure you didn't miss a step.** Carefully 13 | check all of the steps and commands to run have been followed. Consult the 14 | forum if you're unsure or have questions about steps in a guide/tutorial. 15 | 16 | - **For Arduino projects check these very common issues to ensure they don't apply**: 17 | 18 | - For uploading sketches or communicating with the board make sure you're using 19 | a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes 20 | very hard to tell the difference between a data and charge cable! Try using the 21 | cable with other devices or swapping to another cable to confirm it is not 22 | the problem. 23 | 24 | - **Be sure you are supplying adequate power to the board.** Check the specs of 25 | your board and plug in an external power supply. In many cases just 26 | plugging a board into your computer is not enough to power it and other 27 | peripherals. 28 | 29 | - **Double check all soldering joints and connections.** Flakey connections 30 | cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. 31 | 32 | - **Ensure you are using an official Arduino or Adafruit board.** We can't 33 | guarantee a clone board will have the same functionality and work as expected 34 | with this code and don't support them. 35 | 36 | If you're sure this issue is a defect in the code and checked the steps above 37 | please fill in the following fields to provide enough troubleshooting information. 38 | You may delete the guideline and text above to just leave the following details: 39 | 40 | - Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** 41 | 42 | - Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO 43 | VERSION HERE** 44 | 45 | - List the steps to reproduce the problem below (if possible attach a sketch or 46 | copy the sketch code in too): **LIST REPRO STEPS BELOW** 47 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for creating a pull request to contribute to Adafruit's GitHub code! 2 | Before you open the request please review the following guidelines and tips to 3 | help it be more easily integrated: 4 | 5 | - **Describe the scope of your change--i.e. what the change does and what parts 6 | of the code were modified.** This will help us understand any risks of integrating 7 | the code. 8 | 9 | - **Describe any known limitations with your change.** For example if the change 10 | doesn't apply to a supported platform of the library please mention it. 11 | 12 | - **Please run any tests or examples that can exercise your modified code.** We 13 | strive to not break users of the code and running tests/examples helps with this 14 | process. 15 | 16 | Thank you again for contributing! We will try to test and integrate the change 17 | as soon as we can, but be aware we have many GitHub repositories to manage and 18 | can't immediately respond to every request. There is no need to bump or check in 19 | on a pull request (it will clutter the discussion of the request). 20 | 21 | Also don't be worried if the request is closed or not integrated--sometimes the 22 | priorities of Adafruit's GitHub code (education, ease of use) might not match the 23 | priorities of the pull request. Don't fret, the open source community thrives on 24 | forks and GitHub makes it easy to keep your changes in a forked repo. 25 | 26 | After reviewing the guidelines above you can delete this text from the pull request. 27 | -------------------------------------------------------------------------------- /.github/workflows/githubci.yml: -------------------------------------------------------------------------------- 1 | name: Arduino Library CI 2 | 3 | on: [pull_request, push, repository_dispatch] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/setup-python@v4 11 | with: 12 | python-version: '3.x' 13 | - uses: actions/checkout@v3 14 | - uses: actions/checkout@v3 15 | with: 16 | repository: adafruit/ci-arduino 17 | path: ci 18 | 19 | - name: pre-install 20 | run: bash ci/actions_install.sh 21 | 22 | - name: test platforms 23 | run: python3 ci/build_platform.py main_platforms 24 | 25 | - name: clang 26 | run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r . 27 | 28 | - name: doxygen 29 | env: 30 | GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }} 31 | PRETTYNAME : "RTClib" 32 | run: bash ci/doxy_gen_and_deploy.sh src 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | html 3 | Doxyfile* 4 | doxygen_sqlite3.db 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RTClib [![Build Status](https://github.com/adafruit/RTClib/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/RTClib/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/RTClib/html/index.html) 2 | 3 | This is a fork of JeeLab's fantastic real time clock library for Arduino. 4 | 5 | Works great with Adafruit RTC breakouts: 6 | 7 | - [DS3231 Precision RTC](https://www.adafruit.com/product/3013) (breakout) and [Stemma QT version](https://www.adafruit.com/product/5188) 8 | - [PCF8523 RTC](https://www.adafruit.com/product/3295) 9 | - [DS1307 RTC](https://www.adafruit.com/product/3296) 10 | 11 | Please note that dayOfTheWeek() ranges from 0 to 6 inclusive with 0 being 'Sunday'. 12 | 13 | 14 | 15 | ## Compatibility 16 | 17 | MCU | Tested Works | Doesn't Work | Not Tested | Notes 18 | ------------------ | :----------: | :----------: | :---------: | ----- 19 | Atmega328 @ 16MHz | X | | | 20 | Atmega328 @ 12MHz | X | | | 21 | Atmega32u4 @ 16MHz | X | | | Use SDA/SCL on pins D3 & D2 22 | Atmega32u4 @ 8MHz | X | | | Use SDA/SCL on pins D3 & D2 23 | ESP8266 | X | | | SDA/SCL default to pins 4 & 5 but any two pins can be assigned as SDA/SCL using Wire.begin(SDA,SCL) 24 | Atmega2560 @ 16MHz | X | | | Use SDA/SCL on Pins 20 & 21 25 | ATSAM3X8E | X | | | Use SDA1 and SCL1 26 | ATSAM21D | X | | | 27 | ATtiny85 @ 16MHz | X | | | 28 | ATtiny85 @ 8MHz | X | | | 29 | Intel Curie @ 32MHz | | | X | 30 | STM32F2 | | | X | 31 | 32 | * ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini 33 | * ATmega328 @ 12MHz : Adafruit Pro Trinket 3V 34 | * ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0 35 | * ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro 36 | * ESP8266 : Adafruit Huzzah 37 | * ATmega2560 @ 16MHz : Arduino Mega 38 | * ATSAM3X8E : Arduino Due 39 | * ATSAM21D : Arduino Zero, M0 Pro 40 | * ATtiny85 @ 16MHz : Adafruit Trinket 5V 41 | * ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V 42 | 43 | 44 | Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! 45 | 46 | # Dependencies 47 | * [Adafruit BusIO](https://github.com/adafruit/Adafruit_BusIO) 48 | 49 | # Contributing 50 | 51 | Contributions are welcome! Please read our [Code of Conduct](https://github.com/adafruit/RTClib/blob/master/code-of-conduct.md) 52 | before contributing to help this project stay welcoming. 53 | 54 | ## Documentation and doxygen 55 | For the detailed API documentation, see https://adafruit.github.io/RTClib/html/index.html 56 | Documentation is produced by doxygen. Contributions should include documentation for any new code added. 57 | 58 | Some examples of how to use doxygen can be found in these guide pages: 59 | 60 | https://learn.adafruit.com/the-well-automated-arduino-library/doxygen 61 | 62 | https://learn.adafruit.com/the-well-automated-arduino-library/doxygen-tips 63 | 64 | ## Code formatting and clang-format 65 | The code should be formatted according to the [LLVM Coding Standards](https://llvm.org/docs/CodingStandards.html), which is the default of the clang-format tool. The easiest way to ensure conformance is to [install clang-format](https://llvm.org/builds/) and run 66 | 67 | ```shell 68 | clang-format -i 69 | ``` 70 | 71 | See [Formatting with clang-format](https://learn.adafruit.com/the-well-automated-arduino-library/formatting-with-clang-format) for details. 72 | 73 | Written by JeeLabs 74 | MIT license, check license.txt for more information 75 | All text above must be included in any redistribution 76 | 77 | To install, use the Arduino Library Manager and search for "RTClib" and install the library. 78 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Adafruit Community Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and leaders pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level or type of 9 | experience, education, socio-economic status, nationality, personal appearance, 10 | race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | We are committed to providing a friendly, safe and welcoming environment for 15 | all. 16 | 17 | Examples of behavior that contributes to creating a positive environment 18 | include: 19 | 20 | * Be kind and courteous to others 21 | * Using welcoming and inclusive language 22 | * Being respectful of differing viewpoints and experiences 23 | * Collaborating with other community members 24 | * Gracefully accepting constructive criticism 25 | * Focusing on what is best for the community 26 | * Showing empathy towards other community members 27 | 28 | Examples of unacceptable behavior by participants include: 29 | 30 | * The use of sexualized language or imagery and sexual attention or advances 31 | * The use of inappropriate images, including in a community member's avatar 32 | * The use of inappropriate language, including in a community member's nickname 33 | * Any spamming, flaming, baiting or other attention-stealing behavior 34 | * Excessive or unwelcome helping; answering outside the scope of the question 35 | asked 36 | * Trolling, insulting/derogatory comments, and personal or political attacks 37 | * Public or private harassment 38 | * Publishing others' private information, such as a physical or electronic 39 | address, without explicit permission 40 | * Other conduct which could reasonably be considered inappropriate 41 | 42 | The goal of the standards and moderation guidelines outlined here is to build 43 | and maintain a respectful community. We ask that you don’t just aim to be 44 | "technically unimpeachable", but rather try to be your best self. 45 | 46 | We value many things beyond technical expertise, including collaboration and 47 | supporting others within our community. Providing a positive experience for 48 | other community members can have a much more significant impact than simply 49 | providing the correct answer. 50 | 51 | ## Our Responsibilities 52 | 53 | Project leaders are responsible for clarifying the standards of acceptable 54 | behavior and are expected to take appropriate and fair corrective action in 55 | response to any instances of unacceptable behavior. 56 | 57 | Project leaders have the right and responsibility to remove, edit, or 58 | reject messages, comments, commits, code, issues, and other contributions 59 | that are not aligned to this Code of Conduct, or to ban temporarily or 60 | permanently any community member for other behaviors that they deem 61 | inappropriate, threatening, offensive, or harmful. 62 | 63 | ## Moderation 64 | 65 | Instances of behaviors that violate the Adafruit Community Code of Conduct 66 | may be reported by any member of the community. Community members are 67 | encouraged to report these situations, including situations they witness 68 | involving other community members. 69 | 70 | You may report in the following ways: 71 | 72 | In any situation, you may send an email to . 73 | 74 | On the Adafruit Discord, you may send an open message from any channel 75 | to all Community Helpers by tagging @community helpers. You may also send an 76 | open message from any channel, or a direct message to @kattni#1507, 77 | @tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or 78 | @Andon#8175. 79 | 80 | Email and direct message reports will be kept confidential. 81 | 82 | In situations on Discord where the issue is particularly egregious, possibly 83 | illegal, requires immediate action, or violates the Discord terms of service, 84 | you should also report the message directly to Discord. 85 | 86 | These are the steps for upholding our community’s standards of conduct. 87 | 88 | 1. Any member of the community may report any situation that violates the 89 | Adafruit Community Code of Conduct. All reports will be reviewed and 90 | investigated. 91 | 2. If the behavior is an egregious violation, the community member who 92 | committed the violation may be banned immediately, without warning. 93 | 3. Otherwise, moderators will first respond to such behavior with a warning. 94 | 4. Moderators follow a soft "three strikes" policy - the community member may 95 | be given another chance, if they are receptive to the warning and change their 96 | behavior. 97 | 5. If the community member is unreceptive or unreasonable when warned by a 98 | moderator, or the warning goes unheeded, they may be banned for a first or 99 | second offense. Repeated offenses will result in the community member being 100 | banned. 101 | 102 | ## Scope 103 | 104 | This Code of Conduct and the enforcement policies listed above apply to all 105 | Adafruit Community venues. This includes but is not limited to any community 106 | spaces (both public and private), the entire Adafruit Discord server, and 107 | Adafruit GitHub repositories. Examples of Adafruit Community spaces include 108 | but are not limited to meet-ups, audio chats on the Adafruit Discord, or 109 | interaction at a conference. 110 | 111 | This Code of Conduct applies both within project spaces and in public spaces 112 | when an individual is representing the project or its community. As a community 113 | member, you are representing our community, and are expected to behave 114 | accordingly. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 1.4, available at 120 | , 121 | and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html). 122 | 123 | For other projects adopting the Adafruit Community Code of 124 | Conduct, please contact the maintainers of those projects for enforcement. 125 | If you wish to use this code of conduct for your own project, consider 126 | explicitly mentioning your moderation policy or making a copy with your 127 | own moderation policy so as to avoid confusion. 128 | -------------------------------------------------------------------------------- /examples/DS3231_alarm/DS3231_alarm.ino: -------------------------------------------------------------------------------- 1 | /* Example implementation of an alarm using DS3231 2 | * 3 | * VCC and GND of RTC should be connected to some power source 4 | * SDA, SCL of RTC should be connected to SDA, SCL of arduino 5 | * SQW should be connected to CLOCK_INTERRUPT_PIN 6 | * CLOCK_INTERRUPT_PIN needs to work with interrupts 7 | */ 8 | 9 | #include 10 | // #include 11 | 12 | RTC_DS3231 rtc; 13 | 14 | // the pin that is connected to SQW 15 | #define CLOCK_INTERRUPT_PIN 2 16 | 17 | void setup() { 18 | Serial.begin(9600); 19 | 20 | // initializing the rtc 21 | if(!rtc.begin()) { 22 | Serial.println("Couldn't find RTC!"); 23 | Serial.flush(); 24 | while (1) delay(10); 25 | } 26 | 27 | if(rtc.lostPower()) { 28 | // this will adjust to the date and time at compilation 29 | rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 30 | } 31 | 32 | //we don't need the 32K Pin, so disable it 33 | rtc.disable32K(); 34 | 35 | // Making it so, that the alarm will trigger an interrupt 36 | pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP); 37 | attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, FALLING); 38 | 39 | // set alarm 1, 2 flag to false (so alarm 1, 2 didn't happen so far) 40 | // if not done, this easily leads to problems, as both register aren't reset on reboot/recompile 41 | rtc.clearAlarm(1); 42 | rtc.clearAlarm(2); 43 | 44 | // stop oscillating signals at SQW Pin 45 | // otherwise setAlarm1 will fail 46 | rtc.writeSqwPinMode(DS3231_OFF); 47 | 48 | // turn off alarm 2 (in case it isn't off already) 49 | // again, this isn't done at reboot, so a previously set alarm could easily go overlooked 50 | rtc.disableAlarm(2); 51 | 52 | // schedule an alarm 10 seconds in the future 53 | if(!rtc.setAlarm1( 54 | rtc.now() + TimeSpan(10), 55 | DS3231_A1_Second // this mode triggers the alarm when the seconds match. See Doxygen for other options 56 | )) { 57 | Serial.println("Error, alarm wasn't set!"); 58 | }else { 59 | Serial.println("Alarm will happen in 10 seconds!"); 60 | } 61 | } 62 | 63 | void loop() { 64 | // print current time 65 | char date[10] = "hh:mm:ss"; 66 | rtc.now().toString(date); 67 | Serial.print(date); 68 | 69 | // the stored alarm value + mode 70 | DateTime alarm1 = rtc.getAlarm1(); 71 | Ds3231Alarm1Mode alarm1mode = rtc.getAlarm1Mode(); 72 | char alarm1Date[12] = "DD hh:mm:ss"; 73 | alarm1.toString(alarm1Date); 74 | Serial.print(" [Alarm1: "); 75 | Serial.print(alarm1Date); 76 | Serial.print(", Mode: "); 77 | switch (alarm1mode) { 78 | case DS3231_A1_PerSecond: Serial.print("PerSecond"); break; 79 | case DS3231_A1_Second: Serial.print("Second"); break; 80 | case DS3231_A1_Minute: Serial.print("Minute"); break; 81 | case DS3231_A1_Hour: Serial.print("Hour"); break; 82 | case DS3231_A1_Date: Serial.print("Date"); break; 83 | case DS3231_A1_Day: Serial.print("Day"); break; 84 | } 85 | 86 | // the value at SQW-Pin (because of pullup 1 means no alarm) 87 | Serial.print("] SQW: "); 88 | Serial.print(digitalRead(CLOCK_INTERRUPT_PIN)); 89 | 90 | // whether a alarm fired 91 | Serial.print(" Fired: "); 92 | Serial.print(rtc.alarmFired(1)); 93 | 94 | // Serial.print(" Alarm2: "); 95 | // Serial.println(rtc.alarmFired(2)); 96 | // control register values (see https://datasheets.maximintegrated.com/en/ds/DS3231.pdf page 13) 97 | // Serial.print(" Control: 0b"); 98 | // Serial.println(read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL), BIN); 99 | 100 | // resetting SQW and alarm 1 flag 101 | // using setAlarm1, the next alarm could now be configurated 102 | if (rtc.alarmFired(1)) { 103 | rtc.clearAlarm(1); 104 | Serial.print(" - Alarm cleared"); 105 | } 106 | Serial.println(); 107 | 108 | delay(2000); 109 | } 110 | 111 | void onAlarm() { 112 | Serial.println("Alarm occured!"); 113 | } 114 | 115 | /*static uint8_t read_i2c_register(uint8_t addr, uint8_t reg) { 116 | Wire.beginTransmission(addr); 117 | Wire.write((byte)reg); 118 | Wire.endTransmission(); 119 | 120 | Wire.requestFrom(addr, (byte)1); 121 | return Wire.read(); 122 | }*/ 123 | -------------------------------------------------------------------------------- /examples/customWire_DS3231onSAMD21/.metro_m4.test.only: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/RTClib/5298434167b770c4602661d682e3b340d565073f/examples/customWire_DS3231onSAMD21/.metro_m4.test.only -------------------------------------------------------------------------------- /examples/customWire_DS3231onSAMD21/customWire_DS3231onSAMD21.ino: -------------------------------------------------------------------------------- 1 | /* Using DS3231 (or other supported RTC) with a custom TwoWire instance 2 | * 3 | * If using a microcontroller which supports additional i2c ports, 4 | * such as the SAMD21's SERCOMX, a user can define a custom i2c bus 5 | * to use with an RTC. 6 | * This example builds the custom i2c bus using SERCOM0 and leverages the "wiring_private.h" APIs 7 | * 8 | * Connecting the device: 9 | * VCC and GND of RTC should be connected to some power source 10 | * SDA, SCL of RTC should be connected to the custom SDA and SCL pins. 11 | * In this particular example we are using a Nano 33 IoT and routing 12 | * the custom Wire instance over pins 6 (SDA) and 5 (SCL) 13 | * 14 | * This example will work with Arduino Zero, any Arduino MKR board based on SAMD21, Nano 33 IoT 15 | * and any board by Adafruit, Sparkfun, Seeed Studio based on the same microcontroller 16 | * 17 | */ 18 | #include 19 | #include "wiring_private.h" 20 | #include 21 | 22 | /* Defining the custom TwoWire instance for SAMD21 */ 23 | TwoWire myWire(&sercom0, 6, 5); // Create the new wire instance assigning it to pin 0 and 1 24 | extern "C"{ 25 | void SERCOM0_Handler(void); 26 | 27 | void SERCOM0_Handler(void) { 28 | 29 | myWire.onService(); 30 | 31 | } 32 | } 33 | 34 | /* Creating a new DS3231 object */ 35 | RTC_DS3231 myRTC; 36 | 37 | String daysNames[] = { 38 | "Sunday", 39 | "Monday", 40 | "Tuesday", 41 | "Wednesday", 42 | "Thursday", 43 | "Friday", 44 | "Saturday" 45 | }; 46 | String monthsNames[] = { 47 | "-", 48 | "January", 49 | "February", 50 | "March", 51 | "April", 52 | "May", 53 | "June", 54 | "July", 55 | "August", 56 | "September", 57 | "October", 58 | "November", 59 | "December" 60 | }; 61 | 62 | void setup() { 63 | Serial.begin(57600); 64 | Serial.println("start"); 65 | 66 | unsigned long setupStartTime = millis(); 67 | /*** Waiting for Serial to be ready or timeout ***/ 68 | while(!Serial && millis() - setupStartTime < 3000); 69 | 70 | /* 71 | * Initialising pins 6 and 5 to be routed to the SERCOM0 pads 0 and 1 in order 72 | * to be used as SDA and SCL. Without this step the periphearl won't be patched through 73 | */ 74 | pinPeripheral(6, PIO_SERCOM_ALT); // PAD[0] //Assign SDA function to pin 0 75 | pinPeripheral(5, PIO_SERCOM_ALT); // PAD[1] //Assign SCL function to pin 1 76 | 77 | /* We now pass our custom TwoWire object to the RTC instance */ 78 | myRTC.begin(&myWire); 79 | 80 | /* 81 | * From this moment on every operation on the RTC will work as expected 82 | * But the i2c bus being used will be the one we manually created using SERCOM0 83 | */ 84 | 85 | /* 86 | * Creating a Date object with 87 | * YEAR, MONTH, DAY (2021, January, 1) 88 | * HOUR, MINUTE, SECONDS (0, 0, 0) 89 | * Midnight of January 1st, 2021 90 | */ 91 | DateTime newDT = DateTime(2021, 1, 1, 0, 0, 0); 92 | 93 | /* Pushing that date/time to the RTC */ 94 | myRTC.adjust(newDT); 95 | Serial.println("setup done"); 96 | } 97 | 98 | void loop() { 99 | /* creating a temporary date/time object to store the data coming from the RTC */ 100 | DateTime dt = myRTC.now(); 101 | 102 | /* printing that data to the Serial port in a meaningful format */ 103 | Serial.println("************"); 104 | Serial.print(daysNames[dt.dayOfTheWeek()]); 105 | Serial.print(" "); 106 | Serial.print(monthsNames[dt.month()]); 107 | Serial.print(" "); 108 | Serial.print(dt.day()); 109 | Serial.print(", "); 110 | Serial.println(dt.year()); 111 | Serial.print(dt.hour()); 112 | Serial.print(":"); 113 | Serial.print(dt.minute()); 114 | Serial.print(":"); 115 | Serial.println(dt.second()); 116 | /* Delays are bad, but let's not flood the Serial for this silly example */ 117 | delay(500); 118 | } 119 | 120 | 121 | -------------------------------------------------------------------------------- /examples/datecalc/datecalc.ino: -------------------------------------------------------------------------------- 1 | // Simple date conversions and calculations 2 | 3 | #include "RTClib.h" 4 | 5 | void showDate(const char* txt, const DateTime& dt) { 6 | Serial.print(txt); 7 | Serial.print(' '); 8 | Serial.print(dt.year(), DEC); 9 | Serial.print('/'); 10 | Serial.print(dt.month(), DEC); 11 | Serial.print('/'); 12 | Serial.print(dt.day(), DEC); 13 | Serial.print(' '); 14 | Serial.print(dt.hour(), DEC); 15 | Serial.print(':'); 16 | Serial.print(dt.minute(), DEC); 17 | Serial.print(':'); 18 | Serial.print(dt.second(), DEC); 19 | 20 | Serial.print(" = "); 21 | Serial.print(dt.unixtime()); 22 | Serial.print("s / "); 23 | Serial.print(dt.unixtime() / 86400L); 24 | Serial.print("d since 1970"); 25 | 26 | Serial.println(); 27 | } 28 | 29 | void showTimeSpan(const char* txt, const TimeSpan& ts) { 30 | Serial.print(txt); 31 | Serial.print(" "); 32 | Serial.print(ts.days(), DEC); 33 | Serial.print(" days "); 34 | Serial.print(ts.hours(), DEC); 35 | Serial.print(" hours "); 36 | Serial.print(ts.minutes(), DEC); 37 | Serial.print(" minutes "); 38 | Serial.print(ts.seconds(), DEC); 39 | Serial.print(" seconds ("); 40 | Serial.print(ts.totalseconds(), DEC); 41 | Serial.print(" total seconds)"); 42 | Serial.println(); 43 | } 44 | 45 | void setup () { 46 | Serial.begin(57600); 47 | 48 | #ifndef ESP8266 49 | while (!Serial); // wait for serial port to connect. Needed for native USB 50 | #endif 51 | 52 | DateTime dt0 (0, 1, 1, 0, 0, 0); 53 | showDate("dt0", dt0); 54 | 55 | DateTime dt1 (1, 1, 1, 0, 0, 0); 56 | showDate("dt1", dt1); 57 | 58 | DateTime dt2 (2009, 1, 1, 0, 0, 0); 59 | showDate("dt2", dt2); 60 | 61 | DateTime dt3 (2009, 1, 2, 0, 0, 0); 62 | showDate("dt3", dt3); 63 | 64 | DateTime dt4 (2009, 1, 27, 0, 0, 0); 65 | showDate("dt4", dt4); 66 | 67 | DateTime dt5 (2009, 2, 27, 0, 0, 0); 68 | showDate("dt5", dt5); 69 | 70 | DateTime dt6 (2009, 12, 27, 0, 0, 0); 71 | showDate("dt6", dt6); 72 | 73 | DateTime dt7 (dt6.unixtime() + 3600); // One hour later. 74 | showDate("dt7", dt7); 75 | 76 | DateTime dt75 = dt6 + TimeSpan(0, 1, 0, 0); // One hour later with TimeSpan addition. 77 | showDate("dt7.5", dt75); 78 | 79 | DateTime dt8 (dt6.unixtime() + 86400L); // One day later. 80 | showDate("dt8", dt8); 81 | 82 | DateTime dt85 = dt6 + TimeSpan(1, 0, 0, 0); // One day later with TimeSpan addition. 83 | showDate("dt8.5", dt85); 84 | 85 | DateTime dt9 (dt6.unixtime() + 7 * 86400L); // One week later. 86 | showDate("dt9", dt9); 87 | 88 | DateTime dt95 = dt6 + TimeSpan(7, 0, 0, 0); // One week later with TimeSpan addition. 89 | showDate("dt9.5", dt95); 90 | 91 | DateTime dt10 = dt6 + TimeSpan(0, 0, 42, 42); // Fourty two minutes and fourty two seconds later. 92 | showDate("dt10", dt10); 93 | 94 | DateTime dt11 = dt6 - TimeSpan(7, 0, 0, 0); // One week ago. 95 | showDate("dt11", dt11); 96 | 97 | TimeSpan ts1 = dt6 - dt5; 98 | showTimeSpan("dt6-dt5", ts1); 99 | 100 | TimeSpan ts2 = dt10 - dt6; 101 | showTimeSpan("dt10-dt6", ts2); 102 | } 103 | 104 | void loop () { 105 | } 106 | -------------------------------------------------------------------------------- /examples/ds1307/ds1307.ino: -------------------------------------------------------------------------------- 1 | // Date and time functions using a DS1307 RTC connected via I2C and Wire lib 2 | #include "RTClib.h" 3 | 4 | RTC_DS1307 rtc; 5 | 6 | char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 7 | 8 | void setup () { 9 | Serial.begin(57600); 10 | 11 | #ifndef ESP8266 12 | while (!Serial); // wait for serial port to connect. Needed for native USB 13 | #endif 14 | 15 | if (! rtc.begin()) { 16 | Serial.println("Couldn't find RTC"); 17 | Serial.flush(); 18 | while (1) delay(10); 19 | } 20 | 21 | if (! rtc.isrunning()) { 22 | Serial.println("RTC is NOT running, let's set the time!"); 23 | // When time needs to be set on a new device, or after a power loss, the 24 | // following line sets the RTC to the date & time this sketch was compiled 25 | rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 26 | // This line sets the RTC with an explicit date & time, for example to set 27 | // January 21, 2014 at 3am you would call: 28 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 29 | } 30 | 31 | // When time needs to be re-set on a previously configured device, the 32 | // following line sets the RTC to the date & time this sketch was compiled 33 | // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 34 | // This line sets the RTC with an explicit date & time, for example to set 35 | // January 21, 2014 at 3am you would call: 36 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 37 | } 38 | 39 | void loop () { 40 | DateTime now = rtc.now(); 41 | 42 | Serial.print(now.year(), DEC); 43 | Serial.print('/'); 44 | Serial.print(now.month(), DEC); 45 | Serial.print('/'); 46 | Serial.print(now.day(), DEC); 47 | Serial.print(" ("); 48 | Serial.print(daysOfTheWeek[now.dayOfTheWeek()]); 49 | Serial.print(") "); 50 | Serial.print(now.hour(), DEC); 51 | Serial.print(':'); 52 | Serial.print(now.minute(), DEC); 53 | Serial.print(':'); 54 | Serial.print(now.second(), DEC); 55 | Serial.println(); 56 | 57 | Serial.print(" since midnight 1/1/1970 = "); 58 | Serial.print(now.unixtime()); 59 | Serial.print("s = "); 60 | Serial.print(now.unixtime() / 86400L); 61 | Serial.println("d"); 62 | 63 | // calculate a date which is 7 days, 12 hours, 30 minutes, and 6 seconds into the future 64 | DateTime future (now + TimeSpan(7,12,30,6)); 65 | 66 | Serial.print(" now + 7d + 12h + 30m + 6s: "); 67 | Serial.print(future.year(), DEC); 68 | Serial.print('/'); 69 | Serial.print(future.month(), DEC); 70 | Serial.print('/'); 71 | Serial.print(future.day(), DEC); 72 | Serial.print(' '); 73 | Serial.print(future.hour(), DEC); 74 | Serial.print(':'); 75 | Serial.print(future.minute(), DEC); 76 | Serial.print(':'); 77 | Serial.print(future.second(), DEC); 78 | Serial.println(); 79 | 80 | Serial.println(); 81 | delay(3000); 82 | } 83 | -------------------------------------------------------------------------------- /examples/ds1307SqwPin/ds1307SqwPin.ino: -------------------------------------------------------------------------------- 1 | // SQW/OUT pin mode using a DS1307 RTC connected via I2C. 2 | // 3 | // According to the data sheet (http://datasheets.maxim-ic.com/en/ds/DS1307.pdf), the 4 | // DS1307's SQW/OUT pin can be set to low, high, 1Hz, 4.096kHz, 8.192kHz, or 32.768kHz. 5 | // 6 | // This sketch reads the state of the pin, then iterates through the possible values at 7 | // 5 second intervals. 8 | // 9 | 10 | // NOTE: 11 | // You must connect a pull up resistor (~10kohm) from the SQW pin up to VCC. Without 12 | // this pull up the wave output will not work! 13 | 14 | #include "RTClib.h" 15 | 16 | RTC_DS1307 rtc; 17 | 18 | int mode_index = 0; 19 | 20 | Ds1307SqwPinMode modes[] = { DS1307_OFF, DS1307_ON, DS1307_SquareWave1HZ, DS1307_SquareWave4kHz, DS1307_SquareWave8kHz, DS1307_SquareWave32kHz}; 21 | 22 | 23 | void print_mode() { 24 | Ds1307SqwPinMode mode = rtc.readSqwPinMode(); 25 | 26 | Serial.print("Sqw Pin Mode: "); 27 | switch(mode) { 28 | case DS1307_OFF: Serial.println("OFF"); break; 29 | case DS1307_ON: Serial.println("ON"); break; 30 | case DS1307_SquareWave1HZ: Serial.println("1Hz"); break; 31 | case DS1307_SquareWave4kHz: Serial.println("4.096kHz"); break; 32 | case DS1307_SquareWave8kHz: Serial.println("8.192kHz"); break; 33 | case DS1307_SquareWave32kHz: Serial.println("32.768kHz"); break; 34 | default: Serial.println("UNKNOWN"); break; 35 | } 36 | } 37 | 38 | void setup () { 39 | Serial.begin(57600); 40 | 41 | #ifndef ESP8266 42 | while (!Serial); // wait for serial port to connect. Needed for native USB 43 | #endif 44 | 45 | if (! rtc.begin()) { 46 | Serial.println("Couldn't find RTC"); 47 | Serial.flush(); 48 | while (1) delay(10); 49 | } 50 | 51 | print_mode(); 52 | } 53 | 54 | void loop () { 55 | rtc.writeSqwPinMode(modes[mode_index++]); 56 | print_mode(); 57 | 58 | if (mode_index > 5) { 59 | mode_index = 0; 60 | } 61 | 62 | delay(5000); 63 | } 64 | -------------------------------------------------------------------------------- /examples/ds1307nvram/ds1307nvram.ino: -------------------------------------------------------------------------------- 1 | // Example of using the non-volatile RAM storage on the DS1307. 2 | // You can write up to 56 bytes from address 0 to 55. 3 | // Data will be persisted as long as the DS1307 has battery power. 4 | 5 | #include "RTClib.h" 6 | 7 | RTC_DS1307 rtc; 8 | 9 | void printnvram(uint8_t address) { 10 | Serial.print("Address 0x"); 11 | Serial.print(address, HEX); 12 | Serial.print(" = 0x"); 13 | Serial.println(rtc.readnvram(address), HEX); 14 | } 15 | 16 | void setup () { 17 | Serial.begin(57600); 18 | 19 | #ifndef ESP8266 20 | while (!Serial); // wait for serial port to connect. Needed for native USB 21 | #endif 22 | 23 | if (! rtc.begin()) { 24 | Serial.println("Couldn't find RTC"); 25 | Serial.flush(); 26 | while (1) delay(10); 27 | } 28 | 29 | // Print old RAM contents on startup. 30 | Serial.println("Current NVRAM values:"); 31 | for (int i = 0; i < 6; ++i) { 32 | printnvram(i); 33 | } 34 | 35 | // Write some bytes to non-volatile RAM storage. 36 | // NOTE: You can only read and write from addresses 0 to 55 (i.e. 56 byte values). 37 | Serial.println("Writing NVRAM values."); 38 | // Example writing one byte at a time: 39 | rtc.writenvram(0, 0xFE); 40 | rtc.writenvram(1, 0xED); 41 | // Example writing multiple bytes: 42 | uint8_t writeData[4] = { 0xBE, 0xEF, 0x01, 0x02 }; 43 | rtc.writenvram(2, writeData, 4); 44 | 45 | // Read bytes from non-volatile RAM storage. 46 | Serial.println("Reading NVRAM values:"); 47 | // Example reading one byte at a time. 48 | Serial.println(rtc.readnvram(0), HEX); 49 | Serial.println(rtc.readnvram(1), HEX); 50 | // Example reading multiple bytes: 51 | uint8_t readData[4] = {0}; 52 | rtc.readnvram(readData, 4, 2); 53 | Serial.println(readData[0], HEX); 54 | Serial.println(readData[1], HEX); 55 | Serial.println(readData[2], HEX); 56 | Serial.println(readData[3], HEX); 57 | 58 | } 59 | 60 | void loop () { 61 | // Do nothing in the loop. 62 | } 63 | -------------------------------------------------------------------------------- /examples/ds3231/ds3231.ino: -------------------------------------------------------------------------------- 1 | // Date and time functions using a DS3231 RTC connected via I2C and Wire lib 2 | #include "RTClib.h" 3 | 4 | RTC_DS3231 rtc; 5 | 6 | char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 7 | 8 | void setup () { 9 | Serial.begin(57600); 10 | 11 | #ifndef ESP8266 12 | while (!Serial); // wait for serial port to connect. Needed for native USB 13 | #endif 14 | 15 | if (! rtc.begin()) { 16 | Serial.println("Couldn't find RTC"); 17 | Serial.flush(); 18 | while (1) delay(10); 19 | } 20 | 21 | if (rtc.lostPower()) { 22 | Serial.println("RTC lost power, let's set the time!"); 23 | // When time needs to be set on a new device, or after a power loss, the 24 | // following line sets the RTC to the date & time this sketch was compiled 25 | rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 26 | // This line sets the RTC with an explicit date & time, for example to set 27 | // January 21, 2014 at 3am you would call: 28 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 29 | } 30 | 31 | // When time needs to be re-set on a previously configured device, the 32 | // following line sets the RTC to the date & time this sketch was compiled 33 | // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 34 | // This line sets the RTC with an explicit date & time, for example to set 35 | // January 21, 2014 at 3am you would call: 36 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 37 | } 38 | 39 | void loop () { 40 | DateTime now = rtc.now(); 41 | 42 | Serial.print(now.year(), DEC); 43 | Serial.print('/'); 44 | Serial.print(now.month(), DEC); 45 | Serial.print('/'); 46 | Serial.print(now.day(), DEC); 47 | Serial.print(" ("); 48 | Serial.print(daysOfTheWeek[now.dayOfTheWeek()]); 49 | Serial.print(") "); 50 | Serial.print(now.hour(), DEC); 51 | Serial.print(':'); 52 | Serial.print(now.minute(), DEC); 53 | Serial.print(':'); 54 | Serial.print(now.second(), DEC); 55 | Serial.println(); 56 | 57 | Serial.print(" since midnight 1/1/1970 = "); 58 | Serial.print(now.unixtime()); 59 | Serial.print("s = "); 60 | Serial.print(now.unixtime() / 86400L); 61 | Serial.println("d"); 62 | 63 | // calculate a date which is 7 days, 12 hours, 30 minutes, 6 seconds into the future 64 | DateTime future (now + TimeSpan(7,12,30,6)); 65 | 66 | Serial.print(" now + 7d + 12h + 30m + 6s: "); 67 | Serial.print(future.year(), DEC); 68 | Serial.print('/'); 69 | Serial.print(future.month(), DEC); 70 | Serial.print('/'); 71 | Serial.print(future.day(), DEC); 72 | Serial.print(' '); 73 | Serial.print(future.hour(), DEC); 74 | Serial.print(':'); 75 | Serial.print(future.minute(), DEC); 76 | Serial.print(':'); 77 | Serial.print(future.second(), DEC); 78 | Serial.println(); 79 | 80 | Serial.print("Temperature: "); 81 | Serial.print(rtc.getTemperature()); 82 | Serial.println(" C"); 83 | 84 | Serial.println(); 85 | delay(3000); 86 | } 87 | -------------------------------------------------------------------------------- /examples/interrupts1Hz/.leonardo.test.only: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/RTClib/5298434167b770c4602661d682e3b340d565073f/examples/interrupts1Hz/.leonardo.test.only -------------------------------------------------------------------------------- /examples/interrupts1Hz/.mega2560.test.only: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/RTClib/5298434167b770c4602661d682e3b340d565073f/examples/interrupts1Hz/.mega2560.test.only -------------------------------------------------------------------------------- /examples/interrupts1Hz/.uno.test.only: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/RTClib/5298434167b770c4602661d682e3b340d565073f/examples/interrupts1Hz/.uno.test.only -------------------------------------------------------------------------------- /examples/interrupts1Hz/interrupts1Hz.ino: -------------------------------------------------------------------------------- 1 | /*********************************************************************** 2 | 3 | Combining RTClib with the avr-libc timing functions 4 | =================================================== 5 | 6 | The standard way of getting the current time and date with RTClib is to 7 | call the now() method of the appropriate RTC class. This, however, is 8 | somewhat slow, as it involves communicating with the RTC through the I2C 9 | bus. An alternative, more lightweight method involves configuring the 10 | RTC to deliver one pulse per second to an interrupt pin, and counting 11 | the seconds in the interrupt handler. The timekeeping is then entirely 12 | handled in the Arduino, with no I2C communication with the RTC other 13 | than during the initialization phase. 14 | 15 | On AVR-based Arduinos (Uno, Nano, Micro, ...), the Arduino core library 16 | is built on top of avr-libc, which is an implementation of the standard 17 | C library for the AVR platform. This library provides the standard C 18 | functions for handling time:[1] time(), gmtime(), mktime(), etc. The 19 | time() function is normally used to retrieve the current time from the 20 | operating system, but since we have no operating system, the avr-libc 21 | provides its own non-standard functions for implementing a time source: 22 | 23 | - set_system_time() initializes the library's idea of the current time 24 | - system_tick() steps the system time by one second. 25 | 26 | This sketch demonstrates how to combine RTClib and avr-libc in order to 27 | handle the timekeeping entirely on the Arduino from an interrupt 28 | delivered by the RTC: 29 | 30 | - RTClib is used to configure the RTC and retrieve the initial time 31 | - avr-libc is used for regular timekeeping 32 | 33 | This sketch only works on AVR-based Arduinos, as it relies on 34 | non-standard functions provided by avr-libc. 35 | 36 | [1] https://www.nongnu.org/avr-libc/user-manual/group__avr__time.html 37 | 38 | ***********************************************************************/ 39 | 40 | #include 41 | #include // standard C timing functions 42 | 43 | // Pin receiving the one-pulse-per-second signal from the RTC. 44 | // This should be an interrupt-capable pin. 45 | const uint8_t pin1pps = 2; 46 | 47 | // We will use the PCF8523 RTC, which has the handy "Second Timer". 48 | // Other RTCs could be used with their "square wave" output configured 49 | // to 1 Hz. 50 | RTC_PCF8523 rtc; 51 | 52 | void setup() { 53 | 54 | // Initialize the serial port. 55 | Serial.begin(57600); 56 | while (!Serial); // wait for serial port to connect. Needed for native USB 57 | 58 | // Initialize the RTC. 59 | if (! rtc.begin()) { 60 | Serial.println("Couldn't find RTC"); 61 | Serial.flush(); 62 | while (1) delay(10); 63 | } 64 | if (!rtc.initialized() || rtc.lostPower()) { 65 | rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 66 | } 67 | rtc.deconfigureAllTimers(); // undo previous configuration, if any 68 | 69 | // Initialize the system time from the RTC time. Both avr-libc and 70 | // DateTime::secondstime() use the start of year 2000 as their 71 | // reference "epoch". 72 | set_system_time(rtc.now().secondstime()); 73 | 74 | // Keep the time in sync using the one-pulse-per-second output of the 75 | // RTC as an interrupt source and calling system_tick() from the 76 | // interrupt service routine. 77 | pinMode(pin1pps, INPUT_PULLUP); 78 | rtc.enableSecondTimer(); 79 | attachInterrupt(digitalPinToInterrupt(pin1pps), system_tick, FALLING); 80 | } 81 | 82 | void loop() { 83 | 84 | // From here on, we only use the standard C timing functions. 85 | // time() returns the current time as a single number of type time_t, 86 | // this is the number of seconds elapsed since a reference "epoch". 87 | time_t now = time(nullptr); 88 | 89 | // gmtime() converts the time to a broken-down form (year, month...) 90 | // similar to the DateTime class. Unlike localtime(), it doesn't 91 | // attempt timezone conversions. 92 | struct tm *broken_down_time = gmtime(&now); 93 | 94 | // asctime() returns a textual representation of the date and time as 95 | // a C string (pointer to a character array). The format is similar to 96 | // the DateTime::toString() format "DDD MMM DD hh:mm:ss YYYY". 97 | Serial.println(asctime(broken_down_time)); 98 | 99 | delay(1000); 100 | } 101 | -------------------------------------------------------------------------------- /examples/pcf8523/pcf8523.ino: -------------------------------------------------------------------------------- 1 | // Date and time functions using a PCF8523 RTC connected via I2C and Wire lib 2 | #include "RTClib.h" 3 | 4 | RTC_PCF8523 rtc; 5 | 6 | char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 7 | 8 | void setup () { 9 | Serial.begin(57600); 10 | 11 | #ifndef ESP8266 12 | while (!Serial); // wait for serial port to connect. Needed for native USB 13 | #endif 14 | 15 | if (! rtc.begin()) { 16 | Serial.println("Couldn't find RTC"); 17 | Serial.flush(); 18 | while (1) delay(10); 19 | } 20 | 21 | if (! rtc.initialized() || rtc.lostPower()) { 22 | Serial.println("RTC is NOT initialized, let's set the time!"); 23 | // When time needs to be set on a new device, or after a power loss, the 24 | // following line sets the RTC to the date & time this sketch was compiled 25 | rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 26 | // This line sets the RTC with an explicit date & time, for example to set 27 | // January 21, 2014 at 3am you would call: 28 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 29 | // 30 | // Note: allow 2 seconds after inserting battery or applying external power 31 | // without battery before calling adjust(). This gives the PCF8523's 32 | // crystal oscillator time to stabilize. If you call adjust() very quickly 33 | // after the RTC is powered, lostPower() may still return true. 34 | } 35 | 36 | // When time needs to be re-set on a previously configured device, the 37 | // following line sets the RTC to the date & time this sketch was compiled 38 | // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 39 | // This line sets the RTC with an explicit date & time, for example to set 40 | // January 21, 2014 at 3am you would call: 41 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 42 | 43 | // When the RTC was stopped and stays connected to the battery, it has 44 | // to be restarted by clearing the STOP bit. Let's do this to ensure 45 | // the RTC is running. 46 | rtc.start(); 47 | 48 | // The PCF8523 can be calibrated for: 49 | // - Aging adjustment 50 | // - Temperature compensation 51 | // - Accuracy tuning 52 | // The offset mode to use, once every two hours or once every minute. 53 | // The offset Offset value from -64 to +63. See the Application Note for calculation of offset values. 54 | // https://www.nxp.com/docs/en/application-note/AN11247.pdf 55 | // The deviation in parts per million can be calculated over a period of observation. Both the drift (which can be negative) 56 | // and the observation period must be in seconds. For accuracy the variation should be observed over about 1 week. 57 | // Note: any previous calibration should cancelled prior to any new observation period. 58 | // Example - RTC gaining 43 seconds in 1 week 59 | float drift = 43; // seconds plus or minus over oservation period - set to 0 to cancel previous calibration. 60 | float period_sec = (7 * 86400); // total obsevation period in seconds (86400 = seconds in 1 day: 7 days = (7 * 86400) seconds ) 61 | float deviation_ppm = (drift / period_sec * 1000000); // deviation in parts per million (μs) 62 | float drift_unit = 4.34; // use with offset mode PCF8523_TwoHours 63 | // float drift_unit = 4.069; //For corrections every min the drift_unit is 4.069 ppm (use with offset mode PCF8523_OneMinute) 64 | int offset = round(deviation_ppm / drift_unit); 65 | // rtc.calibrate(PCF8523_TwoHours, offset); // Un-comment to perform calibration once drift (seconds) and observation period (seconds) are correct 66 | // rtc.calibrate(PCF8523_TwoHours, 0); // Un-comment to cancel previous calibration 67 | 68 | Serial.print("Offset is "); Serial.println(offset); // Print to control offset 69 | 70 | } 71 | 72 | void loop () { 73 | DateTime now = rtc.now(); 74 | 75 | Serial.print(now.year(), DEC); 76 | Serial.print('/'); 77 | Serial.print(now.month(), DEC); 78 | Serial.print('/'); 79 | Serial.print(now.day(), DEC); 80 | Serial.print(" ("); 81 | Serial.print(daysOfTheWeek[now.dayOfTheWeek()]); 82 | Serial.print(") "); 83 | Serial.print(now.hour(), DEC); 84 | Serial.print(':'); 85 | Serial.print(now.minute(), DEC); 86 | Serial.print(':'); 87 | Serial.print(now.second(), DEC); 88 | Serial.println(); 89 | 90 | Serial.print(" since midnight 1/1/1970 = "); 91 | Serial.print(now.unixtime()); 92 | Serial.print("s = "); 93 | Serial.print(now.unixtime() / 86400L); 94 | Serial.println("d"); 95 | 96 | // calculate a date which is 7 days, 12 hours and 30 seconds into the future 97 | DateTime future (now + TimeSpan(7,12,30,6)); 98 | 99 | Serial.print(" now + 7d + 12h + 30m + 6s: "); 100 | Serial.print(future.year(), DEC); 101 | Serial.print('/'); 102 | Serial.print(future.month(), DEC); 103 | Serial.print('/'); 104 | Serial.print(future.day(), DEC); 105 | Serial.print(' '); 106 | Serial.print(future.hour(), DEC); 107 | Serial.print(':'); 108 | Serial.print(future.minute(), DEC); 109 | Serial.print(':'); 110 | Serial.print(future.second(), DEC); 111 | Serial.println(); 112 | 113 | Serial.println(); 114 | delay(3000); 115 | } 116 | -------------------------------------------------------------------------------- /examples/pcf8523Countdown/pcf8523Countdown.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /* 3 | Countdown Timer using a PCF8523 RTC connected via I2C and Wire lib 4 | with the INT/SQW pin wired to an interrupt-capable input. 5 | 6 | According to the data sheet, the PCF8523 can run countdown timers 7 | from 244 microseconds to 10.625 days: 8 | https://www.nxp.com/docs/en/data-sheet/PCF8523.pdf#page=34 9 | 10 | This sketch sets a countdown timer, and executes code when it reaches 0, 11 | then blinks the built-in LED like BlinkWithoutDelay, but without millis()! 12 | 13 | NOTE: 14 | You must connect the PCF8523's interrupt pin to your Arduino or other 15 | microcontroller on an input pin that can handle interrupts, and that has a 16 | pullup resistor. The pin will be briefly pulled low each time the countdown 17 | reaches 0. This example will not work without the interrupt pin connected! 18 | 19 | On Adafruit breakout boards, the interrupt pin is labeled 'INT' or 'SQW'. 20 | */ 21 | /**************************************************************************/ 22 | 23 | #include "RTClib.h" 24 | 25 | RTC_PCF8523 rtc; 26 | 27 | // Input pin with interrupt capability 28 | // const int timerInterruptPin = 2; // Most Arduinos 29 | const int timerInterruptPin = 5; // Adafruit Feather M0/M4/nRF52840 30 | 31 | // Variables modified during an interrupt must be declared volatile 32 | volatile bool countdownInterruptTriggered = false; 33 | volatile int numCountdownInterrupts = 0; 34 | 35 | void setup () { 36 | Serial.begin(57600); 37 | 38 | #ifndef ESP8266 39 | while (!Serial); // wait for serial port to connect. Needed for native USB 40 | #endif 41 | 42 | if (! rtc.begin()) { 43 | Serial.println("Couldn't find RTC"); 44 | Serial.flush(); 45 | while (1) delay(10); 46 | } 47 | 48 | pinMode(LED_BUILTIN, OUTPUT); 49 | 50 | // Set the pin attached to PCF8523 INT to be an input with pullup to HIGH. 51 | // The PCF8523 interrupt pin will briefly pull it LOW at the end of a given 52 | // countdown period, then it will be released to be pulled HIGH again. 53 | pinMode(timerInterruptPin, INPUT_PULLUP); 54 | 55 | Serial.println(F("\nStarting PCF8523 Countdown Timer example.")); 56 | Serial.print(F("Configured to expect PCF8523 INT/SQW pin connected to input pin: ")); 57 | Serial.println(timerInterruptPin); 58 | Serial.println(F("This example will not work without the interrupt pin connected!\n\n")); 59 | 60 | // Timer configuration is not cleared on an RTC reset due to battery backup! 61 | rtc.deconfigureAllTimers(); 62 | 63 | Serial.println(F("First, use the PCF8523's 'Countdown Timer' with an interrupt.")); 64 | Serial.println(F("Set the countdown for 10 seconds and we'll let it run for 2 rounds.")); 65 | Serial.println(F("Starting Countdown Timer now...")); 66 | 67 | // These are the PCF8523's built-in "Timer Source Clock Frequencies". 68 | // They are predefined time periods you choose as your base unit of time, 69 | // depending on the length of countdown timer you need. 70 | // The minimum length of your countdown is 1 time period. 71 | // The maximum length of your countdown is 255 time periods. 72 | // 73 | // PCF8523_FrequencyHour = 1 hour, max 10.625 days (255 hours) 74 | // PCF8523_FrequencyMinute = 1 minute, max 4.25 hours 75 | // PCF8523_FrequencySecond = 1 second, max 4.25 minutes 76 | // PCF8523_Frequency64Hz = 1/64 of a second (15.625 milliseconds), max 3.984 seconds 77 | // PCF8523_Frequency4kHz = 1/4096 of a second (244 microseconds), max 62.256 milliseconds 78 | // 79 | // 80 | // These are the PCF8523's optional 'Low Pulse Widths' of time the interrupt 81 | // pin is held LOW at the end of every countdown (frequency 64Hz or longer). 82 | // 83 | // PCF8523_LowPulse3x64Hz = 46.875 ms 3/64ths second (default) 84 | // PCF8523_LowPulse4x64Hz = 62.500 ms 4/64ths second 85 | // PCF8523_LowPulse5x64Hz = 78.125 ms 5/64ths second 86 | // PCF8523_LowPulse6x64Hz = 93.750 ms 6/64ths second 87 | // PCF8523_LowPulse8x64Hz = 125.000 ms 8/64ths second 88 | // PCF8523_LowPulse10x64Hz = 156.250 ms 10/64ths second 89 | // PCF8523_LowPulse12x64Hz = 187.500 ms 12/64ths second 90 | // PCF8523_LowPulse14x64Hz = 218.750 ms 14/64ths second 91 | // 92 | // 93 | // Uncomment an example below: 94 | 95 | // rtc.enableCountdownTimer(PCF8523_FrequencyHour, 24); // 1 day 96 | // rtc.enableCountdownTimer(PCF8523_FrequencyMinute, 150); // 2.5 hours 97 | rtc.enableCountdownTimer(PCF8523_FrequencySecond, 10); // 10 seconds 98 | // rtc.enableCountdownTimer(PCF8523_Frequency64Hz, 32); // 1/2 second 99 | // rtc.enableCountdownTimer(PCF8523_Frequency64Hz, 16); // 1/4 second 100 | // rtc.enableCountdownTimer(PCF8523_Frequency4kHz, 205); // 50 milliseconds 101 | 102 | attachInterrupt(digitalPinToInterrupt(timerInterruptPin), countdownOver, FALLING); 103 | 104 | // This message proves we're not blocked while counting down! 105 | Serial.println(F(" While we're waiting, a word of caution:")); 106 | Serial.println(F(" When starting a new countdown timer, the first time period is not of fixed")); 107 | Serial.println(F(" duration. The amount of inaccuracy for the first time period is up to one full")); 108 | Serial.println(F(" clock frequency. Example: just the first second of the first round of a new")); 109 | Serial.println(F(" countdown based on PCF8523_FrequencySecond may be off by as much as 1 second!")); 110 | Serial.println(F(" For critical timing, consider starting actions on the first interrupt.")); 111 | } 112 | 113 | // Triggered by the PCF8523 Countdown Timer interrupt at the end of a countdown 114 | // period. Meanwhile, the PCF8523 immediately starts the countdown again. 115 | void countdownOver () { 116 | // Set a flag to run code in the loop(): 117 | countdownInterruptTriggered = true; 118 | numCountdownInterrupts++; 119 | } 120 | 121 | // Triggered by the PCF8523 Second Timer every second. 122 | void toggleLed () { 123 | // Run certain types of fast executing code here: 124 | digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); 125 | } 126 | 127 | void loop () { 128 | if (countdownInterruptTriggered && numCountdownInterrupts == 1) { 129 | Serial.println(F("1st countdown interrupt triggered. Accurate timekeeping starts now.")); 130 | countdownInterruptTriggered = false; // don't come in here again 131 | } else if (countdownInterruptTriggered && numCountdownInterrupts == 2) { 132 | Serial.println(F("2nd countdown interrupt triggered. Disabling countdown and detaching interrupt.\n\n")); 133 | rtc.disableCountdownTimer(); 134 | detachInterrupt(digitalPinToInterrupt(timerInterruptPin)); 135 | delay(2000); 136 | 137 | 138 | Serial.println(F("Now, set up the PCF8523's 'Second Timer' to toggle the built-in LED at 1Hz...")); 139 | attachInterrupt(digitalPinToInterrupt(timerInterruptPin), toggleLed, FALLING); 140 | rtc.enableSecondTimer(); 141 | Serial.println(F("Look for the built-in LED to flash 1 second ON, 1 second OFF, repeat. ")); 142 | Serial.println(F("Meanwhile this program will use delay() to block code execution briefly")); 143 | Serial.println(F("before moving on to the last example. Notice the LED keeps blinking!\n\n")); 144 | delay(20000); // less accurate, blocks execution here. Meanwhile Second Timer keeps running. 145 | rtc.disableSecondTimer(); 146 | detachInterrupt(digitalPinToInterrupt(timerInterruptPin)); 147 | 148 | 149 | Serial.println(F("Lastly, set up a Countdown Timer that works without attaching an interrupt...")); 150 | rtc.enableCountdownTimer(PCF8523_Frequency64Hz, 32, PCF8523_LowPulse8x64Hz); 151 | Serial.println(F("Look for the LED to turn on every 1/2 second and stay lit for 1/8th of a second.")); 152 | Serial.println(F("The countdown was set to a source clock frequency of 64 Hz (1/64th of a second)")); 153 | Serial.println(F("for a length of 32 time periods. 32 * 1/64th of a second is 1/2 of a second.")); 154 | Serial.println(F("The low pulse duration was set to 125 ms, or 1/8th of a second.")); 155 | Serial.println(F("The loop() keeps the built-in LED set to the opposite state of the INT/SQW pin.")); 156 | 157 | 158 | countdownInterruptTriggered = false; // don't come in here again 159 | } 160 | 161 | // While countdown running, INT/SQW pullup to HIGH, set LED to LOW (off) 162 | // When countdown is over, INT/SQW pulled down LOW, set LED to HIGH (on) 163 | digitalWrite(LED_BUILTIN, !digitalRead(timerInterruptPin)); 164 | } 165 | -------------------------------------------------------------------------------- /examples/pcf8563/pcf8563.ino: -------------------------------------------------------------------------------- 1 | // Date and time functions using a PCF8563 RTC connected via I2C and Wire lib 2 | #include "RTClib.h" 3 | 4 | RTC_PCF8563 rtc; 5 | 6 | char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 7 | 8 | void setup () { 9 | Serial.begin(115200); 10 | 11 | #ifndef ESP8266 12 | while (!Serial); // wait for serial port to connect. Needed for native USB 13 | #endif 14 | 15 | if (! rtc.begin()) { 16 | Serial.println("Couldn't find RTC"); 17 | Serial.flush(); 18 | while (1) delay(10); 19 | } 20 | 21 | if (rtc.lostPower()) { 22 | Serial.println("RTC is NOT initialized, let's set the time!"); 23 | // When time needs to be set on a new device, or after a power loss, the 24 | // following line sets the RTC to the date & time this sketch was compiled 25 | rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 26 | // This line sets the RTC with an explicit date & time, for example to set 27 | // January 21, 2014 at 3am you would call: 28 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 29 | // 30 | // Note: allow 2 seconds after inserting battery or applying external power 31 | // without battery before calling adjust(). This gives the PCF8523's 32 | // crystal oscillator time to stabilize. If you call adjust() very quickly 33 | // after the RTC is powered, lostPower() may still return true. 34 | } 35 | 36 | // When time needs to be re-set on a previously configured device, the 37 | // following line sets the RTC to the date & time this sketch was compiled 38 | // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 39 | // This line sets the RTC with an explicit date & time, for example to set 40 | // January 21, 2014 at 3am you would call: 41 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 42 | 43 | // When the RTC was stopped and stays connected to the battery, it has 44 | // to be restarted by clearing the STOP bit. Let's do this to ensure 45 | // the RTC is running. 46 | rtc.start(); 47 | } 48 | 49 | void loop () { 50 | DateTime now = rtc.now(); 51 | 52 | Serial.print(now.year(), DEC); 53 | Serial.print('/'); 54 | Serial.print(now.month(), DEC); 55 | Serial.print('/'); 56 | Serial.print(now.day(), DEC); 57 | Serial.print(" ("); 58 | Serial.print(daysOfTheWeek[now.dayOfTheWeek()]); 59 | Serial.print(") "); 60 | Serial.print(now.hour(), DEC); 61 | Serial.print(':'); 62 | Serial.print(now.minute(), DEC); 63 | Serial.print(':'); 64 | Serial.print(now.second(), DEC); 65 | Serial.println(); 66 | 67 | Serial.print(" since midnight 1/1/1970 = "); 68 | Serial.print(now.unixtime()); 69 | Serial.print("s = "); 70 | Serial.print(now.unixtime() / 86400L); 71 | Serial.println("d"); 72 | 73 | // calculate a date which is 7 days, 12 hours and 30 seconds into the future 74 | DateTime future (now + TimeSpan(7,12,30,6)); 75 | 76 | Serial.print(" now + 7d + 12h + 30m + 6s: "); 77 | Serial.print(future.year(), DEC); 78 | Serial.print('/'); 79 | Serial.print(future.month(), DEC); 80 | Serial.print('/'); 81 | Serial.print(future.day(), DEC); 82 | Serial.print(' '); 83 | Serial.print(future.hour(), DEC); 84 | Serial.print(':'); 85 | Serial.print(future.minute(), DEC); 86 | Serial.print(':'); 87 | Serial.print(future.second(), DEC); 88 | Serial.println(); 89 | 90 | Serial.println(); 91 | delay(3000); 92 | } 93 | -------------------------------------------------------------------------------- /examples/pcf8563_interrupt/pcf8563_interrupt.ino: -------------------------------------------------------------------------------- 1 | // Date and time functions using a PCF8563 RTC connected via I2C and Wire lib 2 | #include "RTClib.h" 3 | 4 | RTC_PCF8563 rtc; 5 | 6 | char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 7 | 8 | // use D2 for INT0; attach to CLKOUT pin on RTC 9 | const uint8_t INT_PIN = 2; 10 | 11 | // flag to update serial; set in interrupt callback 12 | volatile uint8_t tick_tock = 1; 13 | 14 | // INT0 interrupt callback; update tick_tock flag 15 | void set_tick_tock(void) { 16 | tick_tock = 1; 17 | } 18 | 19 | void setup () { 20 | Serial.begin(115200); 21 | 22 | #ifndef ESP8266 23 | while (!Serial); // wait for serial port to connect. Needed for native USB 24 | #endif 25 | 26 | 27 | pinMode(INT_PIN, INPUT); // set up interrupt pin 28 | digitalWrite(INT_PIN, HIGH); // turn on pullup resistors 29 | // attach interrupt to set_tick_tock callback on rising edge of INT0 30 | attachInterrupt(digitalPinToInterrupt(INT_PIN), set_tick_tock, RISING); 31 | 32 | if (! rtc.begin()) { 33 | Serial.println("Couldn't find RTC"); 34 | Serial.flush(); 35 | while (1) delay(10); 36 | } 37 | 38 | if (rtc.lostPower()) { 39 | Serial.println("RTC is NOT initialized, let's set the time!"); 40 | // When time needs to be set on a new device, or after a power loss, the 41 | // following line sets the RTC to the date & time this sketch was compiled 42 | rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 43 | // This line sets the RTC with an explicit date & time, for example to set 44 | // January 21, 2014 at 3am you would call: 45 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 46 | // 47 | // Note: allow 2 seconds after inserting battery or applying external power 48 | // without battery before calling adjust(). This gives the PCF8523's 49 | // crystal oscillator time to stabilize. If you call adjust() very quickly 50 | // after the RTC is powered, lostPower() may still return true. 51 | } 52 | 53 | 54 | 55 | // When time needs to be re-set on a previously configured device, the 56 | // following line sets the RTC to the date & time this sketch was compiled 57 | // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 58 | // This line sets the RTC with an explicit date & time, for example to set 59 | // January 21, 2014 at 3am you would call: 60 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 61 | 62 | // When the RTC was stopped and stays connected to the battery, it has 63 | // to be restarted by clearing the STOP bit. Let's do this to ensure 64 | // the RTC is running. 65 | rtc.start(); 66 | 67 | // turn on 1Hz clock out, used as INT0 for serial update every second 68 | rtc.writeSqwPinMode(PCF8563_SquareWave1Hz); 69 | } 70 | 71 | void loop () { 72 | 73 | // check if time display should be output 74 | if(tick_tock) { 75 | 76 | DateTime now = rtc.now(); 77 | 78 | char time_format[] = "hh:mm:ss AP"; 79 | char date_format[] = "MM/DD/YYYY"; 80 | 81 | Serial.println(now.toString(time_format)); 82 | Serial.println(now.toString(date_format)); 83 | Serial.println(); 84 | 85 | tick_tock = 0; 86 | 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /examples/softrtc/softrtc.ino: -------------------------------------------------------------------------------- 1 | // Date and time functions using just software, based on millis() & timer 2 | 3 | #include "RTClib.h" 4 | 5 | RTC_Millis rtc; 6 | 7 | void setup () { 8 | Serial.begin(57600); 9 | 10 | #ifndef ESP8266 11 | while (!Serial); // wait for serial port to connect. Needed for native USB 12 | #endif 13 | 14 | // following line sets the RTC to the date & time this sketch was compiled 15 | rtc.begin(DateTime(F(__DATE__), F(__TIME__))); 16 | // This line sets the RTC with an explicit date & time, for example to set 17 | // January 21, 2014 at 3am you would call: 18 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 19 | } 20 | 21 | void loop () { 22 | DateTime now = rtc.now(); 23 | 24 | Serial.print(now.year(), DEC); 25 | Serial.print('/'); 26 | Serial.print(now.month(), DEC); 27 | Serial.print('/'); 28 | Serial.print(now.day(), DEC); 29 | Serial.print(' '); 30 | Serial.print(now.hour(), DEC); 31 | Serial.print(':'); 32 | Serial.print(now.minute(), DEC); 33 | Serial.print(':'); 34 | Serial.print(now.second(), DEC); 35 | Serial.println(); 36 | 37 | Serial.print(" seconds since 1970: "); 38 | Serial.println(now.unixtime()); 39 | 40 | // calculate a date which is 7 days and 30 seconds into the future 41 | DateTime future (now.unixtime() + 7 * 86400L + 30); 42 | 43 | Serial.print(" now + 7d + 30s: "); 44 | Serial.print(future.year(), DEC); 45 | Serial.print('/'); 46 | Serial.print(future.month(), DEC); 47 | Serial.print('/'); 48 | Serial.print(future.day(), DEC); 49 | Serial.print(' '); 50 | Serial.print(future.hour(), DEC); 51 | Serial.print(':'); 52 | Serial.print(future.minute(), DEC); 53 | Serial.print(':'); 54 | Serial.print(future.second(), DEC); 55 | Serial.println(); 56 | 57 | Serial.println(); 58 | delay(3000); 59 | } 60 | -------------------------------------------------------------------------------- /examples/timestamp/timestamp.ino: -------------------------------------------------------------------------------- 1 | /* Timestamp functions using a DS1307 RTC connected via I2C and Wire lib 2 | ** 3 | ** Useful for file name 4 | ** ` SD.open(time.timestamp()+".log", FILE_WRITE) ` 5 | ** 6 | ** 7 | ** Created: 2015-06-01 by AxelTB 8 | ** Last Edit: 9 | */ 10 | 11 | #include "RTClib.h" 12 | 13 | RTC_DS1307 rtc; 14 | 15 | void setup () { 16 | Serial.begin(57600); 17 | 18 | #ifndef ESP8266 19 | while (!Serial); // wait for serial port to connect. Needed for native USB 20 | #endif 21 | 22 | if (! rtc.begin()) { 23 | Serial.println("Couldn't find RTC"); 24 | Serial.flush(); 25 | while (1) delay(10); 26 | } 27 | 28 | if (! rtc.isrunning()) { 29 | Serial.println("RTC is NOT running, let's set the time!"); 30 | // When time needs to be set on a new device, or after a power loss, the 31 | // following line sets the RTC to the date & time this sketch was compiled 32 | rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 33 | // This line sets the RTC with an explicit date & time, for example to set 34 | // January 21, 2014 at 3am you would call: 35 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 36 | } 37 | 38 | // When time needs to be re-set on a previously configured device, the 39 | // following line sets the RTC to the date & time this sketch was compiled 40 | // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 41 | // This line sets the RTC with an explicit date & time, for example to set 42 | // January 21, 2014 at 3am you would call: 43 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 44 | } 45 | 46 | void loop() { 47 | DateTime time = rtc.now(); 48 | 49 | //Full Timestamp 50 | Serial.println(String("DateTime::TIMESTAMP_FULL:\t")+time.timestamp(DateTime::TIMESTAMP_FULL)); 51 | 52 | //Date Only 53 | Serial.println(String("DateTime::TIMESTAMP_DATE:\t")+time.timestamp(DateTime::TIMESTAMP_DATE)); 54 | 55 | //Full Timestamp 56 | Serial.println(String("DateTime::TIMESTAMP_TIME:\t")+time.timestamp(DateTime::TIMESTAMP_TIME)); 57 | 58 | Serial.println("\n"); 59 | 60 | //Delay 5s 61 | delay(5000); 62 | } 63 | -------------------------------------------------------------------------------- /examples/toString/toString.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | RTC_DS1307 rtc; 5 | 6 | 7 | void setup () { 8 | Serial.begin(57600); 9 | 10 | #ifndef ESP8266 11 | while (!Serial); // wait for serial port to connect. Needed for native USB 12 | #endif 13 | 14 | if (! rtc.begin()) { 15 | Serial.println("Couldn't find RTC"); 16 | Serial.flush(); 17 | while (1) delay(10); 18 | } 19 | 20 | if (! rtc.isrunning()) { 21 | Serial.println("RTC is NOT running, let's set the time!"); 22 | // When time needs to be set on a new device, or after a power loss, the 23 | // following line sets the RTC to the date & time this sketch was compiled 24 | rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 25 | // This line sets the RTC with an explicit date & time, for example to set 26 | // January 21, 2014 at 3am you would call: 27 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 28 | } 29 | 30 | // When time needs to be re-set on a previously configured device, the 31 | // following line sets the RTC to the date & time this sketch was compiled 32 | // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 33 | // This line sets the RTC with an explicit date & time, for example to set 34 | // January 21, 2014 at 3am you would call: 35 | // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); 36 | } 37 | 38 | void loop() { 39 | 40 | DateTime now = rtc.now(); 41 | 42 | //buffer can be defined using following combinations: 43 | //hh - the hour with a leading zero (00 to 23) 44 | //mm - the minute with a leading zero (00 to 59) 45 | //ss - the whole second with a leading zero where applicable (00 to 59) 46 | //YYYY - the year as four digit number 47 | //YY - the year as two digit number (00-99) 48 | //MM - the month as number with a leading zero (01-12) 49 | //MMM - the abbreviated English month name ('Jan' to 'Dec') 50 | //DD - the day as number with a leading zero (01 to 31) 51 | //DDD - the abbreviated English day name ('Mon' to 'Sun') 52 | 53 | char buf1[] = "hh:mm"; 54 | Serial.println(now.toString(buf1)); 55 | 56 | char buf2[] = "YYMMDD-hh:mm:ss"; 57 | Serial.println(now.toString(buf2)); 58 | 59 | char buf3[] = "Today is DDD, MMM DD YYYY"; 60 | Serial.println(now.toString(buf3)); 61 | 62 | char buf4[] = "MM-DD-YYYY"; 63 | Serial.println(now.toString(buf4)); 64 | 65 | delay(1000); 66 | } 67 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For RTClib 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | DateTime KEYWORD1 10 | TimeSpan KEYWORD1 11 | RTC_DS1307 KEYWORD1 12 | RTC_DS3231 KEYWORD1 13 | RTC_PCF8523 KEYWORD1 14 | RTC_PCF8563 KEYWORD1 15 | RTC_Millis KEYWORD1 16 | RTC_Micros KEYWORD1 17 | Ds1307SqwPinMode KEYWORD1 18 | Ds3231SqwPinMode KEYWORD1 19 | Ds3231Alarm1Mode KEYWORD1 20 | Ds3231Alarm2Mode KEYWORD1 21 | Pcf8523SqwPinMode KEYWORD1 22 | PCF8523TimerClockFreq KEYWORD1 23 | PCF8523TimerIntPulse KEYWORD1 24 | Pcf8523OffsetMode KEYWORD1 25 | Pcf8563SqwPinMode KEYWORD1 26 | 27 | ####################################### 28 | # Methods and Functions (KEYWORD2) 29 | ####################################### 30 | 31 | isValid KEYWORD2 32 | year KEYWORD2 33 | month KEYWORD2 34 | day KEYWORD2 35 | hour KEYWORD2 36 | twelveHour KEYWORD2 37 | isPM KEYWORD2 38 | minute KEYWORD2 39 | second KEYWORD2 40 | dayOfTheWeek KEYWORD2 41 | secondstime KEYWORD2 42 | unixtime KEYWORD2 43 | days KEYWORD2 44 | hours KEYWORD2 45 | minutes KEYWORD2 46 | seconds KEYWORD2 47 | totalseconds KEYWORD2 48 | begin KEYWORD2 49 | adjust KEYWORD2 50 | adjustDrift KEYWORD2 51 | isrunning KEYWORD2 52 | now KEYWORD2 53 | readSqwPinMode KEYWORD2 54 | writeSqwPinMode KEYWORD2 55 | timestamp KEYWORD2 56 | toString KEYWORD2 57 | readnvram KEYWORD2 58 | writenvram KEYWORD2 59 | setAlarm1 KEYWORD2 60 | setAlarm2 KEYWORD2 61 | disableAlarm KEYWORD2 62 | clearAlarm KEYWORD2 63 | alarmFired KEYWORD2 64 | getTemperature KEYWORD2 65 | lostPower KEYWORD2 66 | initialized KEYWORD2 67 | enableSecondTimer KEYWORD2 68 | disableSecondTimer KEYWORD2 69 | enableCountdownTimer KEYWORD2 70 | disableCountdownTimer KEYWORD2 71 | deconfigureAllTimers KEYWORD2 72 | calibrate KEYWORD2 73 | enable32K KEYWORD2 74 | disable32K KEYWORD2 75 | isEnabled32K KEYWORD2 76 | 77 | ####################################### 78 | # Constants (LITERAL1) 79 | ####################################### 80 | TIMESTAMP_FULL LITERAL1 81 | TIMESTAMP_DATE LITERAL1 82 | TIMESTAMP_TIME LITERAL1 83 | 84 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=RTClib 2 | version=2.1.4 3 | author=Adafruit 4 | maintainer=Adafruit 5 | sentence=A fork of Jeelab's fantastic RTC library 6 | paragraph=Works with DS1307, DS3231, PCF8523, PCF8563 on multiple architectures 7 | category=Timing 8 | url=https://github.com/adafruit/RTClib 9 | architectures=* 10 | depends=Adafruit BusIO 11 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Adafruit Industries 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/RTC_DS1307.cpp: -------------------------------------------------------------------------------- 1 | #include "RTClib.h" 2 | 3 | #define DS1307_ADDRESS 0x68 ///< I2C address for DS1307 4 | #define DS1307_CONTROL 0x07 ///< Control register 5 | #define DS1307_NVRAM 0x08 ///< Start of RAM registers - 56 bytes, 0x08 to 0x3f 6 | 7 | /**************************************************************************/ 8 | /*! 9 | @brief Start I2C for the DS1307 and test succesful connection 10 | @param wireInstance pointer to the I2C bus 11 | @return True if Wire can find DS1307 or false otherwise. 12 | */ 13 | /**************************************************************************/ 14 | bool RTC_DS1307::begin(TwoWire *wireInstance) { 15 | if (i2c_dev) 16 | delete i2c_dev; 17 | i2c_dev = new Adafruit_I2CDevice(DS1307_ADDRESS, wireInstance); 18 | if (!i2c_dev->begin()) 19 | return false; 20 | return true; 21 | } 22 | 23 | /**************************************************************************/ 24 | /*! 25 | @brief Is the DS1307 running? Check the Clock Halt bit in register 0 26 | @return 1 if the RTC is running, 0 if not 27 | */ 28 | /**************************************************************************/ 29 | uint8_t RTC_DS1307::isrunning(void) { return !(read_register(0) >> 7); } 30 | 31 | /**************************************************************************/ 32 | /*! 33 | @brief Set the date and time in the DS1307 34 | @param dt DateTime object containing the desired date/time 35 | */ 36 | /**************************************************************************/ 37 | void RTC_DS1307::adjust(const DateTime &dt) { 38 | uint8_t buffer[8] = {0, 39 | bin2bcd(dt.second()), 40 | bin2bcd(dt.minute()), 41 | bin2bcd(dt.hour()), 42 | 0, 43 | bin2bcd(dt.day()), 44 | bin2bcd(dt.month()), 45 | bin2bcd(dt.year() - 2000U)}; 46 | i2c_dev->write(buffer, 8); 47 | } 48 | 49 | /**************************************************************************/ 50 | /*! 51 | @brief Get the current date and time from the DS1307 52 | @return DateTime object containing the current date and time 53 | */ 54 | /**************************************************************************/ 55 | DateTime RTC_DS1307::now() { 56 | uint8_t buffer[7]; 57 | buffer[0] = 0; 58 | i2c_dev->write_then_read(buffer, 1, buffer, 7); 59 | 60 | return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5]), 61 | bcd2bin(buffer[4]), bcd2bin(buffer[2]), bcd2bin(buffer[1]), 62 | bcd2bin(buffer[0] & 0x7F)); 63 | } 64 | 65 | /**************************************************************************/ 66 | /*! 67 | @brief Read the current mode of the SQW pin 68 | @return Mode as Ds1307SqwPinMode enum 69 | */ 70 | /**************************************************************************/ 71 | Ds1307SqwPinMode RTC_DS1307::readSqwPinMode() { 72 | return static_cast(read_register(DS1307_CONTROL) & 0x93); 73 | } 74 | 75 | /**************************************************************************/ 76 | /*! 77 | @brief Change the SQW pin mode 78 | @param mode The mode to use 79 | */ 80 | /**************************************************************************/ 81 | void RTC_DS1307::writeSqwPinMode(Ds1307SqwPinMode mode) { 82 | write_register(DS1307_CONTROL, mode); 83 | } 84 | 85 | /**************************************************************************/ 86 | /*! 87 | @brief Read data from the DS1307's NVRAM 88 | @param buf Pointer to a buffer to store the data - make sure it's large 89 | enough to hold size bytes 90 | @param size Number of bytes to read 91 | @param address Starting NVRAM address, from 0 to 55 92 | */ 93 | /**************************************************************************/ 94 | void RTC_DS1307::readnvram(uint8_t *buf, uint8_t size, uint8_t address) { 95 | uint8_t addrByte = DS1307_NVRAM + address; 96 | i2c_dev->write_then_read(&addrByte, 1, buf, size); 97 | } 98 | 99 | /**************************************************************************/ 100 | /*! 101 | @brief Write data to the DS1307 NVRAM 102 | @param address Starting NVRAM address, from 0 to 55 103 | @param buf Pointer to buffer containing the data to write 104 | @param size Number of bytes in buf to write to NVRAM 105 | */ 106 | /**************************************************************************/ 107 | void RTC_DS1307::writenvram(uint8_t address, const uint8_t *buf, uint8_t size) { 108 | uint8_t addrByte = DS1307_NVRAM + address; 109 | i2c_dev->write(buf, size, true, &addrByte, 1); 110 | } 111 | 112 | /**************************************************************************/ 113 | /*! 114 | @brief Shortcut to read one byte from NVRAM 115 | @param address NVRAM address, 0 to 55 116 | @return The byte read from NVRAM 117 | */ 118 | /**************************************************************************/ 119 | uint8_t RTC_DS1307::readnvram(uint8_t address) { 120 | uint8_t data; 121 | readnvram(&data, 1, address); 122 | return data; 123 | } 124 | 125 | /**************************************************************************/ 126 | /*! 127 | @brief Shortcut to write one byte to NVRAM 128 | @param address NVRAM address, 0 to 55 129 | @param data One byte to write 130 | */ 131 | /**************************************************************************/ 132 | void RTC_DS1307::writenvram(uint8_t address, uint8_t data) { 133 | writenvram(address, &data, 1); 134 | } 135 | -------------------------------------------------------------------------------- /src/RTC_DS3231.cpp: -------------------------------------------------------------------------------- 1 | #include "RTClib.h" 2 | 3 | #define DS3231_ADDRESS 0x68 ///< I2C address for DS3231 4 | #define DS3231_TIME 0x00 ///< Time register 5 | #define DS3231_ALARM1 0x07 ///< Alarm 1 register 6 | #define DS3231_ALARM2 0x0B ///< Alarm 2 register 7 | #define DS3231_CONTROL 0x0E ///< Control register 8 | #define DS3231_STATUSREG 0x0F ///< Status register 9 | #define DS3231_TEMPERATUREREG \ 10 | 0x11 ///< Temperature register (high byte - low byte is at 0x12), 10-bit 11 | ///< temperature value 12 | 13 | /**************************************************************************/ 14 | /*! 15 | @brief Start I2C for the DS3231 and test succesful connection 16 | @param wireInstance pointer to the I2C bus 17 | @return True if Wire can find DS3231 or false otherwise. 18 | */ 19 | /**************************************************************************/ 20 | bool RTC_DS3231::begin(TwoWire *wireInstance) { 21 | if (i2c_dev) 22 | delete i2c_dev; 23 | i2c_dev = new Adafruit_I2CDevice(DS3231_ADDRESS, wireInstance); 24 | if (!i2c_dev->begin()) 25 | return false; 26 | return true; 27 | } 28 | 29 | /**************************************************************************/ 30 | /*! 31 | @brief Check the status register Oscillator Stop Flag to see if the DS3231 32 | stopped due to power loss 33 | @return True if the bit is set (oscillator stopped) or false if it is 34 | running 35 | */ 36 | /**************************************************************************/ 37 | bool RTC_DS3231::lostPower(void) { 38 | return read_register(DS3231_STATUSREG) >> 7; 39 | } 40 | 41 | /**************************************************************************/ 42 | /*! 43 | @brief Set the date and flip the Oscillator Stop Flag 44 | @param dt DateTime object containing the date/time to set 45 | */ 46 | /**************************************************************************/ 47 | void RTC_DS3231::adjust(const DateTime &dt) { 48 | uint8_t buffer[8] = {DS3231_TIME, 49 | bin2bcd(dt.second()), 50 | bin2bcd(dt.minute()), 51 | bin2bcd(dt.hour()), 52 | bin2bcd(dowToDS3231(dt.dayOfTheWeek())), 53 | bin2bcd(dt.day()), 54 | bin2bcd(dt.month()), 55 | bin2bcd(dt.year() - 2000U)}; 56 | i2c_dev->write(buffer, 8); 57 | 58 | uint8_t statreg = read_register(DS3231_STATUSREG); 59 | statreg &= ~0x80; // flip OSF bit 60 | write_register(DS3231_STATUSREG, statreg); 61 | } 62 | 63 | /**************************************************************************/ 64 | /*! 65 | @brief Get the current date/time 66 | @return DateTime object with the current date/time 67 | */ 68 | /**************************************************************************/ 69 | DateTime RTC_DS3231::now() { 70 | uint8_t buffer[7]; 71 | buffer[0] = 0; 72 | i2c_dev->write_then_read(buffer, 1, buffer, 7); 73 | 74 | return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5] & 0x7F), 75 | bcd2bin(buffer[4]), bcd2bin(buffer[2]), bcd2bin(buffer[1]), 76 | bcd2bin(buffer[0] & 0x7F)); 77 | } 78 | 79 | /**************************************************************************/ 80 | /*! 81 | @brief Read the SQW pin mode 82 | @return Pin mode, see Ds3231SqwPinMode enum 83 | */ 84 | /**************************************************************************/ 85 | Ds3231SqwPinMode RTC_DS3231::readSqwPinMode() { 86 | int mode; 87 | mode = read_register(DS3231_CONTROL) & 0x1C; 88 | if (mode & 0x04) 89 | mode = DS3231_OFF; 90 | return static_cast(mode); 91 | } 92 | 93 | /**************************************************************************/ 94 | /*! 95 | @brief Set the SQW pin mode 96 | @param mode Desired mode, see Ds3231SqwPinMode enum 97 | */ 98 | /**************************************************************************/ 99 | void RTC_DS3231::writeSqwPinMode(Ds3231SqwPinMode mode) { 100 | uint8_t ctrl = read_register(DS3231_CONTROL); 101 | 102 | ctrl &= ~0x04; // turn off INTCON 103 | ctrl &= ~0x18; // set freq bits to 0 104 | 105 | write_register(DS3231_CONTROL, ctrl | mode); 106 | } 107 | 108 | /**************************************************************************/ 109 | /*! 110 | @brief Get the current temperature from the DS3231's temperature sensor 111 | @return Current temperature (float) 112 | */ 113 | /**************************************************************************/ 114 | float RTC_DS3231::getTemperature() { 115 | uint8_t buffer[2] = {DS3231_TEMPERATUREREG, 0}; 116 | i2c_dev->write_then_read(buffer, 1, buffer, 2); 117 | return (float)buffer[0] + (buffer[1] >> 6) * 0.25f; 118 | } 119 | 120 | /**************************************************************************/ 121 | /*! 122 | @brief Set alarm 1 for DS3231 123 | @param dt DateTime object 124 | @param alarm_mode Desired mode, see Ds3231Alarm1Mode enum 125 | @return False if control register is not set, otherwise true 126 | */ 127 | /**************************************************************************/ 128 | bool RTC_DS3231::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) { 129 | uint8_t ctrl = read_register(DS3231_CONTROL); 130 | if (!(ctrl & 0x04)) { 131 | return false; 132 | } 133 | 134 | uint8_t A1M1 = (alarm_mode & 0x01) << 7; // Seconds bit 7. 135 | uint8_t A1M2 = (alarm_mode & 0x02) << 6; // Minutes bit 7. 136 | uint8_t A1M3 = (alarm_mode & 0x04) << 5; // Hour bit 7. 137 | uint8_t A1M4 = (alarm_mode & 0x08) << 4; // Day/Date bit 7. 138 | uint8_t DY_DT = (alarm_mode & 0x10) 139 | << 2; // Day/Date bit 6. Date when 0, day of week when 1. 140 | uint8_t day = (DY_DT) ? dowToDS3231(dt.dayOfTheWeek()) : dt.day(); 141 | 142 | uint8_t buffer[5] = {DS3231_ALARM1, uint8_t(bin2bcd(dt.second()) | A1M1), 143 | uint8_t(bin2bcd(dt.minute()) | A1M2), 144 | uint8_t(bin2bcd(dt.hour()) | A1M3), 145 | uint8_t(bin2bcd(day) | A1M4 | DY_DT)}; 146 | i2c_dev->write(buffer, 5); 147 | 148 | write_register(DS3231_CONTROL, ctrl | 0x01); // AI1E 149 | 150 | return true; 151 | } 152 | 153 | /**************************************************************************/ 154 | /*! 155 | @brief Set alarm 2 for DS3231 156 | @param dt DateTime object 157 | @param alarm_mode Desired mode, see Ds3231Alarm2Mode enum 158 | @return False if control register is not set, otherwise true 159 | */ 160 | /**************************************************************************/ 161 | bool RTC_DS3231::setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode) { 162 | uint8_t ctrl = read_register(DS3231_CONTROL); 163 | if (!(ctrl & 0x04)) { 164 | return false; 165 | } 166 | 167 | uint8_t A2M2 = (alarm_mode & 0x01) << 7; // Minutes bit 7. 168 | uint8_t A2M3 = (alarm_mode & 0x02) << 6; // Hour bit 7. 169 | uint8_t A2M4 = (alarm_mode & 0x04) << 5; // Day/Date bit 7. 170 | uint8_t DY_DT = (alarm_mode & 0x08) 171 | << 3; // Day/Date bit 6. Date when 0, day of week when 1. 172 | uint8_t day = (DY_DT) ? dowToDS3231(dt.dayOfTheWeek()) : dt.day(); 173 | 174 | uint8_t buffer[4] = {DS3231_ALARM2, uint8_t(bin2bcd(dt.minute()) | A2M2), 175 | uint8_t(bin2bcd(dt.hour()) | A2M3), 176 | uint8_t(bin2bcd(day) | A2M4 | DY_DT)}; 177 | i2c_dev->write(buffer, 4); 178 | 179 | write_register(DS3231_CONTROL, ctrl | 0x02); // AI2E 180 | 181 | return true; 182 | } 183 | 184 | /**************************************************************************/ 185 | /*! 186 | @brief Get the date/time value of Alarm1 187 | @return DateTime object with the Alarm1 data set in the 188 | day, hour, minutes, and seconds fields 189 | */ 190 | /**************************************************************************/ 191 | DateTime RTC_DS3231::getAlarm1() { 192 | uint8_t buffer[5] = {DS3231_ALARM1, 0, 0, 0, 0}; 193 | i2c_dev->write_then_read(buffer, 1, buffer, 5); 194 | 195 | uint8_t seconds = bcd2bin(buffer[0] & 0x7F); 196 | uint8_t minutes = bcd2bin(buffer[1] & 0x7F); 197 | // Fetching the hour assumes 24 hour time (never 12) 198 | // because this library exclusively stores the time 199 | // in 24 hour format. Note that the DS3231 supports 200 | // 12 hour storage, and sets bits to indicate the type 201 | // that is stored. 202 | uint8_t hour = bcd2bin(buffer[2] & 0x3F); 203 | 204 | // Determine if the alarm is set to fire based on the 205 | // day of the week, or an explicit date match. 206 | bool isDayOfWeek = (buffer[3] & 0x40) >> 6; 207 | uint8_t day; 208 | if (isDayOfWeek) { 209 | // Alarm set to match on day of the week 210 | day = bcd2bin(buffer[3] & 0x0F); 211 | } else { 212 | // Alarm set to match on day of the month 213 | day = bcd2bin(buffer[3] & 0x3F); 214 | } 215 | 216 | // On the first week of May 2000, the day-of-the-week number 217 | // matches the date number. 218 | return DateTime(2000, 5, day, hour, minutes, seconds); 219 | } 220 | 221 | /**************************************************************************/ 222 | /*! 223 | @brief Get the date/time value of Alarm2 224 | @return DateTime object with the Alarm2 data set in the 225 | day, hour, and minutes fields 226 | */ 227 | /**************************************************************************/ 228 | DateTime RTC_DS3231::getAlarm2() { 229 | uint8_t buffer[4] = {DS3231_ALARM2, 0, 0, 0}; 230 | i2c_dev->write_then_read(buffer, 1, buffer, 4); 231 | 232 | uint8_t minutes = bcd2bin(buffer[0] & 0x7F); 233 | // Fetching the hour assumes 24 hour time (never 12) 234 | // because this library exclusively stores the time 235 | // in 24 hour format. Note that the DS3231 supports 236 | // 12 hour storage, and sets bits to indicate the type 237 | // that is stored. 238 | uint8_t hour = bcd2bin(buffer[1] & 0x3F); 239 | 240 | // Determine if the alarm is set to fire based on the 241 | // day of the week, or an explicit date match. 242 | bool isDayOfWeek = (buffer[2] & 0x40) >> 6; 243 | uint8_t day; 244 | if (isDayOfWeek) { 245 | // Alarm set to match on day of the week 246 | day = bcd2bin(buffer[2] & 0x0F); 247 | } else { 248 | // Alarm set to match on day of the month 249 | day = bcd2bin(buffer[2] & 0x3F); 250 | } 251 | 252 | // On the first week of May 2000, the day-of-the-week number 253 | // matches the date number. 254 | return DateTime(2000, 5, day, hour, minutes, 0); 255 | } 256 | 257 | /**************************************************************************/ 258 | /*! 259 | @brief Get the mode for Alarm1 260 | @return Ds3231Alarm1Mode enum value for the current Alarm1 mode 261 | */ 262 | /**************************************************************************/ 263 | Ds3231Alarm1Mode RTC_DS3231::getAlarm1Mode() { 264 | uint8_t buffer[5] = {DS3231_ALARM1, 0, 0, 0, 0}; 265 | i2c_dev->write_then_read(buffer, 1, buffer, 5); 266 | 267 | uint8_t alarm_mode = (buffer[0] & 0x80) >> 7 // A1M1 - Seconds bit 268 | | (buffer[1] & 0x80) >> 6 // A1M2 - Minutes bit 269 | | (buffer[2] & 0x80) >> 5 // A1M3 - Hour bit 270 | | (buffer[3] & 0x80) >> 4 // A1M4 - Day/Date bit 271 | | (buffer[3] & 0x40) >> 2; // DY_DT 272 | 273 | // Determine which mode the fetched alarm bits map to 274 | switch (alarm_mode) { 275 | case DS3231_A1_PerSecond: 276 | case DS3231_A1_Second: 277 | case DS3231_A1_Minute: 278 | case DS3231_A1_Hour: 279 | case DS3231_A1_Date: 280 | case DS3231_A1_Day: 281 | return (Ds3231Alarm1Mode)alarm_mode; 282 | default: 283 | // Default if the alarm mode cannot be read 284 | return DS3231_A1_Date; 285 | } 286 | } 287 | 288 | /**************************************************************************/ 289 | /*! 290 | @brief Get the mode for Alarm2 291 | @return Ds3231Alarm2Mode enum value for the current Alarm2 mode 292 | */ 293 | /**************************************************************************/ 294 | Ds3231Alarm2Mode RTC_DS3231::getAlarm2Mode() { 295 | uint8_t buffer[4] = {DS3231_ALARM2, 0, 0, 0}; 296 | i2c_dev->write_then_read(buffer, 1, buffer, 4); 297 | 298 | uint8_t alarm_mode = (buffer[0] & 0x80) >> 7 // A2M2 - Minutes bit 299 | | (buffer[1] & 0x80) >> 6 // A2M3 - Hour bit 300 | | (buffer[2] & 0x80) >> 5 // A2M4 - Day/Date bit 301 | | (buffer[2] & 0x40) >> 3; // DY_DT 302 | 303 | // Determine which mode the fetched alarm bits map to 304 | switch (alarm_mode) { 305 | case DS3231_A2_PerMinute: 306 | case DS3231_A2_Minute: 307 | case DS3231_A2_Hour: 308 | case DS3231_A2_Date: 309 | case DS3231_A2_Day: 310 | return (Ds3231Alarm2Mode)alarm_mode; 311 | default: 312 | // Default if the alarm mode cannot be read 313 | return DS3231_A2_Date; 314 | } 315 | } 316 | 317 | /**************************************************************************/ 318 | /*! 319 | @brief Disable alarm 320 | @param alarm_num Alarm number to disable 321 | */ 322 | /**************************************************************************/ 323 | void RTC_DS3231::disableAlarm(uint8_t alarm_num) { 324 | uint8_t ctrl = read_register(DS3231_CONTROL); 325 | ctrl &= ~(1 << (alarm_num - 1)); 326 | write_register(DS3231_CONTROL, ctrl); 327 | } 328 | 329 | /**************************************************************************/ 330 | /*! 331 | @brief Clear status of alarm 332 | @param alarm_num Alarm number to clear 333 | */ 334 | /**************************************************************************/ 335 | void RTC_DS3231::clearAlarm(uint8_t alarm_num) { 336 | uint8_t status = read_register(DS3231_STATUSREG); 337 | status &= ~(0x1 << (alarm_num - 1)); 338 | write_register(DS3231_STATUSREG, status); 339 | } 340 | 341 | /**************************************************************************/ 342 | /*! 343 | @brief Get status of alarm 344 | @param alarm_num Alarm number to check status of 345 | @return True if alarm has been fired otherwise false 346 | */ 347 | /**************************************************************************/ 348 | bool RTC_DS3231::alarmFired(uint8_t alarm_num) { 349 | return (read_register(DS3231_STATUSREG) >> (alarm_num - 1)) & 0x1; 350 | } 351 | 352 | /**************************************************************************/ 353 | /*! 354 | @brief Enable 32KHz Output 355 | @details The 32kHz output is enabled by default. It requires an external 356 | pull-up resistor to function correctly 357 | */ 358 | /**************************************************************************/ 359 | void RTC_DS3231::enable32K(void) { 360 | uint8_t status = read_register(DS3231_STATUSREG); 361 | status |= (0x1 << 0x03); 362 | write_register(DS3231_STATUSREG, status); 363 | } 364 | 365 | /**************************************************************************/ 366 | /*! 367 | @brief Disable 32KHz Output 368 | */ 369 | /**************************************************************************/ 370 | void RTC_DS3231::disable32K(void) { 371 | uint8_t status = read_register(DS3231_STATUSREG); 372 | status &= ~(0x1 << 0x03); 373 | write_register(DS3231_STATUSREG, status); 374 | } 375 | 376 | /**************************************************************************/ 377 | /*! 378 | @brief Get status of 32KHz Output 379 | @return True if enabled otherwise false 380 | */ 381 | /**************************************************************************/ 382 | bool RTC_DS3231::isEnabled32K(void) { 383 | return (read_register(DS3231_STATUSREG) >> 0x03) & 0x01; 384 | } 385 | -------------------------------------------------------------------------------- /src/RTC_Micros.cpp: -------------------------------------------------------------------------------- 1 | #include "RTClib.h" 2 | 3 | /**************************************************************************/ 4 | /*! 5 | @brief Set the current date/time of the RTC_Micros clock. 6 | @param dt DateTime object with the desired date and time 7 | */ 8 | /**************************************************************************/ 9 | void RTC_Micros::adjust(const DateTime &dt) { 10 | lastMicros = micros(); 11 | lastUnix = dt.unixtime(); 12 | } 13 | 14 | /**************************************************************************/ 15 | /*! 16 | @brief Adjust the RTC_Micros clock to compensate for system clock drift 17 | @param ppm Adjustment to make. A positive adjustment makes the clock faster. 18 | */ 19 | /**************************************************************************/ 20 | void RTC_Micros::adjustDrift(int ppm) { microsPerSecond = 1000000 - ppm; } 21 | 22 | /**************************************************************************/ 23 | /*! 24 | @brief Get the current date/time from the RTC_Micros clock. 25 | @return DateTime object containing the current date/time 26 | */ 27 | /**************************************************************************/ 28 | DateTime RTC_Micros::now() { 29 | uint32_t elapsedSeconds = (micros() - lastMicros) / microsPerSecond; 30 | lastMicros += elapsedSeconds * microsPerSecond; 31 | lastUnix += elapsedSeconds; 32 | return lastUnix; 33 | } 34 | -------------------------------------------------------------------------------- /src/RTC_Millis.cpp: -------------------------------------------------------------------------------- 1 | #include "RTClib.h" 2 | 3 | /**************************************************************************/ 4 | /*! 5 | @brief Set the current date/time of the RTC_Millis clock. 6 | @param dt DateTime object with the desired date and time 7 | */ 8 | /**************************************************************************/ 9 | void RTC_Millis::adjust(const DateTime &dt) { 10 | lastMillis = millis(); 11 | lastUnix = dt.unixtime(); 12 | } 13 | 14 | /**************************************************************************/ 15 | /*! 16 | @brief Return a DateTime object containing the current date/time. 17 | Note that computing (millis() - lastMillis) is rollover-safe as long 18 | as this method is called at least once every 49.7 days. 19 | @return DateTime object containing current time 20 | */ 21 | /**************************************************************************/ 22 | DateTime RTC_Millis::now() { 23 | uint32_t elapsedSeconds = (millis() - lastMillis) / 1000; 24 | lastMillis += elapsedSeconds * 1000; 25 | lastUnix += elapsedSeconds; 26 | return lastUnix; 27 | } 28 | -------------------------------------------------------------------------------- /src/RTC_PCF8523.cpp: -------------------------------------------------------------------------------- 1 | #include "RTClib.h" 2 | 3 | #define PCF8523_ADDRESS 0x68 ///< I2C address for PCF8523 4 | #define PCF8523_CLKOUTCONTROL 0x0F ///< Timer and CLKOUT control register 5 | #define PCF8523_CONTROL_1 0x00 ///< Control and status register 1 6 | #define PCF8523_CONTROL_2 0x01 ///< Control and status register 2 7 | #define PCF8523_CONTROL_3 0x02 ///< Control and status register 3 8 | #define PCF8523_TIMER_B_FRCTL 0x12 ///< Timer B source clock frequency control 9 | #define PCF8523_TIMER_B_VALUE 0x13 ///< Timer B value (number clock periods) 10 | #define PCF8523_OFFSET 0x0E ///< Offset register 11 | #define PCF8523_STATUSREG 0x03 ///< Status register 12 | 13 | /**************************************************************************/ 14 | /*! 15 | @brief Start I2C for the PCF8523 and test succesful connection 16 | @param wireInstance pointer to the I2C bus 17 | @return True if Wire can find PCF8523 or false otherwise. 18 | */ 19 | /**************************************************************************/ 20 | bool RTC_PCF8523::begin(TwoWire *wireInstance) { 21 | if (i2c_dev) 22 | delete i2c_dev; 23 | i2c_dev = new Adafruit_I2CDevice(PCF8523_ADDRESS, wireInstance); 24 | if (!i2c_dev->begin()) 25 | return false; 26 | return true; 27 | } 28 | 29 | /**************************************************************************/ 30 | /*! 31 | @brief Check the status register Oscillator Stop flag to see if the PCF8523 32 | stopped due to power loss 33 | @details When battery or external power is first applied, the PCF8523's 34 | crystal oscillator takes up to 2s to stabilize. During this time adjust() 35 | cannot clear the 'OS' flag. See datasheet OS flag section for details. 36 | @return True if the bit is set (oscillator is or has stopped) and false only 37 | after the bit is cleared, for instance with adjust() 38 | */ 39 | /**************************************************************************/ 40 | bool RTC_PCF8523::lostPower(void) { 41 | return read_register(PCF8523_STATUSREG) >> 7; 42 | } 43 | 44 | /**************************************************************************/ 45 | /*! 46 | @brief Check control register 3 to see if we've run adjust() yet (setting 47 | the date/time and battery switchover mode) 48 | @return True if the PCF8523 has been set up, false if not 49 | */ 50 | /**************************************************************************/ 51 | bool RTC_PCF8523::initialized(void) { 52 | return (read_register(PCF8523_CONTROL_3) & 0xE0) != 0xE0; 53 | } 54 | 55 | /**************************************************************************/ 56 | /*! 57 | @brief Set the date and time, set battery switchover mode 58 | @param dt DateTime to set 59 | */ 60 | /**************************************************************************/ 61 | void RTC_PCF8523::adjust(const DateTime &dt) { 62 | uint8_t buffer[8] = {3, // start at location 3 63 | bin2bcd(dt.second()), 64 | bin2bcd(dt.minute()), 65 | bin2bcd(dt.hour()), 66 | bin2bcd(dt.day()), 67 | bin2bcd(0), // skip weekdays 68 | bin2bcd(dt.month()), 69 | bin2bcd(dt.year() - 2000U)}; 70 | i2c_dev->write(buffer, 8); 71 | 72 | // set to battery switchover mode 73 | write_register(PCF8523_CONTROL_3, 0x00); 74 | } 75 | 76 | /**************************************************************************/ 77 | /*! 78 | @brief Get the current date/time 79 | @return DateTime object containing the current date/time 80 | */ 81 | /**************************************************************************/ 82 | DateTime RTC_PCF8523::now() { 83 | uint8_t buffer[7]; 84 | buffer[0] = 3; 85 | i2c_dev->write_then_read(buffer, 1, buffer, 7); 86 | 87 | return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5]), 88 | bcd2bin(buffer[3]), bcd2bin(buffer[2]), bcd2bin(buffer[1]), 89 | bcd2bin(buffer[0] & 0x7F)); 90 | } 91 | 92 | /**************************************************************************/ 93 | /*! 94 | @brief Resets the STOP bit in register Control_1 95 | */ 96 | /**************************************************************************/ 97 | void RTC_PCF8523::start(void) { 98 | uint8_t ctlreg = read_register(PCF8523_CONTROL_1); 99 | if (ctlreg & (1 << 5)) 100 | write_register(PCF8523_CONTROL_1, ctlreg & ~(1 << 5)); 101 | } 102 | 103 | /**************************************************************************/ 104 | /*! 105 | @brief Sets the STOP bit in register Control_1 106 | */ 107 | /**************************************************************************/ 108 | void RTC_PCF8523::stop(void) { 109 | write_register(PCF8523_CONTROL_1, 110 | read_register(PCF8523_CONTROL_1) | (1 << 5)); 111 | } 112 | 113 | /**************************************************************************/ 114 | /*! 115 | @brief Is the PCF8523 running? Check the STOP bit in register Control_1 116 | @return 1 if the RTC is running, 0 if not 117 | */ 118 | /**************************************************************************/ 119 | uint8_t RTC_PCF8523::isrunning() { 120 | return !((read_register(PCF8523_CONTROL_1) >> 5) & 1); 121 | } 122 | 123 | /**************************************************************************/ 124 | /*! 125 | @brief Read the mode of the INT/SQW pin on the PCF8523 126 | @return SQW pin mode as a #Pcf8523SqwPinMode enum 127 | */ 128 | /**************************************************************************/ 129 | Pcf8523SqwPinMode RTC_PCF8523::readSqwPinMode() { 130 | int mode = read_register(PCF8523_CLKOUTCONTROL); 131 | mode >>= 3; 132 | mode &= 0x7; 133 | return static_cast(mode); 134 | } 135 | 136 | /**************************************************************************/ 137 | /*! 138 | @brief Set the INT/SQW pin mode on the PCF8523 139 | @param mode The mode to set, see the #Pcf8523SqwPinMode enum for options 140 | */ 141 | /**************************************************************************/ 142 | void RTC_PCF8523::writeSqwPinMode(Pcf8523SqwPinMode mode) { 143 | write_register(PCF8523_CLKOUTCONTROL, mode << 3); 144 | } 145 | 146 | /**************************************************************************/ 147 | /*! 148 | @brief Enable the Second Timer (1Hz) Interrupt on the PCF8523. 149 | @details The INT/SQW pin will pull low for a brief pulse once per second. 150 | */ 151 | /**************************************************************************/ 152 | void RTC_PCF8523::enableSecondTimer() { 153 | uint8_t ctlreg = read_register(PCF8523_CONTROL_1); 154 | uint8_t clkreg = read_register(PCF8523_CLKOUTCONTROL); 155 | // TAM pulse int. mode (shared with Timer A), CLKOUT (aka SQW) disabled 156 | write_register(PCF8523_CLKOUTCONTROL, clkreg | 0xB8); 157 | // SIE Second timer int. enable 158 | write_register(PCF8523_CONTROL_1, ctlreg | (1 << 2)); 159 | } 160 | 161 | /**************************************************************************/ 162 | /*! 163 | @brief Disable the Second Timer (1Hz) Interrupt on the PCF8523. 164 | */ 165 | /**************************************************************************/ 166 | void RTC_PCF8523::disableSecondTimer() { 167 | write_register(PCF8523_CONTROL_1, 168 | read_register(PCF8523_CONTROL_1) & ~(1 << 2)); 169 | } 170 | 171 | /**************************************************************************/ 172 | /*! 173 | @brief Enable the Countdown Timer Interrupt on the PCF8523. 174 | @details The INT/SQW pin will be pulled low at the end of a specified 175 | countdown period ranging from 244 microseconds to 10.625 days. 176 | Uses PCF8523 Timer B. Any existing CLKOUT square wave, configured with 177 | writeSqwPinMode(), will halt. The interrupt low pulse width is adjustable 178 | from 3/64ths (default) to 14/64ths of a second. 179 | @param clkFreq One of the PCF8523's Timer Source Clock Frequencies. 180 | See the #PCF8523TimerClockFreq enum for options and associated time ranges. 181 | @param numPeriods The number of clkFreq periods (1-255) to count down. 182 | @param lowPulseWidth Optional: the length of time for the interrupt pin 183 | low pulse. See the #PCF8523TimerIntPulse enum for options. 184 | */ 185 | /**************************************************************************/ 186 | void RTC_PCF8523::enableCountdownTimer(PCF8523TimerClockFreq clkFreq, 187 | uint8_t numPeriods, 188 | uint8_t lowPulseWidth) { 189 | // Datasheet cautions against updating countdown value while it's running, 190 | // so disabling allows repeated calls with new values to set new countdowns 191 | disableCountdownTimer(); 192 | 193 | // Leave compatible settings intact 194 | uint8_t ctlreg = read_register(PCF8523_CONTROL_2); 195 | uint8_t clkreg = read_register(PCF8523_CLKOUTCONTROL); 196 | 197 | // CTBIE Countdown Timer B Interrupt Enabled 198 | write_register(PCF8523_CONTROL_2, ctlreg |= 0x01); 199 | 200 | // Timer B source clock frequency, optionally int. low pulse width 201 | write_register(PCF8523_TIMER_B_FRCTL, lowPulseWidth << 4 | clkFreq); 202 | 203 | // Timer B value (number of source clock periods) 204 | write_register(PCF8523_TIMER_B_VALUE, numPeriods); 205 | 206 | // TBM Timer B pulse int. mode, CLKOUT (aka SQW) disabled, TBC start Timer B 207 | write_register(PCF8523_CLKOUTCONTROL, clkreg | 0x79); 208 | } 209 | 210 | /**************************************************************************/ 211 | /*! 212 | @overload 213 | @brief Enable Countdown Timer using default interrupt low pulse width. 214 | @param clkFreq One of the PCF8523's Timer Source Clock Frequencies. 215 | See the #PCF8523TimerClockFreq enum for options and associated time ranges. 216 | @param numPeriods The number of clkFreq periods (1-255) to count down. 217 | */ 218 | /**************************************************************************/ 219 | void RTC_PCF8523::enableCountdownTimer(PCF8523TimerClockFreq clkFreq, 220 | uint8_t numPeriods) { 221 | enableCountdownTimer(clkFreq, numPeriods, 0); 222 | } 223 | 224 | /**************************************************************************/ 225 | /*! 226 | @brief Disable the Countdown Timer Interrupt on the PCF8523. 227 | @details For simplicity, this function strictly disables Timer B by setting 228 | TBC to 0. The datasheet describes TBC as the Timer B on/off switch. 229 | Timer B is the only countdown timer implemented at this time. 230 | The following flags have no effect while TBC is off, they are *not* cleared: 231 | - TBM: Timer B will still be set to pulsed mode. 232 | - CTBIE: Timer B interrupt would be triggered if TBC were on. 233 | - CTBF: Timer B flag indicates that interrupt was triggered. Though 234 | typically used for non-pulsed mode, user may wish to query this later. 235 | */ 236 | /**************************************************************************/ 237 | void RTC_PCF8523::disableCountdownTimer() { 238 | // TBC disable to stop Timer B clock 239 | write_register(PCF8523_CLKOUTCONTROL, 240 | ~1 & read_register(PCF8523_CLKOUTCONTROL)); 241 | } 242 | 243 | /**************************************************************************/ 244 | /*! 245 | @brief Stop all timers, clear their flags and settings on the PCF8523. 246 | @details This includes the Countdown Timer, Second Timer, and any CLKOUT 247 | square wave configured with writeSqwPinMode(). 248 | */ 249 | /**************************************************************************/ 250 | void RTC_PCF8523::deconfigureAllTimers() { 251 | disableSecondTimer(); // Surgically clears CONTROL_1 252 | write_register(PCF8523_CONTROL_2, 0); 253 | write_register(PCF8523_CLKOUTCONTROL, 0); 254 | write_register(PCF8523_TIMER_B_FRCTL, 0); 255 | write_register(PCF8523_TIMER_B_VALUE, 0); 256 | } 257 | 258 | /**************************************************************************/ 259 | /*! 260 | @brief Compensate the drift of the RTC. 261 | @details This method sets the "offset" register of the PCF8523, 262 | which can be used to correct a previously measured drift rate. 263 | Two correction modes are available: 264 | 265 | - **PCF8523\_TwoHours**: Clock adjustments are performed on 266 | `offset` consecutive minutes every two hours. This is the most 267 | energy-efficient mode. 268 | 269 | - **PCF8523\_OneMinute**: Clock adjustments are performed on 270 | `offset` consecutive seconds every minute. Extra adjustments are 271 | performed on the last second of the minute is `abs(offset)>60`. 272 | 273 | The `offset` parameter sets the correction amount in units of 274 | roughly 4 ppm. The exact unit depends on the selected mode: 275 | 276 | | mode | offset unit | 277 | |---------------------|----------------------------------------| 278 | | `PCF8523_TwoHours` | 4.340 ppm = 0.375 s/day = 2.625 s/week | 279 | | `PCF8523_OneMinute` | 4.069 ppm = 0.352 s/day = 2.461 s/week | 280 | 281 | See the accompanying sketch pcf8523.ino for an example on how to 282 | use this method. 283 | 284 | @param mode Correction mode, either `PCF8523_TwoHours` or 285 | `PCF8523_OneMinute`. 286 | @param offset Correction amount, from -64 to +63. A positive offset 287 | makes the clock slower. 288 | */ 289 | /**************************************************************************/ 290 | void RTC_PCF8523::calibrate(Pcf8523OffsetMode mode, int8_t offset) { 291 | write_register(PCF8523_OFFSET, ((uint8_t)offset & 0x7F) | mode); 292 | } 293 | -------------------------------------------------------------------------------- /src/RTC_PCF8563.cpp: -------------------------------------------------------------------------------- 1 | #include "RTClib.h" 2 | 3 | #define PCF8563_ADDRESS 0x51 ///< I2C address for PCF8563 4 | #define PCF8563_CLKOUTCONTROL 0x0D ///< CLKOUT control register 5 | #define PCF8563_CONTROL_1 0x00 ///< Control and status register 1 6 | #define PCF8563_CONTROL_2 0x01 ///< Control and status register 2 7 | #define PCF8563_VL_SECONDS 0x02 ///< register address for VL_SECONDS 8 | #define PCF8563_CLKOUT_MASK 0x83 ///< bitmask for SqwPinMode on CLKOUT pin 9 | 10 | /**************************************************************************/ 11 | /*! 12 | @brief Start I2C for the PCF8563 and test succesful connection 13 | @param wireInstance pointer to the I2C bus 14 | @return True if Wire can find PCF8563 or false otherwise. 15 | */ 16 | /**************************************************************************/ 17 | bool RTC_PCF8563::begin(TwoWire *wireInstance) { 18 | if (i2c_dev) 19 | delete i2c_dev; 20 | i2c_dev = new Adafruit_I2CDevice(PCF8563_ADDRESS, wireInstance); 21 | if (!i2c_dev->begin()) 22 | return false; 23 | return true; 24 | } 25 | 26 | /**************************************************************************/ 27 | /*! 28 | @brief Check the status of the VL bit in the VL_SECONDS register. 29 | @details The PCF8563 has an on-chip voltage-low detector. When VDD drops 30 | below Vlow, bit VL in the VL_seconds register is set to indicate that 31 | the integrity of the clock information is no longer guaranteed. 32 | @return True if the bit is set (VDD droped below Vlow) indicating that 33 | the clock integrity is not guaranteed and false only after the bit is 34 | cleared using adjust() 35 | */ 36 | /**************************************************************************/ 37 | bool RTC_PCF8563::lostPower(void) { 38 | return read_register(PCF8563_VL_SECONDS) >> 7; 39 | } 40 | 41 | /**************************************************************************/ 42 | /*! 43 | @brief Set the date and time 44 | @param dt DateTime to set 45 | */ 46 | /**************************************************************************/ 47 | void RTC_PCF8563::adjust(const DateTime &dt) { 48 | uint8_t buffer[8] = {PCF8563_VL_SECONDS, // start at location 2, VL_SECONDS 49 | bin2bcd(dt.second()), bin2bcd(dt.minute()), 50 | bin2bcd(dt.hour()), bin2bcd(dt.day()), 51 | bin2bcd(0), // skip weekdays 52 | bin2bcd(dt.month()), bin2bcd(dt.year() - 2000U)}; 53 | i2c_dev->write(buffer, 8); 54 | } 55 | 56 | /**************************************************************************/ 57 | /*! 58 | @brief Get the current date/time 59 | @return DateTime object containing the current date/time 60 | */ 61 | /**************************************************************************/ 62 | DateTime RTC_PCF8563::now() { 63 | uint8_t buffer[7]; 64 | buffer[0] = PCF8563_VL_SECONDS; // start at location 2, VL_SECONDS 65 | i2c_dev->write_then_read(buffer, 1, buffer, 7); 66 | 67 | return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5] & 0x1F), 68 | bcd2bin(buffer[3] & 0x3F), bcd2bin(buffer[2] & 0x3F), 69 | bcd2bin(buffer[1] & 0x7F), bcd2bin(buffer[0] & 0x7F)); 70 | } 71 | 72 | /**************************************************************************/ 73 | /*! 74 | @brief Resets the STOP bit in register Control_1 75 | */ 76 | /**************************************************************************/ 77 | void RTC_PCF8563::start(void) { 78 | uint8_t ctlreg = read_register(PCF8563_CONTROL_1); 79 | if (ctlreg & (1 << 5)) 80 | write_register(PCF8563_CONTROL_1, ctlreg & ~(1 << 5)); 81 | } 82 | 83 | /**************************************************************************/ 84 | /*! 85 | @brief Sets the STOP bit in register Control_1 86 | */ 87 | /**************************************************************************/ 88 | void RTC_PCF8563::stop(void) { 89 | uint8_t ctlreg = read_register(PCF8563_CONTROL_1); 90 | if (!(ctlreg & (1 << 5))) 91 | write_register(PCF8563_CONTROL_1, ctlreg | (1 << 5)); 92 | } 93 | 94 | /**************************************************************************/ 95 | /*! 96 | @brief Is the PCF8563 running? Check the STOP bit in register Control_1 97 | @return 1 if the RTC is running, 0 if not 98 | */ 99 | /**************************************************************************/ 100 | uint8_t RTC_PCF8563::isrunning() { 101 | return !((read_register(PCF8563_CONTROL_1) >> 5) & 1); 102 | } 103 | 104 | /**************************************************************************/ 105 | /*! 106 | @brief Read the mode of the CLKOUT pin on the PCF8563 107 | @return CLKOUT pin mode as a #Pcf8563SqwPinMode enum 108 | */ 109 | /**************************************************************************/ 110 | Pcf8563SqwPinMode RTC_PCF8563::readSqwPinMode() { 111 | int mode = read_register(PCF8563_CLKOUTCONTROL); 112 | return static_cast(mode & PCF8563_CLKOUT_MASK); 113 | } 114 | 115 | /**************************************************************************/ 116 | /*! 117 | @brief Set the CLKOUT pin mode on the PCF8563 118 | @param mode The mode to set, see the #Pcf8563SqwPinMode enum for options 119 | */ 120 | /**************************************************************************/ 121 | void RTC_PCF8563::writeSqwPinMode(Pcf8563SqwPinMode mode) { 122 | write_register(PCF8563_CLKOUTCONTROL, mode); 123 | } 124 | -------------------------------------------------------------------------------- /src/RTClib.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file RTClib.cpp 4 | 5 | @mainpage Adafruit RTClib 6 | 7 | @section intro Introduction 8 | 9 | This is a fork of JeeLab's fantastic real time clock library for Arduino. 10 | 11 | For details on using this library with an RTC module like the DS1307, PCF8523, 12 | or DS3231, see the guide at: 13 | https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview 14 | 15 | Adafruit invests time and resources providing this open source code, 16 | please support Adafruit and open-source hardware by purchasing 17 | products from Adafruit! 18 | 19 | @section classes Available classes 20 | 21 | This library provides the following classes: 22 | 23 | - Classes for manipulating dates, times and durations: 24 | - DateTime represents a specific point in time; this is the data 25 | type used for setting and reading the supported RTCs 26 | - TimeSpan represents the length of a time interval 27 | - Interfacing specific RTC chips: 28 | - RTC_DS1307 29 | - RTC_DS3231 30 | - RTC_PCF8523 31 | - RTC_PCF8563 32 | - RTC emulated in software; do not expect much accuracy out of these: 33 | - RTC_Millis is based on `millis()` 34 | - RTC_Micros is based on `micros()`; its drift rate can be tuned by 35 | the user 36 | 37 | @section license License 38 | 39 | Original library by JeeLabs https://jeelabs.org/pub/docs/rtclib/, released to 40 | the public domain. 41 | 42 | This version: MIT (see LICENSE) 43 | */ 44 | /**************************************************************************/ 45 | 46 | #include "RTClib.h" 47 | 48 | #ifdef __AVR__ 49 | #include 50 | #elif defined(ESP8266) 51 | #include 52 | #elif defined(ARDUINO_ARCH_SAMD) 53 | // nothing special needed 54 | #elif defined(ARDUINO_SAM_DUE) 55 | #define PROGMEM 56 | #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) 57 | #endif 58 | 59 | /**************************************************************************/ 60 | /*! 61 | @brief Write value to register. 62 | @param reg register address 63 | @param val value to write 64 | */ 65 | /**************************************************************************/ 66 | void RTC_I2C::write_register(uint8_t reg, uint8_t val) { 67 | uint8_t buffer[2] = {reg, val}; 68 | i2c_dev->write(buffer, 2); 69 | } 70 | 71 | /**************************************************************************/ 72 | /*! 73 | @brief Read value from register. 74 | @param reg register address 75 | @return value of register 76 | */ 77 | /**************************************************************************/ 78 | uint8_t RTC_I2C::read_register(uint8_t reg) { 79 | uint8_t buffer[1]; 80 | i2c_dev->write(®, 1); 81 | i2c_dev->read(buffer, 1); 82 | return buffer[0]; 83 | } 84 | 85 | /**************************************************************************/ 86 | // utility code, some of this could be exposed in the DateTime API if needed 87 | /**************************************************************************/ 88 | 89 | /** 90 | Number of days in each month, from January to November. December is not 91 | needed. Omitting it avoids an incompatibility with Paul Stoffregen's Time 92 | library. C.f. https://github.com/adafruit/RTClib/issues/114 93 | */ 94 | const uint8_t daysInMonth[] PROGMEM = {31, 28, 31, 30, 31, 30, 95 | 31, 31, 30, 31, 30}; 96 | 97 | /**************************************************************************/ 98 | /*! 99 | @brief Given a date, return number of days since 2000/01/01, 100 | valid for 2000--2099 101 | @param y Year 102 | @param m Month 103 | @param d Day 104 | @return Number of days 105 | */ 106 | /**************************************************************************/ 107 | static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) { 108 | if (y >= 2000U) 109 | y -= 2000U; 110 | uint16_t days = d; 111 | for (uint8_t i = 1; i < m; ++i) 112 | days += pgm_read_byte(daysInMonth + i - 1); 113 | if (m > 2 && y % 4 == 0) 114 | ++days; 115 | return days + 365 * y + (y + 3) / 4 - 1; 116 | } 117 | 118 | /**************************************************************************/ 119 | /*! 120 | @brief Given a number of days, hours, minutes, and seconds, return the 121 | total seconds 122 | @param days Days 123 | @param h Hours 124 | @param m Minutes 125 | @param s Seconds 126 | @return Number of seconds total 127 | */ 128 | /**************************************************************************/ 129 | static uint32_t time2ulong(uint16_t days, uint8_t h, uint8_t m, uint8_t s) { 130 | return ((days * 24UL + h) * 60 + m) * 60 + s; 131 | } 132 | 133 | /**************************************************************************/ 134 | /*! 135 | @brief Constructor from 136 | [Unix time](https://en.wikipedia.org/wiki/Unix_time). 137 | 138 | This builds a DateTime from an integer specifying the number of seconds 139 | elapsed since the epoch: 1970-01-01 00:00:00. This number is analogous 140 | to Unix time, with two small differences: 141 | 142 | - The Unix epoch is specified to be at 00:00:00 143 | [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time), 144 | whereas this class has no notion of time zones. The epoch used in 145 | this class is then at 00:00:00 on whatever time zone the user chooses 146 | to use, ignoring changes in DST. 147 | 148 | - Unix time is conventionally represented with signed numbers, whereas 149 | this constructor takes an unsigned argument. Because of this, it does 150 | _not_ suffer from the 151 | [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem). 152 | 153 | If called without argument, it returns the earliest time representable 154 | by this class: 2000-01-01 00:00:00. 155 | 156 | @see The `unixtime()` method is the converse of this constructor. 157 | 158 | @param t Time elapsed in seconds since 1970-01-01 00:00:00. 159 | */ 160 | /**************************************************************************/ 161 | DateTime::DateTime(uint32_t t) { 162 | t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970 163 | 164 | ss = t % 60; 165 | t /= 60; 166 | mm = t % 60; 167 | t /= 60; 168 | hh = t % 24; 169 | uint16_t days = t / 24; 170 | uint8_t leap; 171 | for (yOff = 0;; ++yOff) { 172 | leap = yOff % 4 == 0; 173 | if (days < 365U + leap) 174 | break; 175 | days -= 365 + leap; 176 | } 177 | for (m = 1; m < 12; ++m) { 178 | uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1); 179 | if (leap && m == 2) 180 | ++daysPerMonth; 181 | if (days < daysPerMonth) 182 | break; 183 | days -= daysPerMonth; 184 | } 185 | d = days + 1; 186 | } 187 | 188 | /**************************************************************************/ 189 | /*! 190 | @brief Constructor from (year, month, day, hour, minute, second). 191 | @warning If the provided parameters are not valid (e.g. 31 February), 192 | the constructed DateTime will be invalid. 193 | @see The `isValid()` method can be used to test whether the 194 | constructed DateTime is valid. 195 | @param year Either the full year (range: 2000--2099) or the offset from 196 | year 2000 (range: 0--99). 197 | @param month Month number (1--12). 198 | @param day Day of the month (1--31). 199 | @param hour,min,sec Hour (0--23), minute (0--59) and second (0--59). 200 | */ 201 | /**************************************************************************/ 202 | DateTime::DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, 203 | uint8_t min, uint8_t sec) { 204 | if (year >= 2000U) 205 | year -= 2000U; 206 | yOff = year; 207 | m = month; 208 | d = day; 209 | hh = hour; 210 | mm = min; 211 | ss = sec; 212 | } 213 | 214 | /**************************************************************************/ 215 | /*! 216 | @brief Copy constructor. 217 | @param copy DateTime to copy. 218 | */ 219 | /**************************************************************************/ 220 | DateTime::DateTime(const DateTime ©) 221 | : yOff(copy.yOff), m(copy.m), d(copy.d), hh(copy.hh), mm(copy.mm), 222 | ss(copy.ss) {} 223 | 224 | /**************************************************************************/ 225 | /*! 226 | @brief Convert a string containing two digits to uint8_t, e.g. "09" returns 227 | 9 228 | @param p Pointer to a string containing two digits 229 | */ 230 | /**************************************************************************/ 231 | static uint8_t conv2d(const char *p) { 232 | uint8_t v = 0; 233 | if ('0' <= *p && *p <= '9') 234 | v = *p - '0'; 235 | return 10 * v + *++p - '0'; 236 | } 237 | 238 | /**************************************************************************/ 239 | /*! 240 | @brief Constructor for generating the build time. 241 | 242 | This constructor expects its parameters to be strings in the format 243 | generated by the compiler's preprocessor macros `__DATE__` and 244 | `__TIME__`. Usage: 245 | 246 | ``` 247 | DateTime buildTime(__DATE__, __TIME__); 248 | ``` 249 | 250 | @note The `F()` macro can be used to reduce the RAM footprint, see 251 | the next constructor. 252 | 253 | @param date Date string, e.g. "Apr 16 2020". 254 | @param time Time string, e.g. "18:34:56". 255 | */ 256 | /**************************************************************************/ 257 | DateTime::DateTime(const char *date, const char *time) { 258 | yOff = conv2d(date + 9); 259 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 260 | switch (date[0]) { 261 | case 'J': 262 | m = (date[1] == 'a') ? 1 : ((date[2] == 'n') ? 6 : 7); 263 | break; 264 | case 'F': 265 | m = 2; 266 | break; 267 | case 'A': 268 | m = date[2] == 'r' ? 4 : 8; 269 | break; 270 | case 'M': 271 | m = date[2] == 'r' ? 3 : 5; 272 | break; 273 | case 'S': 274 | m = 9; 275 | break; 276 | case 'O': 277 | m = 10; 278 | break; 279 | case 'N': 280 | m = 11; 281 | break; 282 | case 'D': 283 | m = 12; 284 | break; 285 | } 286 | d = conv2d(date + 4); 287 | hh = conv2d(time); 288 | mm = conv2d(time + 3); 289 | ss = conv2d(time + 6); 290 | } 291 | 292 | /**************************************************************************/ 293 | /*! 294 | @brief Memory friendly constructor for generating the build time. 295 | 296 | This version is intended to save RAM by keeping the date and time 297 | strings in program memory. Use it with the `F()` macro: 298 | 299 | ``` 300 | DateTime buildTime(F(__DATE__), F(__TIME__)); 301 | ``` 302 | 303 | @param date Date PROGMEM string, e.g. F("Apr 16 2020"). 304 | @param time Time PROGMEM string, e.g. F("18:34:56"). 305 | */ 306 | /**************************************************************************/ 307 | DateTime::DateTime(const __FlashStringHelper *date, 308 | const __FlashStringHelper *time) { 309 | char buff[11]; 310 | memcpy_P(buff, date, 11); 311 | yOff = conv2d(buff + 9); 312 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 313 | switch (buff[0]) { 314 | case 'J': 315 | m = (buff[1] == 'a') ? 1 : ((buff[2] == 'n') ? 6 : 7); 316 | break; 317 | case 'F': 318 | m = 2; 319 | break; 320 | case 'A': 321 | m = buff[2] == 'r' ? 4 : 8; 322 | break; 323 | case 'M': 324 | m = buff[2] == 'r' ? 3 : 5; 325 | break; 326 | case 'S': 327 | m = 9; 328 | break; 329 | case 'O': 330 | m = 10; 331 | break; 332 | case 'N': 333 | m = 11; 334 | break; 335 | case 'D': 336 | m = 12; 337 | break; 338 | } 339 | d = conv2d(buff + 4); 340 | memcpy_P(buff, time, 8); 341 | hh = conv2d(buff); 342 | mm = conv2d(buff + 3); 343 | ss = conv2d(buff + 6); 344 | } 345 | 346 | /**************************************************************************/ 347 | /*! 348 | @brief Constructor for creating a DateTime from an ISO8601 date string. 349 | 350 | This constructor expects its parameters to be a string in the 351 | https://en.wikipedia.org/wiki/ISO_8601 format, e.g: 352 | 353 | "2020-06-25T15:29:37" 354 | 355 | Usage: 356 | 357 | ``` 358 | DateTime dt("2020-06-25T15:29:37"); 359 | ``` 360 | 361 | @note The year must be > 2000, as only the yOff is considered. 362 | 363 | @param iso8601dateTime 364 | A dateTime string in iso8601 format, 365 | e.g. "2020-06-25T15:29:37". 366 | 367 | */ 368 | /**************************************************************************/ 369 | DateTime::DateTime(const char *iso8601dateTime) { 370 | char ref[] = "2000-01-01T00:00:00"; 371 | memcpy(ref, iso8601dateTime, min(strlen(ref), strlen(iso8601dateTime))); 372 | yOff = conv2d(ref + 2); 373 | m = conv2d(ref + 5); 374 | d = conv2d(ref + 8); 375 | hh = conv2d(ref + 11); 376 | mm = conv2d(ref + 14); 377 | ss = conv2d(ref + 17); 378 | } 379 | 380 | /**************************************************************************/ 381 | /*! 382 | @brief Check whether this DateTime is valid. 383 | @return true if valid, false if not. 384 | */ 385 | /**************************************************************************/ 386 | bool DateTime::isValid() const { 387 | if (yOff >= 100) 388 | return false; 389 | DateTime other(unixtime()); 390 | return yOff == other.yOff && m == other.m && d == other.d && hh == other.hh && 391 | mm == other.mm && ss == other.ss; 392 | } 393 | 394 | /**************************************************************************/ 395 | /*! 396 | @brief Writes the DateTime as a string in a user-defined format. 397 | 398 | The _buffer_ parameter should be initialized by the caller with a string 399 | specifying the requested format. This format string may contain any of 400 | the following specifiers: 401 | 402 | | specifier | output | 403 | |-----------|--------------------------------------------------------| 404 | | YYYY | the year as a 4-digit number (2000--2099) | 405 | | YY | the year as a 2-digit number (00--99) | 406 | | MM | the month as a 2-digit number (01--12) | 407 | | MMM | the abbreviated English month name ("Jan"--"Dec") | 408 | | DD | the day as a 2-digit number (01--31) | 409 | | DDD | the abbreviated English day of the week ("Mon"--"Sun") | 410 | | AP | either "AM" or "PM" | 411 | | ap | either "am" or "pm" | 412 | | hh | the hour as a 2-digit number (00--23 or 01--12) | 413 | | mm | the minute as a 2-digit number (00--59) | 414 | | ss | the second as a 2-digit number (00--59) | 415 | 416 | If either "AP" or "ap" is used, the "hh" specifier uses 12-hour mode 417 | (range: 01--12). Otherwise it works in 24-hour mode (range: 00--23). 418 | 419 | The specifiers within _buffer_ will be overwritten with the appropriate 420 | values from the DateTime. Any characters not belonging to one of the 421 | above specifiers are left as-is. 422 | 423 | __Example__: The format "DDD, DD MMM YYYY hh:mm:ss" generates an output 424 | of the form "Thu, 16 Apr 2020 18:34:56. 425 | 426 | @see The `timestamp()` method provides similar functionnality, but it 427 | returns a `String` object and supports a limited choice of 428 | predefined formats. 429 | 430 | @param[in,out] buffer Array of `char` for holding the format description 431 | and the formatted DateTime. Before calling this method, the buffer 432 | should be initialized by the user with the format string. The method 433 | will overwrite the buffer with the formatted date and/or time. 434 | 435 | @return A pointer to the provided buffer. This is returned for 436 | convenience, in order to enable idioms such as 437 | `Serial.println(now.toString(buffer));` 438 | */ 439 | /**************************************************************************/ 440 | 441 | char *DateTime::toString(char *buffer) const { 442 | uint8_t apTag = 443 | (strstr(buffer, "ap") != nullptr) || (strstr(buffer, "AP") != nullptr); 444 | uint8_t hourReformatted = 0, isPM = false; 445 | if (apTag) { // 12 Hour Mode 446 | if (hh == 0) { // midnight 447 | isPM = false; 448 | hourReformatted = 12; 449 | } else if (hh == 12) { // noon 450 | isPM = true; 451 | hourReformatted = 12; 452 | } else if (hh < 12) { // morning 453 | isPM = false; 454 | hourReformatted = hh; 455 | } else { // 1 o'clock or after 456 | isPM = true; 457 | hourReformatted = hh - 12; 458 | } 459 | } 460 | 461 | for (size_t i = 0; i < strlen(buffer) - 1; i++) { 462 | if (buffer[i] == 'h' && buffer[i + 1] == 'h') { 463 | if (!apTag) { // 24 Hour Mode 464 | buffer[i] = '0' + hh / 10; 465 | buffer[i + 1] = '0' + hh % 10; 466 | } else { // 12 Hour Mode 467 | buffer[i] = '0' + hourReformatted / 10; 468 | buffer[i + 1] = '0' + hourReformatted % 10; 469 | } 470 | } 471 | if (buffer[i] == 'm' && buffer[i + 1] == 'm') { 472 | buffer[i] = '0' + mm / 10; 473 | buffer[i + 1] = '0' + mm % 10; 474 | } 475 | if (buffer[i] == 's' && buffer[i + 1] == 's') { 476 | buffer[i] = '0' + ss / 10; 477 | buffer[i + 1] = '0' + ss % 10; 478 | } 479 | if (buffer[i] == 'D' && buffer[i + 1] == 'D' && buffer[i + 2] == 'D') { 480 | static PROGMEM const char day_names[] = "SunMonTueWedThuFriSat"; 481 | const char *p = &day_names[3 * dayOfTheWeek()]; 482 | buffer[i] = pgm_read_byte(p); 483 | buffer[i + 1] = pgm_read_byte(p + 1); 484 | buffer[i + 2] = pgm_read_byte(p + 2); 485 | } else if (buffer[i] == 'D' && buffer[i + 1] == 'D') { 486 | buffer[i] = '0' + d / 10; 487 | buffer[i + 1] = '0' + d % 10; 488 | } 489 | if (buffer[i] == 'M' && buffer[i + 1] == 'M' && buffer[i + 2] == 'M') { 490 | static PROGMEM const char month_names[] = 491 | "JanFebMarAprMayJunJulAugSepOctNovDec"; 492 | const char *p = &month_names[3 * (m - 1)]; 493 | buffer[i] = pgm_read_byte(p); 494 | buffer[i + 1] = pgm_read_byte(p + 1); 495 | buffer[i + 2] = pgm_read_byte(p + 2); 496 | } else if (buffer[i] == 'M' && buffer[i + 1] == 'M') { 497 | buffer[i] = '0' + m / 10; 498 | buffer[i + 1] = '0' + m % 10; 499 | } 500 | if (buffer[i] == 'Y' && buffer[i + 1] == 'Y' && buffer[i + 2] == 'Y' && 501 | buffer[i + 3] == 'Y') { 502 | buffer[i] = '2'; 503 | buffer[i + 1] = '0'; 504 | buffer[i + 2] = '0' + (yOff / 10) % 10; 505 | buffer[i + 3] = '0' + yOff % 10; 506 | } else if (buffer[i] == 'Y' && buffer[i + 1] == 'Y') { 507 | buffer[i] = '0' + (yOff / 10) % 10; 508 | buffer[i + 1] = '0' + yOff % 10; 509 | } 510 | if (buffer[i] == 'A' && buffer[i + 1] == 'P') { 511 | if (isPM) { 512 | buffer[i] = 'P'; 513 | buffer[i + 1] = 'M'; 514 | } else { 515 | buffer[i] = 'A'; 516 | buffer[i + 1] = 'M'; 517 | } 518 | } else if (buffer[i] == 'a' && buffer[i + 1] == 'p') { 519 | if (isPM) { 520 | buffer[i] = 'p'; 521 | buffer[i + 1] = 'm'; 522 | } else { 523 | buffer[i] = 'a'; 524 | buffer[i + 1] = 'm'; 525 | } 526 | } 527 | } 528 | return buffer; 529 | } 530 | 531 | /**************************************************************************/ 532 | /*! 533 | @brief Return the hour in 12-hour format. 534 | @return Hour (1--12). 535 | */ 536 | /**************************************************************************/ 537 | uint8_t DateTime::twelveHour() const { 538 | if (hh == 0 || hh == 12) { // midnight or noon 539 | return 12; 540 | } else if (hh > 12) { // 1 o'clock or later 541 | return hh - 12; 542 | } else { // morning 543 | return hh; 544 | } 545 | } 546 | 547 | /**************************************************************************/ 548 | /*! 549 | @brief Return the day of the week. 550 | @return Day of week as an integer from 0 (Sunday) to 6 (Saturday). 551 | */ 552 | /**************************************************************************/ 553 | uint8_t DateTime::dayOfTheWeek() const { 554 | uint16_t day = date2days(yOff, m, d); 555 | return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6 556 | } 557 | 558 | /**************************************************************************/ 559 | /*! 560 | @brief Return Unix time: seconds since 1 Jan 1970. 561 | 562 | @see The `DateTime::DateTime(uint32_t)` constructor is the converse of 563 | this method. 564 | 565 | @return Number of seconds since 1970-01-01 00:00:00. 566 | */ 567 | /**************************************************************************/ 568 | uint32_t DateTime::unixtime(void) const { 569 | uint32_t t; 570 | uint16_t days = date2days(yOff, m, d); 571 | t = time2ulong(days, hh, mm, ss); 572 | t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000 573 | 574 | return t; 575 | } 576 | 577 | /**************************************************************************/ 578 | /*! 579 | @brief Convert the DateTime to seconds since 1 Jan 2000 580 | 581 | The result can be converted back to a DateTime with: 582 | 583 | ```cpp 584 | DateTime(SECONDS_FROM_1970_TO_2000 + value) 585 | ``` 586 | 587 | @return Number of seconds since 2000-01-01 00:00:00. 588 | */ 589 | /**************************************************************************/ 590 | uint32_t DateTime::secondstime(void) const { 591 | uint32_t t; 592 | uint16_t days = date2days(yOff, m, d); 593 | t = time2ulong(days, hh, mm, ss); 594 | return t; 595 | } 596 | 597 | /**************************************************************************/ 598 | /*! 599 | @brief Add a TimeSpan to the DateTime object 600 | @param span TimeSpan object 601 | @return New DateTime object with span added to it. 602 | */ 603 | /**************************************************************************/ 604 | DateTime DateTime::operator+(const TimeSpan &span) const { 605 | return DateTime(unixtime() + span.totalseconds()); 606 | } 607 | 608 | /**************************************************************************/ 609 | /*! 610 | @brief Subtract a TimeSpan from the DateTime object 611 | @param span TimeSpan object 612 | @return New DateTime object with span subtracted from it. 613 | */ 614 | /**************************************************************************/ 615 | DateTime DateTime::operator-(const TimeSpan &span) const { 616 | return DateTime(unixtime() - span.totalseconds()); 617 | } 618 | 619 | /**************************************************************************/ 620 | /*! 621 | @brief Subtract one DateTime from another 622 | 623 | @note Since a TimeSpan cannot be negative, the subtracted DateTime 624 | should be less (earlier) than or equal to the one it is 625 | subtracted from. 626 | 627 | @param right The DateTime object to subtract from self (the left object) 628 | @return TimeSpan of the difference between DateTimes. 629 | */ 630 | /**************************************************************************/ 631 | TimeSpan DateTime::operator-(const DateTime &right) const { 632 | return TimeSpan(unixtime() - right.unixtime()); 633 | } 634 | 635 | /**************************************************************************/ 636 | /*! 637 | @author Anton Rieutskyi 638 | @brief Test if one DateTime is less (earlier) than another. 639 | @warning if one or both DateTime objects are invalid, returned value is 640 | meaningless 641 | @see use `isValid()` method to check if DateTime object is valid 642 | @param right Comparison DateTime object 643 | @return True if the left DateTime is earlier than the right one, 644 | false otherwise. 645 | */ 646 | /**************************************************************************/ 647 | bool DateTime::operator<(const DateTime &right) const { 648 | return (yOff + 2000U < right.year() || 649 | (yOff + 2000U == right.year() && 650 | (m < right.month() || 651 | (m == right.month() && 652 | (d < right.day() || 653 | (d == right.day() && 654 | (hh < right.hour() || 655 | (hh == right.hour() && 656 | (mm < right.minute() || 657 | (mm == right.minute() && ss < right.second())))))))))); 658 | } 659 | 660 | /**************************************************************************/ 661 | /*! 662 | @author Anton Rieutskyi 663 | @brief Test if two DateTime objects are equal. 664 | @warning if one or both DateTime objects are invalid, returned value is 665 | meaningless 666 | @see use `isValid()` method to check if DateTime object is valid 667 | @param right Comparison DateTime object 668 | @return True if both DateTime objects are the same, false otherwise. 669 | */ 670 | /**************************************************************************/ 671 | bool DateTime::operator==(const DateTime &right) const { 672 | return (right.year() == yOff + 2000U && right.month() == m && 673 | right.day() == d && right.hour() == hh && right.minute() == mm && 674 | right.second() == ss); 675 | } 676 | 677 | /**************************************************************************/ 678 | /*! 679 | @brief Return a ISO 8601 timestamp as a `String` object. 680 | 681 | The generated timestamp conforms to one of the predefined, ISO 682 | 8601-compatible formats for representing the date (if _opt_ is 683 | `TIMESTAMP_DATE`), the time (`TIMESTAMP_TIME`), or both 684 | (`TIMESTAMP_FULL`). 685 | 686 | @see The `toString()` method provides more general string formatting. 687 | 688 | @param opt Format of the timestamp 689 | @return Timestamp string, e.g. "2020-04-16T18:34:56". 690 | */ 691 | /**************************************************************************/ 692 | String DateTime::timestamp(timestampOpt opt) const { 693 | char buffer[25]; // large enough for any DateTime, including invalid ones 694 | 695 | // Generate timestamp according to opt 696 | switch (opt) { 697 | case TIMESTAMP_TIME: 698 | // Only time 699 | sprintf(buffer, "%02d:%02d:%02d", hh, mm, ss); 700 | break; 701 | case TIMESTAMP_DATE: 702 | // Only date 703 | sprintf(buffer, "%u-%02d-%02d", 2000U + yOff, m, d); 704 | break; 705 | default: 706 | // Full 707 | sprintf(buffer, "%u-%02d-%02dT%02d:%02d:%02d", 2000U + yOff, m, d, hh, mm, 708 | ss); 709 | } 710 | return String(buffer); 711 | } 712 | 713 | /**************************************************************************/ 714 | /*! 715 | @brief Create a new TimeSpan object in seconds 716 | @param seconds Number of seconds 717 | */ 718 | /**************************************************************************/ 719 | TimeSpan::TimeSpan(int32_t seconds) : _seconds(seconds) {} 720 | 721 | /**************************************************************************/ 722 | /*! 723 | @brief Create a new TimeSpan object using a number of 724 | days/hours/minutes/seconds e.g. Make a TimeSpan of 3 hours and 45 minutes: 725 | new TimeSpan(0, 3, 45, 0); 726 | @param days Number of days 727 | @param hours Number of hours 728 | @param minutes Number of minutes 729 | @param seconds Number of seconds 730 | */ 731 | /**************************************************************************/ 732 | TimeSpan::TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds) 733 | : _seconds((int32_t)days * 86400L + (int32_t)hours * 3600 + 734 | (int32_t)minutes * 60 + seconds) {} 735 | 736 | /**************************************************************************/ 737 | /*! 738 | @brief Copy constructor, make a new TimeSpan using an existing one 739 | @param copy The TimeSpan to copy 740 | */ 741 | /**************************************************************************/ 742 | TimeSpan::TimeSpan(const TimeSpan ©) : _seconds(copy._seconds) {} 743 | 744 | /**************************************************************************/ 745 | /*! 746 | @brief Add two TimeSpans 747 | @param right TimeSpan to add 748 | @return New TimeSpan object, sum of left and right 749 | */ 750 | /**************************************************************************/ 751 | TimeSpan TimeSpan::operator+(const TimeSpan &right) const { 752 | return TimeSpan(_seconds + right._seconds); 753 | } 754 | 755 | /**************************************************************************/ 756 | /*! 757 | @brief Subtract a TimeSpan 758 | @param right TimeSpan to subtract 759 | @return New TimeSpan object, right subtracted from left 760 | */ 761 | /**************************************************************************/ 762 | TimeSpan TimeSpan::operator-(const TimeSpan &right) const { 763 | return TimeSpan(_seconds - right._seconds); 764 | } 765 | -------------------------------------------------------------------------------- /src/RTClib.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file RTClib.h 4 | 5 | Original library by JeeLabs http://news.jeelabs.org/code/, released to the 6 | public domain 7 | 8 | License: MIT (see LICENSE) 9 | 10 | This is a fork of JeeLab's fantastic real time clock library for Arduino. 11 | 12 | For details on using this library with an RTC module like the DS1307, PCF8523, 13 | or DS3231, see the guide at: 14 | https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview 15 | 16 | Adafruit invests time and resources providing this open source code, 17 | please support Adafruit and open-source hardware by purchasing 18 | products from Adafruit! 19 | */ 20 | /**************************************************************************/ 21 | 22 | #ifndef _RTCLIB_H_ 23 | #define _RTCLIB_H_ 24 | 25 | #include 26 | #include 27 | 28 | class TimeSpan; 29 | 30 | /** Constants */ 31 | #define SECONDS_PER_DAY 86400L ///< 60 * 60 * 24 32 | #define SECONDS_FROM_1970_TO_2000 \ 33 | 946684800 ///< Unixtime for 2000-01-01 00:00:00, useful for initialization 34 | 35 | /** DS1307 SQW pin mode settings */ 36 | enum Ds1307SqwPinMode { 37 | DS1307_OFF = 0x00, // Low 38 | DS1307_ON = 0x80, // High 39 | DS1307_SquareWave1HZ = 0x10, // 1Hz square wave 40 | DS1307_SquareWave4kHz = 0x11, // 4kHz square wave 41 | DS1307_SquareWave8kHz = 0x12, // 8kHz square wave 42 | DS1307_SquareWave32kHz = 0x13 // 32kHz square wave 43 | }; 44 | 45 | /** DS3231 SQW pin mode settings */ 46 | enum Ds3231SqwPinMode { 47 | DS3231_OFF = 0x1C, /**< Off */ 48 | DS3231_SquareWave1Hz = 0x00, /**< 1Hz square wave */ 49 | DS3231_SquareWave1kHz = 0x08, /**< 1kHz square wave */ 50 | DS3231_SquareWave4kHz = 0x10, /**< 4kHz square wave */ 51 | DS3231_SquareWave8kHz = 0x18 /**< 8kHz square wave */ 52 | }; 53 | 54 | /** DS3231 Alarm modes for alarm 1 */ 55 | enum Ds3231Alarm1Mode { 56 | DS3231_A1_PerSecond = 0x0F, /**< Alarm once per second */ 57 | DS3231_A1_Second = 0x0E, /**< Alarm when seconds match */ 58 | DS3231_A1_Minute = 0x0C, /**< Alarm when minutes and seconds match */ 59 | DS3231_A1_Hour = 0x08, /**< Alarm when hours, minutes 60 | and seconds match */ 61 | DS3231_A1_Date = 0x00, /**< Alarm when date (day of month), hours, 62 | minutes and seconds match */ 63 | DS3231_A1_Day = 0x10 /**< Alarm when day (day of week), hours, 64 | minutes and seconds match */ 65 | }; 66 | /** DS3231 Alarm modes for alarm 2 */ 67 | enum Ds3231Alarm2Mode { 68 | DS3231_A2_PerMinute = 0x7, /**< Alarm once per minute 69 | (whenever seconds are 0) */ 70 | DS3231_A2_Minute = 0x6, /**< Alarm when minutes match */ 71 | DS3231_A2_Hour = 0x4, /**< Alarm when hours and minutes match */ 72 | DS3231_A2_Date = 0x0, /**< Alarm when date (day of month), hours 73 | and minutes match */ 74 | DS3231_A2_Day = 0x8 /**< Alarm when day (day of week), hours 75 | and minutes match */ 76 | }; 77 | /** PCF8523 INT/SQW pin mode settings */ 78 | enum Pcf8523SqwPinMode { 79 | PCF8523_OFF = 7, /**< Off */ 80 | PCF8523_SquareWave1HZ = 6, /**< 1Hz square wave */ 81 | PCF8523_SquareWave32HZ = 5, /**< 32Hz square wave */ 82 | PCF8523_SquareWave1kHz = 4, /**< 1kHz square wave */ 83 | PCF8523_SquareWave4kHz = 3, /**< 4kHz square wave */ 84 | PCF8523_SquareWave8kHz = 2, /**< 8kHz square wave */ 85 | PCF8523_SquareWave16kHz = 1, /**< 16kHz square wave */ 86 | PCF8523_SquareWave32kHz = 0 /**< 32kHz square wave */ 87 | }; 88 | 89 | /** PCF8523 Timer Source Clock Frequencies for Timers A and B */ 90 | enum PCF8523TimerClockFreq { 91 | PCF8523_Frequency4kHz = 0, /**< 1/4096th second = 244 microseconds, 92 | max 62.256 milliseconds */ 93 | PCF8523_Frequency64Hz = 1, /**< 1/64th second = 15.625 milliseconds, 94 | max 3.984375 seconds */ 95 | PCF8523_FrequencySecond = 2, /**< 1 second, max 255 seconds = 4.25 minutes */ 96 | PCF8523_FrequencyMinute = 3, /**< 1 minute, max 255 minutes = 4.25 hours */ 97 | PCF8523_FrequencyHour = 4, /**< 1 hour, max 255 hours = 10.625 days */ 98 | }; 99 | 100 | /** PCF8523 Timer Interrupt Low Pulse Width options for Timer B only */ 101 | enum PCF8523TimerIntPulse { 102 | PCF8523_LowPulse3x64Hz = 0, /**< 46.875 ms 3/64ths second */ 103 | PCF8523_LowPulse4x64Hz = 1, /**< 62.500 ms 4/64ths second */ 104 | PCF8523_LowPulse5x64Hz = 2, /**< 78.125 ms 5/64ths second */ 105 | PCF8523_LowPulse6x64Hz = 3, /**< 93.750 ms 6/64ths second */ 106 | PCF8523_LowPulse8x64Hz = 4, /**< 125.000 ms 8/64ths second */ 107 | PCF8523_LowPulse10x64Hz = 5, /**< 156.250 ms 10/64ths second */ 108 | PCF8523_LowPulse12x64Hz = 6, /**< 187.500 ms 12/64ths second */ 109 | PCF8523_LowPulse14x64Hz = 7 /**< 218.750 ms 14/64ths second */ 110 | }; 111 | 112 | /** PCF8523 Offset modes for making temperature/aging/accuracy adjustments */ 113 | enum Pcf8523OffsetMode { 114 | PCF8523_TwoHours = 0x00, /**< Offset made every two hours */ 115 | PCF8523_OneMinute = 0x80 /**< Offset made every minute */ 116 | }; 117 | 118 | /** PCF8563 CLKOUT pin mode settings */ 119 | enum Pcf8563SqwPinMode { 120 | PCF8563_SquareWaveOFF = 0x00, /**< Off */ 121 | PCF8563_SquareWave1Hz = 0x83, /**< 1Hz square wave */ 122 | PCF8563_SquareWave32Hz = 0x82, /**< 32Hz square wave */ 123 | PCF8563_SquareWave1kHz = 0x81, /**< 1kHz square wave */ 124 | PCF8563_SquareWave32kHz = 0x80 /**< 32kHz square wave */ 125 | }; 126 | 127 | /**************************************************************************/ 128 | /*! 129 | @brief Simple general-purpose date/time class (no TZ / DST / leap 130 | seconds). 131 | 132 | This class stores date and time information in a broken-down form, as a 133 | tuple (year, month, day, hour, minute, second). The day of the week is 134 | not stored, but computed on request. The class has no notion of time 135 | zones, daylight saving time, or 136 | [leap seconds](http://en.wikipedia.org/wiki/Leap_second): time is stored 137 | in whatever time zone the user chooses to use. 138 | 139 | The class supports dates in the range from 1 Jan 2000 to 31 Dec 2099 140 | inclusive. 141 | */ 142 | /**************************************************************************/ 143 | class DateTime { 144 | public: 145 | DateTime(uint32_t t = SECONDS_FROM_1970_TO_2000); 146 | DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour = 0, 147 | uint8_t min = 0, uint8_t sec = 0); 148 | DateTime(const DateTime ©); 149 | DateTime(const char *date, const char *time); 150 | DateTime(const __FlashStringHelper *date, const __FlashStringHelper *time); 151 | DateTime(const char *iso8601date); 152 | bool isValid() const; 153 | char *toString(char *buffer) const; 154 | 155 | /*! 156 | @brief Return the year. 157 | @return Year (range: 2000--2099). 158 | */ 159 | uint16_t year() const { return 2000U + yOff; } 160 | /*! 161 | @brief Return the month. 162 | @return Month number (1--12). 163 | */ 164 | uint8_t month() const { return m; } 165 | /*! 166 | @brief Return the day of the month. 167 | @return Day of the month (1--31). 168 | */ 169 | uint8_t day() const { return d; } 170 | /*! 171 | @brief Return the hour 172 | @return Hour (0--23). 173 | */ 174 | uint8_t hour() const { return hh; } 175 | 176 | uint8_t twelveHour() const; 177 | /*! 178 | @brief Return whether the time is PM. 179 | @return 0 if the time is AM, 1 if it's PM. 180 | */ 181 | uint8_t isPM() const { return hh >= 12; } 182 | /*! 183 | @brief Return the minute. 184 | @return Minute (0--59). 185 | */ 186 | uint8_t minute() const { return mm; } 187 | /*! 188 | @brief Return the second. 189 | @return Second (0--59). 190 | */ 191 | uint8_t second() const { return ss; } 192 | 193 | uint8_t dayOfTheWeek() const; 194 | 195 | /* 32-bit times as seconds since 2000-01-01. */ 196 | uint32_t secondstime() const; 197 | 198 | /* 32-bit times as seconds since 1970-01-01. */ 199 | uint32_t unixtime(void) const; 200 | 201 | /*! 202 | Format of the ISO 8601 timestamp generated by `timestamp()`. Each 203 | option corresponds to a `toString()` format as follows: 204 | */ 205 | enum timestampOpt { 206 | TIMESTAMP_FULL, //!< `YYYY-MM-DDThh:mm:ss` 207 | TIMESTAMP_TIME, //!< `hh:mm:ss` 208 | TIMESTAMP_DATE //!< `YYYY-MM-DD` 209 | }; 210 | String timestamp(timestampOpt opt = TIMESTAMP_FULL) const; 211 | 212 | DateTime operator+(const TimeSpan &span) const; 213 | DateTime operator-(const TimeSpan &span) const; 214 | TimeSpan operator-(const DateTime &right) const; 215 | bool operator<(const DateTime &right) const; 216 | 217 | /*! 218 | @brief Test if one DateTime is greater (later) than another. 219 | @warning if one or both DateTime objects are invalid, returned value is 220 | meaningless 221 | @see use `isValid()` method to check if DateTime object is valid 222 | @param right DateTime object to compare 223 | @return True if the left DateTime is later than the right one, 224 | false otherwise 225 | */ 226 | bool operator>(const DateTime &right) const { return right < *this; } 227 | 228 | /*! 229 | @brief Test if one DateTime is less (earlier) than or equal to another 230 | @warning if one or both DateTime objects are invalid, returned value is 231 | meaningless 232 | @see use `isValid()` method to check if DateTime object is valid 233 | @param right DateTime object to compare 234 | @return True if the left DateTime is earlier than or equal to the 235 | right one, false otherwise 236 | */ 237 | bool operator<=(const DateTime &right) const { return !(*this > right); } 238 | 239 | /*! 240 | @brief Test if one DateTime is greater (later) than or equal to another 241 | @warning if one or both DateTime objects are invalid, returned value is 242 | meaningless 243 | @see use `isValid()` method to check if DateTime object is valid 244 | @param right DateTime object to compare 245 | @return True if the left DateTime is later than or equal to the right 246 | one, false otherwise 247 | */ 248 | bool operator>=(const DateTime &right) const { return !(*this < right); } 249 | bool operator==(const DateTime &right) const; 250 | 251 | /*! 252 | @brief Test if two DateTime objects are not equal. 253 | @warning if one or both DateTime objects are invalid, returned value is 254 | meaningless 255 | @see use `isValid()` method to check if DateTime object is valid 256 | @param right DateTime object to compare 257 | @return True if the two objects are not equal, false if they are 258 | */ 259 | bool operator!=(const DateTime &right) const { return !(*this == right); } 260 | 261 | protected: 262 | uint8_t yOff; ///< Year offset from 2000 263 | uint8_t m; ///< Month 1-12 264 | uint8_t d; ///< Day 1-31 265 | uint8_t hh; ///< Hours 0-23 266 | uint8_t mm; ///< Minutes 0-59 267 | uint8_t ss; ///< Seconds 0-59 268 | }; 269 | 270 | /**************************************************************************/ 271 | /*! 272 | @brief Timespan which can represent changes in time with seconds accuracy. 273 | */ 274 | /**************************************************************************/ 275 | class TimeSpan { 276 | public: 277 | TimeSpan(int32_t seconds = 0); 278 | TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds); 279 | TimeSpan(const TimeSpan ©); 280 | 281 | /*! 282 | @brief Number of days in the TimeSpan 283 | e.g. 4 284 | @return int16_t days 285 | */ 286 | int16_t days() const { return _seconds / 86400L; } 287 | /*! 288 | @brief Number of hours in the TimeSpan 289 | This is not the total hours, it includes the days 290 | e.g. 4 days, 3 hours - NOT 99 hours 291 | @return int8_t hours 292 | */ 293 | int8_t hours() const { return _seconds / 3600 % 24; } 294 | /*! 295 | @brief Number of minutes in the TimeSpan 296 | This is not the total minutes, it includes days/hours 297 | e.g. 4 days, 3 hours, 27 minutes 298 | @return int8_t minutes 299 | */ 300 | int8_t minutes() const { return _seconds / 60 % 60; } 301 | /*! 302 | @brief Number of seconds in the TimeSpan 303 | This is not the total seconds, it includes the days/hours/minutes 304 | e.g. 4 days, 3 hours, 27 minutes, 7 seconds 305 | @return int8_t seconds 306 | */ 307 | int8_t seconds() const { return _seconds % 60; } 308 | /*! 309 | @brief Total number of seconds in the TimeSpan, e.g. 358027 310 | @return int32_t seconds 311 | */ 312 | int32_t totalseconds() const { return _seconds; } 313 | 314 | TimeSpan operator+(const TimeSpan &right) const; 315 | TimeSpan operator-(const TimeSpan &right) const; 316 | 317 | protected: 318 | int32_t _seconds; ///< Actual TimeSpan value is stored as seconds 319 | }; 320 | 321 | /**************************************************************************/ 322 | /*! 323 | @brief A generic I2C RTC base class. DO NOT USE DIRECTLY 324 | */ 325 | /**************************************************************************/ 326 | class RTC_I2C { 327 | protected: 328 | /*! 329 | @brief Convert a binary coded decimal value to binary. RTC stores 330 | time/date values as BCD. 331 | @param val BCD value 332 | @return Binary value 333 | */ 334 | static uint8_t bcd2bin(uint8_t val) { return val - 6 * (val >> 4); } 335 | /*! 336 | @brief Convert a binary value to BCD format for the RTC registers 337 | @param val Binary value 338 | @return BCD value 339 | */ 340 | static uint8_t bin2bcd(uint8_t val) { return val + 6 * (val / 10); } 341 | Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface 342 | uint8_t read_register(uint8_t reg); 343 | void write_register(uint8_t reg, uint8_t val); 344 | }; 345 | 346 | /**************************************************************************/ 347 | /*! 348 | @brief RTC based on the DS1307 chip connected via I2C and the Wire library 349 | */ 350 | /**************************************************************************/ 351 | class RTC_DS1307 : RTC_I2C { 352 | public: 353 | bool begin(TwoWire *wireInstance = &Wire); 354 | void adjust(const DateTime &dt); 355 | uint8_t isrunning(void); 356 | DateTime now(); 357 | Ds1307SqwPinMode readSqwPinMode(); 358 | void writeSqwPinMode(Ds1307SqwPinMode mode); 359 | uint8_t readnvram(uint8_t address); 360 | void readnvram(uint8_t *buf, uint8_t size, uint8_t address); 361 | void writenvram(uint8_t address, uint8_t data); 362 | void writenvram(uint8_t address, const uint8_t *buf, uint8_t size); 363 | }; 364 | 365 | /**************************************************************************/ 366 | /*! 367 | @brief RTC based on the DS3231 chip connected via I2C and the Wire library 368 | */ 369 | /**************************************************************************/ 370 | class RTC_DS3231 : RTC_I2C { 371 | public: 372 | bool begin(TwoWire *wireInstance = &Wire); 373 | void adjust(const DateTime &dt); 374 | bool lostPower(void); 375 | DateTime now(); 376 | Ds3231SqwPinMode readSqwPinMode(); 377 | void writeSqwPinMode(Ds3231SqwPinMode mode); 378 | bool setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode); 379 | bool setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode); 380 | DateTime getAlarm1(); 381 | DateTime getAlarm2(); 382 | Ds3231Alarm1Mode getAlarm1Mode(); 383 | Ds3231Alarm2Mode getAlarm2Mode(); 384 | void disableAlarm(uint8_t alarm_num); 385 | void clearAlarm(uint8_t alarm_num); 386 | bool alarmFired(uint8_t alarm_num); 387 | void enable32K(void); 388 | void disable32K(void); 389 | bool isEnabled32K(void); 390 | float getTemperature(); // in Celsius degree 391 | /*! 392 | @brief Convert the day of the week to a representation suitable for 393 | storing in the DS3231: from 1 (Monday) to 7 (Sunday). 394 | @param d Day of the week as represented by the library: 395 | from 0 (Sunday) to 6 (Saturday). 396 | @return the converted value 397 | */ 398 | static uint8_t dowToDS3231(uint8_t d) { return d == 0 ? 7 : d; } 399 | }; 400 | 401 | /**************************************************************************/ 402 | /*! 403 | @brief RTC based on the PCF8523 chip connected via I2C and the Wire library 404 | */ 405 | /**************************************************************************/ 406 | class RTC_PCF8523 : RTC_I2C { 407 | public: 408 | bool begin(TwoWire *wireInstance = &Wire); 409 | void adjust(const DateTime &dt); 410 | bool lostPower(void); 411 | bool initialized(void); 412 | DateTime now(); 413 | void start(void); 414 | void stop(void); 415 | uint8_t isrunning(); 416 | Pcf8523SqwPinMode readSqwPinMode(); 417 | void writeSqwPinMode(Pcf8523SqwPinMode mode); 418 | void enableSecondTimer(void); 419 | void disableSecondTimer(void); 420 | void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods, 421 | uint8_t lowPulseWidth); 422 | void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods); 423 | void disableCountdownTimer(void); 424 | void deconfigureAllTimers(void); 425 | void calibrate(Pcf8523OffsetMode mode, int8_t offset); 426 | }; 427 | 428 | /**************************************************************************/ 429 | /*! 430 | @brief RTC based on the PCF8563 chip connected via I2C and the Wire library 431 | */ 432 | /**************************************************************************/ 433 | class RTC_PCF8563 : RTC_I2C { 434 | public: 435 | bool begin(TwoWire *wireInstance = &Wire); 436 | bool lostPower(void); 437 | void adjust(const DateTime &dt); 438 | DateTime now(); 439 | void start(void); 440 | void stop(void); 441 | uint8_t isrunning(); 442 | Pcf8563SqwPinMode readSqwPinMode(); 443 | void writeSqwPinMode(Pcf8563SqwPinMode mode); 444 | }; 445 | 446 | /**************************************************************************/ 447 | /*! 448 | @brief RTC using the internal millis() clock, has to be initialized before 449 | use. NOTE: this is immune to millis() rollover events. 450 | */ 451 | /**************************************************************************/ 452 | class RTC_Millis { 453 | public: 454 | /*! 455 | @brief Start the RTC 456 | @param dt DateTime object with the date/time to set 457 | */ 458 | void begin(const DateTime &dt) { adjust(dt); } 459 | void adjust(const DateTime &dt); 460 | DateTime now(); 461 | 462 | protected: 463 | /*! 464 | Unix time from the previous call to now(). 465 | 466 | This, together with `lastMillis`, defines the alignment between 467 | the `millis()` timescale and the Unix timescale. Both variables 468 | are updated on each call to now(), which prevents rollover issues. 469 | */ 470 | uint32_t lastUnix; 471 | /*! 472 | `millis()` value corresponding `lastUnix`. 473 | 474 | Note that this is **not** the `millis()` value of the last call to 475 | now(): it's the `millis()` value corresponding to the last **full 476 | second** of Unix time preceding the last call to now(). 477 | */ 478 | uint32_t lastMillis; 479 | }; 480 | 481 | /**************************************************************************/ 482 | /*! 483 | @brief RTC using the internal micros() clock, has to be initialized before 484 | use. Unlike RTC_Millis, this can be tuned in order to compensate for 485 | the natural drift of the system clock. Note that now() has to be 486 | called more frequently than the micros() rollover period, which is 487 | approximately 71.6 minutes. 488 | */ 489 | /**************************************************************************/ 490 | class RTC_Micros { 491 | public: 492 | /*! 493 | @brief Start the RTC 494 | @param dt DateTime object with the date/time to set 495 | */ 496 | void begin(const DateTime &dt) { adjust(dt); } 497 | void adjust(const DateTime &dt); 498 | void adjustDrift(int ppm); 499 | DateTime now(); 500 | 501 | protected: 502 | /*! 503 | Number of microseconds reported by `micros()` per "true" 504 | (calibrated) second. 505 | */ 506 | uint32_t microsPerSecond = 1000000; 507 | /*! 508 | Unix time from the previous call to now(). 509 | 510 | The timing logic is identical to RTC_Millis. 511 | */ 512 | uint32_t lastUnix; 513 | /*! 514 | `micros()` value corresponding to `lastUnix`. 515 | */ 516 | uint32_t lastMicros; 517 | }; 518 | 519 | #endif // _RTCLIB_H_ 520 | --------------------------------------------------------------------------------