├── CHANGELOG ├── LICENSE ├── README.md ├── examples ├── DS3231_alarm │ └── DS3231_alarm.ino ├── DS3231_dateformat │ └── DS3231_dateformat.ino ├── DS3231_intalarm │ └── DS3231_intalarm.ino ├── DS3231_simple │ └── DS3231_simple.ino ├── DS3231_sqw_32khz │ └── DS3231_sqw_32khz.ino └── DS3231_temperature │ └── DS3231_temperature.ino ├── keywords.txt ├── library.json ├── library.properties └── src ├── DS3231.cpp └── DS3231.h /CHANGELOG: -------------------------------------------------------------------------------- 1 | DS3231 Arduino Library 1.1.0 / 19.05.2023 2 | ========================================= 3 | 4 | * Added loadDateTimeFromLong() 5 | * Fixed alarm example sketch 6 | * Fixed typos in readme 7 | * Fixed strDaySufix() 8 | * Fiexd setDateTime() 9 | * Fixed daysInMonth() 10 | * Add PlatformIO and Arduino library informations 11 | * Change to MIT license 12 | * General cleanups 13 | 14 | DS3231 Arduino Library 1.0.1 / 01.12.2014 15 | ========================================= 16 | 17 | * Fix time & square wave battery backup 18 | * New function setBattery(bool timeBattery, bool squareBattery) 19 | * setBattery(true, false) is default called on begin() 20 | 21 | DS3231 Arduino Library 1.0.0 / 27.04.2014 22 | ========================================= 23 | 24 | * First release 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014-2023 Korneliusz Jarzębski 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Arduino-DS3231 2 | ============== 3 | 4 | DS3231 Real-Time Clock. 5 | 6 | ![DS3231](http://www.jarzebski.pl/media/big/publish/2014/04/ds3231-dateformat.png)! 7 | 8 | Date formats (Day) 9 | ------------------ 10 | 11 | * d : Day of the month, 2 digits with leading zeros (01 to 31) 12 | * D : A textual representation of a day, three letters (Mon through Sun) 13 | * j : Day of the month without leading zeros (1 to 31) 14 | * l : A full textual representation of the day of the week (Sunday through Saturday) 15 | * N : ISO-8601 numeric representation of the day of the week (1 for Monday through 7 for Sunday) 16 | * S : English ordinal suffix for the day of the month, 2 characters (st, nd, rd or th. Works well with j) 17 | * w : Numeric representation of the day of the week (0 for Sunday through 6 for Saturday) 18 | * z : The day of the year (0 through 365) 19 | 20 | Date formats (Month) 21 | -------------------- 22 | 23 | * F : A full textual representation of a month, such as January or March (January through December) 24 | * m : Numeric representation of a month, with leading zeros (01 through 12) 25 | * M : A short textual representation of a month, three letters (Jan through Dec) 26 | * n : Numeric representation of a month, without leading zeros (1 through 12) 27 | * t : Number of days in the given month (28 through 31) 28 | 29 | Date formats (Year) 30 | ------------------- 31 | 32 | * L : Whether it's a leap year (1 if it is a leap year, 0 otherwise) 33 | * Y : A full numeric representation of a year, 4 digits (Examples: 1999 or 2003) 34 | * y : A two digit representation of a year (Examples: 99 or 03) 35 | 36 | Date formats (Time) 37 | ------------------- 38 | 39 | * a : Lowercase Ante meridiem and Post meridiem (am or pm) 40 | * A : Uppercase Ante meridiem and Post meridiem (AM or PM) 41 | * g : 12-hour format of an hour without leading zeros (1 through 12) 42 | * G : 24-hour format of an hour without leading zeros (0 through 23) 43 | * h : 12-hour format of an hour with leading zeros (01 through 12) 44 | * H : 24-hour format of an hour with leading zeros (00 through 23) 45 | * i : Minutes with leading zeros (00 to 59) 46 | * s : Seconds, with leading zeros (00 through 59) 47 | 48 | Dare formats (Full Date/Time) 49 | ----------------------------- 50 | 51 | * U : Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) 52 | 53 | More info 54 | --------- 55 | 56 | Tutorials: www.jarzebski.pl/arduino/komponenty/zegar-czasu-rzeczywistego-rtc-ds3231.html 57 | 58 | This library uses I2C to communicate, 2 pins are required to interface. 59 | 60 | Credits 61 | ------- 62 | 63 | Original Code by JeeLabs http://news.jeelabs.org/code/ 64 | 65 | First fork by adafruit https://github.com/adafruit/RTClib 66 | -------------------------------------------------------------------------------- /examples/DS3231_alarm/DS3231_alarm.ino: -------------------------------------------------------------------------------- 1 | /* 2 | DS3231: Real-Time Clock. Alarm simple 3 | Read more: www.jarzebski.pl/arduino/komponenty/zegar-czasu-rzeczywistego-rtc-DS3231.html 4 | GIT: https://github.com/jarzebski/Arduino-DS3231 5 | Web: http://www.jarzebski.pl 6 | (c) 2014 by Korneliusz Jarzebski 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | DS3231 clock; 13 | RTCDateTime dt; 14 | 15 | void setup() 16 | { 17 | Serial.begin(9600); 18 | 19 | // Initialize DS3231 20 | Serial.println("Initialize DS3231");; 21 | clock.begin(); 22 | 23 | // Disarm alarms and clear alarms for this example, because alarms is battery backed. 24 | // Under normal conditions, the settings should be reset after power and restart microcontroller. 25 | clock.armAlarm1(false); 26 | clock.armAlarm2(false); 27 | clock.clearAlarm1(); 28 | clock.clearAlarm2(); 29 | 30 | // Manual (Year, Month, Day, Hour, Minute, Second) 31 | clock.setDateTime(2014, 4, 25, 0, 0, 0); 32 | 33 | // Set Alarm - Every second. 34 | // DS3231_EVERY_SECOND is available only on Alarm1. 35 | // setAlarm1(Date or Day, Hour, Minute, Second, Mode, Armed = true) 36 | // clock.setAlarm1(0, 0, 0, 0, DS3231_EVERY_SECOND); 37 | 38 | // Set Alarm - Every full minute. 39 | // DS3231_EVERY_MINUTE is available only on Alarm2. 40 | // setAlarm2(Date or Day, Hour, Minute, Second, Mode, Armed = true) 41 | // clock.setAlarm2(0, 0, 0, 0, DS3231_EVERY_MINUTE); 42 | 43 | // Set Alarm1 - Every 20s in each minute 44 | // setAlarm1(Date or Day, Hour, Minute, Second, Mode, Armed = true) 45 | clock.setAlarm1(0, 0, 0, 20, DS3231_MATCH_S); 46 | 47 | // Set Alarm2 - Every 01m in each hour 48 | // setAlarm2(Date or Day, Hour, Minute, Mode, Armed = true) 49 | clock.setAlarm2(0, 0, 1, DS3231_MATCH_M); 50 | 51 | // Set Alarm - Every 01m:25s in each hour 52 | // setAlarm1(Date or Day, Hour, Minute, Second, Mode, Armed = true) 53 | // clock.setAlarm1(0, 0, 1, 25, DS3231_MATCH_M_S); 54 | 55 | // Set Alarm - Every 01h:10m:30s in each day 56 | // setAlarm1(Date or Day, Hour, Minute, Second, Mode, Armed = true) 57 | // clock.setAlarm1(0, 1, 10, 30, DS3231_MATCH_H_M_S); 58 | 59 | // Set Alarm - 07h:00m:00s in 25th day in month 60 | // setAlarm1(Date or Day, Hour, Minute, Second, Mode, Armed = true) 61 | // clock.setAlarm1(25, 7, 0, 0, DS3231_MATCH_DT_H_M_S); 62 | 63 | // Set Alarm - 10h:45m:30s in every Friday (1 - Mon, 7 - Sun) 64 | // setAlarm1(Date or Day, Hour, Minute, Second, Mode, Armed = true) 65 | // clock.setAlarm1(5, 10, 40, 30, DS3231_MATCH_DY_H_M_S); 66 | 67 | // Check alarm settings 68 | checkAlarms(); 69 | } 70 | 71 | void checkAlarms() 72 | { 73 | RTCAlarmTime a1; 74 | RTCAlarmTime a2; 75 | 76 | if (clock.isArmed1()) 77 | { 78 | a1 = clock.getAlarm1(); 79 | 80 | Serial.print("Alarm1 is triggered "); 81 | switch (clock.getAlarmType1()) 82 | { 83 | case DS3231_EVERY_SECOND: 84 | Serial.println("every second"); 85 | break; 86 | case DS3231_MATCH_S: 87 | Serial.print("when seconds match: "); 88 | Serial.println(clock.dateFormat("__ __:__:s", a1)); 89 | break; 90 | case DS3231_MATCH_M_S: 91 | Serial.print("when minutes and sencods match: "); 92 | Serial.println(clock.dateFormat("__ __:i:s", a1)); 93 | break; 94 | case DS3231_MATCH_H_M_S: 95 | Serial.print("when hours, minutes and seconds match: "); 96 | Serial.println(clock.dateFormat("__ H:i:s", a1)); 97 | break; 98 | case DS3231_MATCH_DT_H_M_S: 99 | Serial.print("when date, hours, minutes and seconds match: "); 100 | Serial.println(clock.dateFormat("d H:i:s", a1)); 101 | break; 102 | case DS3231_MATCH_DY_H_M_S: 103 | Serial.print("when day of week, hours, minutes and seconds match: "); 104 | Serial.println(clock.dateFormat("l H:i:s", a1)); 105 | break; 106 | default: 107 | Serial.println("UNKNOWN RULE"); 108 | break; 109 | } 110 | } else 111 | { 112 | Serial.println("Alarm1 is disarmed."); 113 | } 114 | 115 | if (clock.isArmed2()) 116 | { 117 | a2 = clock.getAlarm2(); 118 | 119 | Serial.print("Alarm2 is triggered "); 120 | switch (clock.getAlarmType2()) 121 | { 122 | case DS3231_EVERY_MINUTE: 123 | Serial.println("every minute"); 124 | break; 125 | case DS3231_MATCH_M: 126 | Serial.print("when minutes match: "); 127 | Serial.println(clock.dateFormat("__ __:i:s", a2)); 128 | break; 129 | case DS3231_MATCH_H_M: 130 | Serial.print("when hours and minutes match:"); 131 | Serial.println(clock.dateFormat("__ H:i:s", a2)); 132 | break; 133 | case DS3231_MATCH_DT_H_M: 134 | Serial.print("when date, hours and minutes match: "); 135 | Serial.println(clock.dateFormat("d H:i:s", a2)); 136 | break; 137 | case DS3231_MATCH_DY_H_M: 138 | Serial.println("when day of week, hours and minutes match: "); 139 | Serial.print(clock.dateFormat("l H:i:s", a2)); 140 | break; 141 | default: 142 | Serial.println("UNKNOWN RULE"); 143 | break; 144 | } 145 | } else 146 | { 147 | Serial.println("Alarm2 is disarmed."); 148 | } 149 | } 150 | 151 | void loop() 152 | { 153 | dt = clock.getDateTime(); 154 | 155 | Serial.println(clock.dateFormat("d-m-Y H:i:s - l", dt)); 156 | 157 | // Call isAlarm1(false) if you want clear alarm1 flag manualy by clearAlarm1(); 158 | if (clock.isAlarm1()) 159 | { 160 | Serial.println("ALARM 1 TRIGGERED!"); 161 | } 162 | 163 | // Call isAlarm2(false) if you want clear alarm1 flag manualy by clearAlarm2(); 164 | if (clock.isAlarm2()) 165 | { 166 | Serial.println("ALARM 2 TRIGGERED!"); 167 | } 168 | 169 | delay(1000); 170 | } 171 | 172 | 173 | -------------------------------------------------------------------------------- /examples/DS3231_dateformat/DS3231_dateformat.ino: -------------------------------------------------------------------------------- 1 | /* 2 | DS3231: Real-Time Clock. Date Format 3 | Read more: www.jarzebski.pl/arduino/komponenty/zegar-czasu-rzeczywistego-rtc-ds3231.html 4 | GIT: https://github.com/jarzebski/Arduino-DS3231 5 | Web: http://www.jarzebski.pl 6 | (c) 2014 by Korneliusz Jarzebski 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | DS3231 clock; 13 | RTCDateTime dt; 14 | 15 | void setup() 16 | { 17 | Serial.begin(9600); 18 | 19 | // Initialize DS3231 20 | Serial.println("Initialize DS3231");; 21 | clock.begin(); 22 | 23 | // Set sketch compiling time 24 | clock.setDateTime(__DATE__, __TIME__); 25 | 26 | // Set from UNIX timestamp 27 | // clock.setDateTime(1397408400); 28 | 29 | // Manual (YYYY, MM, DD, HH, II, SS 30 | // clock.setDateTime(2014, 4, 13, 19, 21, 00); 31 | } 32 | 33 | void loop() 34 | { 35 | dt = clock.getDateTime(); 36 | 37 | Serial.print("Long number format: "); 38 | Serial.println(clock.dateFormat("d-m-Y H:i:s", dt)); 39 | 40 | Serial.print("Long format with month name: "); 41 | Serial.println(clock.dateFormat("d F Y H:i:s", dt)); 42 | 43 | Serial.print("Short format witch 12h mode: "); 44 | Serial.println(clock.dateFormat("jS M y, h:ia", dt)); 45 | 46 | Serial.print("Today is: "); 47 | Serial.print(clock.dateFormat("l, z", dt)); 48 | Serial.println(" days of the year."); 49 | 50 | Serial.print("Actual month has: "); 51 | Serial.print(clock.dateFormat("t", dt)); 52 | Serial.println(" days."); 53 | 54 | Serial.print("Unixtime: "); 55 | Serial.println(clock.dateFormat("U", dt)); 56 | 57 | Serial.println(); 58 | 59 | delay(1000); 60 | } 61 | 62 | -------------------------------------------------------------------------------- /examples/DS3231_intalarm/DS3231_intalarm.ino: -------------------------------------------------------------------------------- 1 | /* 2 | DS3231: Real-Time Clock. Alarm simple 3 | Read more: www.jarzebski.pl/arduino/komponenty/zegar-czasu-rzeczywistego-rtc-DS3231.html 4 | GIT: https://github.com/jarzebski/Arduino-DS3231 5 | Web: http://www.jarzebski.pl 6 | (c) 2014 by Korneliusz Jarzebski 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | DS3231 clock; 13 | RTCDateTime dt; 14 | boolean isAlarm = false; 15 | int alarmLED = 4; 16 | 17 | void alarmFunction() 18 | { 19 | Serial.println("*** INT 0 ***"); 20 | isAlarm = true; 21 | } 22 | 23 | void setup() 24 | { 25 | Serial.begin(9600); 26 | 27 | // Initialize DS3231 28 | Serial.println("Initialize DS3231");; 29 | clock.begin(); 30 | 31 | // Disarm alarms and clear alarms for this example, because alarms is battery backed. 32 | // Under normal conditions, the settings should be reset after power and restart microcontroller. 33 | clock.armAlarm1(false); 34 | clock.armAlarm2(false); 35 | clock.clearAlarm1(); 36 | clock.clearAlarm2(); 37 | clock.enableOutput(false); 38 | 39 | // Manual (Year, Month, Day, Hour, Minute, Second) 40 | clock.setDateTime(2014, 4, 25, 0, 0, 0); 41 | 42 | // Set Alarm1 - Every 20s in each minute 43 | // setAlarm1(Date or Day, Hour, Minute, Second, Mode, Armed = true) 44 | clock.setAlarm1(0, 0, 0, 10, DS3231_MATCH_S); 45 | 46 | // Attach Interrput to Arduino Pin 2 47 | attachInterrupt(digitalPinToInterrupt(2), alarmFunction, FALLING); 48 | 49 | // Setup LED Pin 50 | pinMode(alarmLED, OUTPUT); 51 | } 52 | 53 | void loop() 54 | { 55 | dt = clock.getDateTime(); 56 | Serial.println(clock.dateFormat("d-m-Y H:i:s - l", dt)); 57 | 58 | digitalWrite(alarmLED, isAlarm); 59 | if (isAlarm) 60 | { 61 | isAlarm = !isAlarm; 62 | clock.clearAlarm1(); 63 | } 64 | 65 | delay(1000); 66 | } 67 | 68 | -------------------------------------------------------------------------------- /examples/DS3231_simple/DS3231_simple.ino: -------------------------------------------------------------------------------- 1 | /* 2 | DS3231: Real-Time Clock. Simple example 3 | Read more: www.jarzebski.pl/arduino/komponenty/zegar-czasu-rzeczywistego-rtc-ds3231.html 4 | GIT: https://github.com/jarzebski/Arduino-DS3231 5 | Web: http://www.jarzebski.pl 6 | (c) 2014 by Korneliusz Jarzebski 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | DS3231 clock; 13 | RTCDateTime dt; 14 | 15 | void setup() 16 | { 17 | Serial.begin(9600); 18 | 19 | // Initialize DS3231 20 | Serial.println("Initialize DS3231");; 21 | clock.begin(); 22 | 23 | // Set sketch compiling time 24 | clock.setDateTime(__DATE__, __TIME__); 25 | } 26 | 27 | void loop() 28 | { 29 | dt = clock.getDateTime(); 30 | 31 | // For leading zero look to DS3231_dateformat example 32 | 33 | Serial.print("Raw data: "); 34 | Serial.print(dt.year); Serial.print("-"); 35 | Serial.print(dt.month); Serial.print("-"); 36 | Serial.print(dt.day); Serial.print(" "); 37 | Serial.print(dt.hour); Serial.print(":"); 38 | Serial.print(dt.minute); Serial.print(":"); 39 | Serial.print(dt.second); Serial.println(""); 40 | 41 | delay(1000); 42 | } 43 | -------------------------------------------------------------------------------- /examples/DS3231_sqw_32khz/DS3231_sqw_32khz.ino: -------------------------------------------------------------------------------- 1 | /* 2 | DS3231: Real-Time Clock. SQW & 32kHz Example 3 | Read more: www.jarzebski.pl/arduino/komponenty/zegar-czasu-rzeczywistego-rtc-ds3231.html 4 | GIT: https://github.com/jarzebski/Arduino-DS3231 5 | Web: http://www.jarzebski.pl 6 | (c) 2014 by Korneliusz Jarzebski 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | DS3231 clock; 13 | 14 | boolean state; 15 | 16 | void setup() 17 | { 18 | Serial.begin(9600); 19 | 20 | // Initialize DS3231 21 | Serial.println("Initialize DS3231");; 22 | clock.begin(); 23 | 24 | // disable 32kHz 25 | clock.enable32kHz(false); 26 | 27 | // Select output as rate to 1Hz 28 | clock.setOutput(DS3231_1HZ); 29 | 30 | // Enable output 31 | clock.enableOutput(true); 32 | 33 | // Check config 34 | 35 | if (clock.isOutput()) 36 | { 37 | Serial.println("Oscilator is enabled"); 38 | } else 39 | { 40 | Serial.println("Oscilator is disabled"); 41 | } 42 | 43 | switch (clock.getOutput()) 44 | { 45 | case DS3231_1HZ: Serial.println("SQW = 1Hz"); break; 46 | case DS3231_4096HZ: Serial.println("SQW = 4096Hz"); break; 47 | case DS3231_8192HZ: Serial.println("SQW = 8192Hz"); break; 48 | case DS3231_32768HZ: Serial.println("SQW = 32768Hz"); break; 49 | default: Serial.println("SQW = Unknown"); break; } 50 | } 51 | 52 | void loop() 53 | { 54 | // Togle 32kHz output 55 | clock.enable32kHz(state); 56 | state = !state; 57 | delay(2000); 58 | } 59 | -------------------------------------------------------------------------------- /examples/DS3231_temperature/DS3231_temperature.ino: -------------------------------------------------------------------------------- 1 | /* 2 | DS3231: Real-Time Clock. Temperature example 3 | Read more: www.jarzebski.pl/arduino/komponenty/zegar-czasu-rzeczywistego-rtc-ds3231.html 4 | GIT: https://github.com/jarzebski/Arduino-DS3231 5 | Web: http://www.jarzebski.pl 6 | (c) 2014 by Korneliusz Jarzebski 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | DS3231 clock; 13 | RTCDateTime dt; 14 | 15 | void setup() 16 | { 17 | Serial.begin(9600); 18 | 19 | // Initialize DS3231 20 | Serial.println("Initialize DS3231");; 21 | clock.begin(); 22 | } 23 | 24 | void loop() 25 | { 26 | // The temperature registers are updated after every 64-second conversion. 27 | // If you want force temperature conversion use forceConversion() 28 | clock.forceConversion(); 29 | 30 | Serial.print("Temperature: "); 31 | Serial.println(clock.readTemperature()); 32 | 33 | delay(1000); 34 | } 35 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Syntax Coloring Map For INA226 3 | ########################################### 4 | 5 | ########################################### 6 | # Datatypes (KEYWORD1) 7 | ########################################### 8 | 9 | DS3231 KEYWORD1 10 | 11 | ########################################### 12 | # Methods and Functions (KEYWORD2) 13 | ########################################### 14 | begin KEYWORD2 15 | setDateTime KEYWORD2 16 | getDateTime KEYWORD2 17 | isReady KEYWORD2 18 | getOutput KEYWORD2 19 | setOutput KEYWORD2 20 | enableOutput KEYWORD2 21 | isOutput KEYWORD2 22 | enable32kHz KEYWORD2 23 | is32kHz KEYWORD2 24 | forceConversion KEYWORD2 25 | readTemperature KEYWORD2 26 | setAlarm1 KEYWORD2 27 | getAlarm1 KEYWORD2 28 | getAlarmType1 KEYWORD2 29 | isAlarm1 KEYWORD2 30 | armAlarm1 KEYWORD2 31 | isArmed1 KEYWORD2 32 | clearAlarm1 KEYWORD2 33 | setAlarm2 KEYWORD2 34 | getAlarm2 KEYWORD2 35 | getAlarmType2 KEYWORD2 36 | isAlarm2 KEYWORD2 37 | armAlarm2 KEYWORD2 38 | isArmed2 KEYWORD2 39 | clearAlarm2 KEYWORD2 40 | setBattery KEYWORD2 41 | dateFormat KEYWORD2 42 | loadDateTimeFromLong KEYWORD2 43 | 44 | ########################################### 45 | # Constants (LITERAL1) 46 | ########################################### 47 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Arduino-DS3231", 3 | "keywords": "DC3231, timer, clock, i2c", 4 | "description": "DS3231 Real-Time Clock", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/jarzebski/Arduino-DS3231" 8 | }, 9 | "authors": { 10 | "name": "Korneliusz Jarzębski", 11 | "url": "https://www.jarzebski.pl" 12 | }, 13 | "version": "1.1.0", 14 | "frameworks": "arduino", 15 | "platforms": "*" 16 | } 17 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=DS3231 Arduino Library 2 | version=1.1.0 3 | author=Korneliusz Jarzębski 4 | maintainer=Korneliusz Jarzębski 5 | sentence=DS3231 Real-Time Clock 6 | paragraph= 7 | category=Timing 8 | url=https://github.com/jarzebski/Arduino-DS3231 9 | architectures=* 10 | includes=DS3231.h 11 | depends= 12 | -------------------------------------------------------------------------------- /src/DS3231.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License 4 | 5 | Copyright (c) 2014-2023 Korneliusz Jarzębski 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | 25 | */ 26 | 27 | #if ARDUINO >= 100 28 | #include "Arduino.h" 29 | #else 30 | #include "WProgram.h" 31 | #endif 32 | 33 | #include 34 | #include "DS3231.h" 35 | 36 | const uint8_t daysArray [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 }; 37 | const uint8_t dowArray[] PROGMEM = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 }; 38 | 39 | bool DS3231::begin(void) 40 | { 41 | Wire.begin(); 42 | 43 | setBattery(true, false); 44 | 45 | t.year = 2000; 46 | t.month = 1; 47 | t.day = 1; 48 | t.hour = 0; 49 | t.minute = 0; 50 | t.second = 0; 51 | t.dayOfWeek = 6; 52 | t.unixtime = 946681200; 53 | 54 | return true; 55 | } 56 | 57 | void DS3231::setDateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) 58 | { 59 | Wire.beginTransmission(DS3231_ADDRESS); 60 | 61 | #if ARDUINO >= 100 62 | Wire.write(DS3231_REG_TIME); 63 | #else 64 | Wire.send(DS3231_REG_TIME); 65 | #endif 66 | 67 | #if ARDUINO >= 100 68 | Wire.write(dec2bcd(second)); 69 | Wire.write(dec2bcd(minute)); 70 | Wire.write(dec2bcd(hour)); 71 | Wire.write(dec2bcd(dow(year, month, day))); 72 | Wire.write(dec2bcd(day)); 73 | Wire.write(dec2bcd(month)); 74 | Wire.write(dec2bcd(year-2000)); 75 | #else 76 | Wire.send(dec2bcd(second)); 77 | Wire.send(dec2bcd(minute)); 78 | Wire.send(dec2bcd(hour)); 79 | Wire.send(dec2bcd(dow(year, month, day))); 80 | Wire.send(dec2bcd(day)); 81 | Wire.send(dec2bcd(month)); 82 | Wire.send(dec2bcd(year-2000)); 83 | #endif 84 | 85 | Wire.endTransmission(); 86 | } 87 | 88 | void DS3231::setDateTime(uint32_t t) 89 | { 90 | t -= 946681200; 91 | 92 | uint16_t year; 93 | uint8_t month; 94 | uint8_t day; 95 | uint8_t hour; 96 | uint8_t minute; 97 | uint8_t second; 98 | 99 | second = t % 60; 100 | t /= 60; 101 | 102 | minute = t % 60; 103 | t /= 60; 104 | 105 | hour = t % 24; 106 | uint16_t days = t / 24; 107 | uint8_t leap; 108 | 109 | for (year = 0; ; ++year) 110 | { 111 | leap = year % 4 == 0; 112 | if (days < 365 + leap) 113 | { 114 | break; 115 | } 116 | days -= 365 + leap; 117 | } 118 | 119 | for (month = 1; ; ++month) 120 | { 121 | uint8_t daysPerMonth = pgm_read_byte(daysArray + month - 1); 122 | 123 | if (leap && month == 2) 124 | { 125 | ++daysPerMonth; 126 | } 127 | 128 | if (days < daysPerMonth) 129 | { 130 | break; 131 | } 132 | days -= daysPerMonth; 133 | } 134 | 135 | day = days + 1; 136 | 137 | setDateTime(year+2000, month, day, hour, minute, second); 138 | } 139 | 140 | 141 | RTCDateTime DS3231::loadDateTimeFromLong(uint32_t t) 142 | { 143 | t -= 946681200; 144 | 145 | uint16_t year; 146 | uint8_t month; 147 | uint8_t day; 148 | uint8_t hour; 149 | uint8_t minute; 150 | uint8_t second; 151 | 152 | second = t % 60; 153 | t /= 60; 154 | 155 | minute = t % 60; 156 | t /= 60; 157 | 158 | hour = t % 24; 159 | uint16_t days = t / 24; 160 | uint8_t leap; 161 | 162 | for (year = 0; ; ++year) 163 | { 164 | leap = year % 4 == 0; 165 | if (days < 365 + leap) 166 | { 167 | break; 168 | } 169 | days -= 365 + leap; 170 | } 171 | 172 | for (month = 1; ; ++month) 173 | { 174 | uint8_t daysPerMonth = pgm_read_byte(daysArray + month - 1); 175 | 176 | if (leap && month == 2) 177 | { 178 | ++daysPerMonth; 179 | } 180 | 181 | if (days < daysPerMonth) 182 | { 183 | break; 184 | } 185 | days -= daysPerMonth; 186 | } 187 | 188 | day = days + 1; 189 | 190 | RTCDateTime temp; 191 | temp.year = year+2000; 192 | temp.month = month; 193 | temp.day = day; 194 | temp.hour = hour; 195 | temp.minute = minute; 196 | temp.second = second; 197 | 198 | return temp; 199 | } 200 | 201 | void DS3231::setDateTime(const char* date, const char* time) 202 | { 203 | uint16_t year; 204 | uint8_t month; 205 | uint8_t day; 206 | uint8_t hour; 207 | uint8_t minute; 208 | uint8_t second; 209 | 210 | year = conv2d(date + 9); 211 | 212 | switch (date[0]) 213 | { 214 | case 'J': month = date[1] == 'a' ? 1 : month = date[2] == 'n' ? 6 : 7; break; 215 | case 'F': month = 2; break; 216 | case 'A': month = date[2] == 'r' ? 4 : 8; break; 217 | case 'M': month = date[2] == 'r' ? 3 : 5; break; 218 | case 'S': month = 9; break; 219 | case 'O': month = 10; break; 220 | case 'N': month = 11; break; 221 | case 'D': month = 12; break; 222 | } 223 | 224 | day = conv2d(date + 4); 225 | hour = conv2d(time); 226 | minute = conv2d(time + 3); 227 | second = conv2d(time + 6); 228 | 229 | setDateTime(year+2000, month, day, hour, minute, second); 230 | } 231 | 232 | char* DS3231::dateFormat(const char* dateFormat, RTCDateTime dt) 233 | { 234 | static char buffer[255]; 235 | 236 | buffer[0] = 0; 237 | 238 | char helper[11]; 239 | 240 | while (*dateFormat != '\0') 241 | { 242 | switch (dateFormat[0]) 243 | { 244 | // Day decoder 245 | case 'd': 246 | sprintf(helper, "%02d", dt.day); 247 | strcat(buffer, (const char *)helper); 248 | break; 249 | case 'j': 250 | sprintf(helper, "%d", dt.day); 251 | strcat(buffer, (const char *)helper); 252 | break; 253 | case 'l': 254 | strcat(buffer, (const char *)strDayOfWeek(dt.dayOfWeek)); 255 | break; 256 | case 'D': 257 | strncat(buffer, strDayOfWeek(dt.dayOfWeek), 3); 258 | break; 259 | case 'N': 260 | sprintf(helper, "%d", dt.dayOfWeek); 261 | strcat(buffer, (const char *)helper); 262 | break; 263 | case 'w': 264 | sprintf(helper, "%d", (dt.dayOfWeek + 7) % 7); 265 | strcat(buffer, (const char *)helper); 266 | break; 267 | case 'z': 268 | sprintf(helper, "%d", dayInYear(dt.year, dt.month, dt.day)); 269 | strcat(buffer, (const char *)helper); 270 | break; 271 | case 'S': 272 | strcat(buffer, (const char *)strDaySufix(dt.day)); 273 | break; 274 | 275 | // Month decoder 276 | case 'm': 277 | sprintf(helper, "%02d", dt.month); 278 | strcat(buffer, (const char *)helper); 279 | break; 280 | case 'n': 281 | sprintf(helper, "%d", dt.month); 282 | strcat(buffer, (const char *)helper); 283 | break; 284 | case 'F': 285 | strcat(buffer, (const char *)strMonth(dt.month)); 286 | break; 287 | case 'M': 288 | strncat(buffer, (const char *)strMonth(dt.month), 3); 289 | break; 290 | case 't': 291 | sprintf(helper, "%d", daysInMonth(dt.year, dt.month)); 292 | strcat(buffer, (const char *)helper); 293 | break; 294 | 295 | // Year decoder 296 | case 'Y': 297 | sprintf(helper, "%d", dt.year); 298 | strcat(buffer, (const char *)helper); 299 | break; 300 | case 'y': sprintf(helper, "%02d", dt.year-2000); 301 | strcat(buffer, (const char *)helper); 302 | break; 303 | case 'L': 304 | sprintf(helper, "%d", isLeapYear(dt.year)); 305 | strcat(buffer, (const char *)helper); 306 | break; 307 | 308 | // Hour decoder 309 | case 'H': 310 | sprintf(helper, "%02d", dt.hour); 311 | strcat(buffer, (const char *)helper); 312 | break; 313 | case 'G': 314 | sprintf(helper, "%d", dt.hour); 315 | strcat(buffer, (const char *)helper); 316 | break; 317 | case 'h': 318 | sprintf(helper, "%02d", hour12(dt.hour)); 319 | strcat(buffer, (const char *)helper); 320 | break; 321 | case 'g': 322 | sprintf(helper, "%d", hour12(dt.hour)); 323 | strcat(buffer, (const char *)helper); 324 | break; 325 | case 'A': 326 | strcat(buffer, (const char *)strAmPm(dt.hour, true)); 327 | break; 328 | case 'a': 329 | strcat(buffer, (const char *)strAmPm(dt.hour, false)); 330 | break; 331 | 332 | // Minute decoder 333 | case 'i': 334 | sprintf(helper, "%02d", dt.minute); 335 | strcat(buffer, (const char *)helper); 336 | break; 337 | 338 | // Second decoder 339 | case 's': 340 | sprintf(helper, "%02d", dt.second); 341 | strcat(buffer, (const char *)helper); 342 | break; 343 | 344 | // Misc decoder 345 | case 'U': 346 | sprintf(helper, "%lu", dt.unixtime); 347 | strcat(buffer, (const char *)helper); 348 | break; 349 | 350 | default: 351 | strncat(buffer, dateFormat, 1); 352 | break; 353 | } 354 | dateFormat++; 355 | } 356 | 357 | return buffer; 358 | } 359 | 360 | char* DS3231::dateFormat(const char* dateFormat, RTCAlarmTime dt) 361 | { 362 | static char buffer[255]; 363 | 364 | buffer[0] = 0; 365 | 366 | char helper[11]; 367 | 368 | while (*dateFormat != '\0') 369 | { 370 | switch (dateFormat[0]) 371 | { 372 | // Day decoder 373 | case 'd': 374 | sprintf(helper, "%02d", dt.day); 375 | strcat(buffer, (const char *)helper); 376 | break; 377 | case 'j': 378 | sprintf(helper, "%d", dt.day); 379 | strcat(buffer, (const char *)helper); 380 | break; 381 | case 'l': 382 | strcat(buffer, (const char *)strDayOfWeek(dt.day)); 383 | break; 384 | case 'D': 385 | strncat(buffer, strDayOfWeek(dt.day), 3); 386 | break; 387 | case 'N': 388 | sprintf(helper, "%d", dt.day); 389 | strcat(buffer, (const char *)helper); 390 | break; 391 | case 'w': 392 | sprintf(helper, "%d", (dt.day + 7) % 7); 393 | strcat(buffer, (const char *)helper); 394 | break; 395 | case 'S': 396 | strcat(buffer, (const char *)strDaySufix(dt.day)); 397 | break; 398 | 399 | // Hour decoder 400 | case 'H': 401 | sprintf(helper, "%02d", dt.hour); 402 | strcat(buffer, (const char *)helper); 403 | break; 404 | case 'G': 405 | sprintf(helper, "%d", dt.hour); 406 | strcat(buffer, (const char *)helper); 407 | break; 408 | case 'h': 409 | sprintf(helper, "%02d", hour12(dt.hour)); 410 | strcat(buffer, (const char *)helper); 411 | break; 412 | case 'g': 413 | sprintf(helper, "%d", hour12(dt.hour)); 414 | strcat(buffer, (const char *)helper); 415 | break; 416 | case 'A': 417 | strcat(buffer, (const char *)strAmPm(dt.hour, true)); 418 | break; 419 | case 'a': 420 | strcat(buffer, (const char *)strAmPm(dt.hour, false)); 421 | break; 422 | 423 | // Minute decoder 424 | case 'i': 425 | sprintf(helper, "%02d", dt.minute); 426 | strcat(buffer, (const char *)helper); 427 | break; 428 | 429 | // Second decoder 430 | case 's': 431 | sprintf(helper, "%02d", dt.second); 432 | strcat(buffer, (const char *)helper); 433 | break; 434 | 435 | default: 436 | strncat(buffer, dateFormat, 1); 437 | break; 438 | } 439 | dateFormat++; 440 | } 441 | 442 | return buffer; 443 | } 444 | 445 | RTCDateTime DS3231::getDateTime(void) 446 | { 447 | int values[7]; 448 | 449 | Wire.beginTransmission(DS3231_ADDRESS); 450 | #if ARDUINO >= 100 451 | Wire.write(DS3231_REG_TIME); 452 | #else 453 | Wire.send(DS3231_REG_TIME); 454 | #endif 455 | Wire.endTransmission(); 456 | 457 | Wire.requestFrom(DS3231_ADDRESS, 7); 458 | 459 | for (int i = 6; i >= 0; i--) 460 | { 461 | #if ARDUINO >= 100 462 | values[i] = bcd2dec(Wire.read()); 463 | #else 464 | values[i] = bcd2dec(Wire.receive()); 465 | #endif 466 | } 467 | 468 | t.year = values[0] + 2000; 469 | t.month = values[1]; 470 | t.day = values[2]; 471 | t.dayOfWeek = values[3]; 472 | t.hour = values[4]; 473 | t.minute = values[5]; 474 | t.second = values[6]; 475 | t.unixtime = unixtime(); 476 | 477 | return t; 478 | } 479 | 480 | uint8_t DS3231::isReady(void) 481 | { 482 | return true; 483 | } 484 | 485 | void DS3231::enableOutput(bool enabled) 486 | { 487 | uint8_t value; 488 | 489 | value = readRegister8(DS3231_REG_CONTROL); 490 | 491 | value &= 0b11111011; 492 | value |= (!enabled << 2); 493 | 494 | writeRegister8(DS3231_REG_CONTROL, value); 495 | } 496 | 497 | void DS3231::setBattery(bool timeBattery, bool squareBattery) 498 | { 499 | uint8_t value; 500 | 501 | value = readRegister8(DS3231_REG_CONTROL); 502 | 503 | if (squareBattery) 504 | { 505 | value |= 0b01000000; 506 | } else 507 | { 508 | value &= 0b10111111; 509 | } 510 | 511 | if (timeBattery) 512 | { 513 | value &= 0b01111011; 514 | } else 515 | { 516 | value |= 0b10000000; 517 | } 518 | 519 | writeRegister8(DS3231_REG_CONTROL, value); 520 | } 521 | 522 | bool DS3231::isOutput(void) 523 | { 524 | uint8_t value; 525 | 526 | value = readRegister8(DS3231_REG_CONTROL); 527 | 528 | value &= 0b00000100; 529 | value >>= 2; 530 | 531 | return !value; 532 | } 533 | 534 | void DS3231::setOutput(DS3231_sqw_t mode) 535 | { 536 | uint8_t value; 537 | 538 | value = readRegister8(DS3231_REG_CONTROL); 539 | 540 | value &= 0b11100111; 541 | value |= (mode << 3); 542 | 543 | writeRegister8(DS3231_REG_CONTROL, value); 544 | } 545 | 546 | DS3231_sqw_t DS3231::getOutput(void) 547 | { 548 | uint8_t value; 549 | 550 | value = readRegister8(DS3231_REG_CONTROL); 551 | 552 | value &= 0b00011000; 553 | value >>= 3; 554 | 555 | return (DS3231_sqw_t)value; 556 | } 557 | 558 | void DS3231::enable32kHz(bool enabled) 559 | { 560 | uint8_t value; 561 | 562 | value = readRegister8(DS3231_REG_STATUS); 563 | 564 | value &= 0b11110111; 565 | value |= (enabled << 3); 566 | 567 | writeRegister8(DS3231_REG_STATUS, value); 568 | } 569 | 570 | bool DS3231::is32kHz(void) 571 | { 572 | uint8_t value; 573 | 574 | value = readRegister8(DS3231_REG_STATUS); 575 | 576 | value &= 0b00001000; 577 | value >>= 3; 578 | 579 | return value; 580 | } 581 | 582 | void DS3231::forceConversion(void) 583 | { 584 | uint8_t value; 585 | 586 | value = readRegister8(DS3231_REG_CONTROL); 587 | 588 | value |= 0b00100000; 589 | 590 | writeRegister8(DS3231_REG_CONTROL, value); 591 | 592 | do {} while ((readRegister8(DS3231_REG_CONTROL) & 0b00100000) != 0); 593 | } 594 | 595 | float DS3231::readTemperature(void) 596 | { 597 | uint8_t msb, lsb; 598 | 599 | Wire.beginTransmission(DS3231_ADDRESS); 600 | #if ARDUINO >= 100 601 | Wire.write(DS3231_REG_TEMPERATURE); 602 | #else 603 | Wire.send(DS3231_REG_TEMPERATURE); 604 | #endif 605 | Wire.endTransmission(); 606 | 607 | Wire.requestFrom(DS3231_ADDRESS, 2); 608 | 609 | #if ARDUINO >= 100 610 | msb = Wire.read(); 611 | lsb = Wire.read(); 612 | #else 613 | msb = Wire.receive(); 614 | lsb = Wire.receive(); 615 | #endif 616 | 617 | return ((((short)msb << 8) | (short)lsb) >> 6) / 4.0f; 618 | } 619 | 620 | RTCAlarmTime DS3231::getAlarm1(void) 621 | { 622 | uint8_t values[4]; 623 | RTCAlarmTime a; 624 | 625 | Wire.beginTransmission(DS3231_ADDRESS); 626 | #if ARDUINO >= 100 627 | Wire.write(DS3231_REG_ALARM_1); 628 | #else 629 | Wire.send(DS3231_REG_ALARM_1); 630 | #endif 631 | Wire.endTransmission(); 632 | 633 | Wire.requestFrom(DS3231_ADDRESS, 4); 634 | 635 | for (int i = 3; i >= 0; i--) 636 | { 637 | #if ARDUINO >= 100 638 | values[i] = bcd2dec(Wire.read() & 0b01111111); 639 | #else 640 | values[i] = bcd2dec(Wire.receive() & 0b01111111); 641 | #endif 642 | } 643 | 644 | a.day = values[0]; 645 | a.hour = values[1]; 646 | a.minute = values[2]; 647 | a.second = values[3]; 648 | 649 | return a; 650 | } 651 | 652 | DS3231_alarm1_t DS3231::getAlarmType1(void) 653 | { 654 | uint8_t values[4]; 655 | uint8_t mode = 0; 656 | 657 | Wire.beginTransmission(DS3231_ADDRESS); 658 | #if ARDUINO >= 100 659 | Wire.write(DS3231_REG_ALARM_1); 660 | #else 661 | Wire.send(DS3231_REG_ALARM_1); 662 | #endif 663 | Wire.endTransmission(); 664 | 665 | Wire.requestFrom(DS3231_ADDRESS, 4); 666 | 667 | for (int i = 3; i >= 0; i--) 668 | { 669 | #if ARDUINO >= 100 670 | values[i] = bcd2dec(Wire.read()); 671 | #else 672 | values[i] = bcd2dec(Wire.receive()); 673 | #endif 674 | } 675 | 676 | mode |= ((values[3] & 0b01000000) >> 6); 677 | mode |= ((values[2] & 0b01000000) >> 5); 678 | mode |= ((values[1] & 0b01000000) >> 4); 679 | mode |= ((values[0] & 0b01000000) >> 3); 680 | mode |= ((values[0] & 0b00100000) >> 1); 681 | 682 | return (DS3231_alarm1_t)mode; 683 | } 684 | 685 | void DS3231::setAlarm1(uint8_t dydw, uint8_t hour, uint8_t minute, uint8_t second, DS3231_alarm1_t mode, bool armed) 686 | { 687 | second = dec2bcd(second); 688 | minute = dec2bcd(minute); 689 | hour = dec2bcd(hour); 690 | dydw = dec2bcd(dydw); 691 | 692 | switch(mode) 693 | { 694 | case DS3231_EVERY_SECOND: 695 | second |= 0b10000000; 696 | minute |= 0b10000000; 697 | hour |= 0b10000000; 698 | dydw |= 0b10000000; 699 | break; 700 | 701 | case DS3231_MATCH_S: 702 | second &= 0b01111111; 703 | minute |= 0b10000000; 704 | hour |= 0b10000000; 705 | dydw |= 0b10000000; 706 | break; 707 | 708 | case DS3231_MATCH_M_S: 709 | second &= 0b01111111; 710 | minute &= 0b01111111; 711 | hour |= 0b10000000; 712 | dydw |= 0b10000000; 713 | break; 714 | 715 | case DS3231_MATCH_H_M_S: 716 | second &= 0b01111111; 717 | minute &= 0b01111111; 718 | hour &= 0b01111111; 719 | dydw |= 0b10000000; 720 | break; 721 | 722 | case DS3231_MATCH_DT_H_M_S: 723 | second &= 0b01111111; 724 | minute &= 0b01111111; 725 | hour &= 0b01111111; 726 | dydw &= 0b01111111; 727 | break; 728 | 729 | case DS3231_MATCH_DY_H_M_S: 730 | second &= 0b01111111; 731 | minute &= 0b01111111; 732 | hour &= 0b01111111; 733 | dydw &= 0b01111111; 734 | dydw |= 0b01000000; 735 | break; 736 | } 737 | 738 | Wire.beginTransmission(DS3231_ADDRESS); 739 | #if ARDUINO >= 100 740 | Wire.write(DS3231_REG_ALARM_1); 741 | Wire.write(second); 742 | Wire.write(minute); 743 | Wire.write(hour); 744 | Wire.write(dydw); 745 | #else 746 | Wire.send(DS3231_REG_ALARM_1); 747 | Wire.send(second); 748 | Wire.send(minute); 749 | Wire.send(hour); 750 | Wire.send(dydw); 751 | #endif 752 | 753 | Wire.endTransmission(); 754 | 755 | armAlarm1(armed); 756 | 757 | clearAlarm1(); 758 | } 759 | 760 | bool DS3231::isAlarm1(bool clear) 761 | { 762 | uint8_t alarm; 763 | 764 | alarm = readRegister8(DS3231_REG_STATUS); 765 | alarm &= 0b00000001; 766 | 767 | if (alarm && clear) 768 | { 769 | clearAlarm1(); 770 | } 771 | 772 | return alarm; 773 | } 774 | 775 | void DS3231::armAlarm1(bool armed) 776 | { 777 | uint8_t value; 778 | value = readRegister8(DS3231_REG_CONTROL); 779 | 780 | if (armed) 781 | { 782 | value |= 0b00000001; 783 | } else 784 | { 785 | value &= 0b11111110; 786 | } 787 | 788 | writeRegister8(DS3231_REG_CONTROL, value); 789 | } 790 | 791 | bool DS3231::isArmed1(void) 792 | { 793 | uint8_t value; 794 | value = readRegister8(DS3231_REG_CONTROL); 795 | value &= 0b00000001; 796 | return value; 797 | } 798 | 799 | void DS3231::clearAlarm1(void) 800 | { 801 | uint8_t value; 802 | 803 | value = readRegister8(DS3231_REG_STATUS); 804 | value &= 0b11111110; 805 | 806 | writeRegister8(DS3231_REG_STATUS, value); 807 | } 808 | 809 | RTCAlarmTime DS3231::getAlarm2(void) 810 | { 811 | uint8_t values[3]; 812 | RTCAlarmTime a; 813 | 814 | Wire.beginTransmission(DS3231_ADDRESS); 815 | #if ARDUINO >= 100 816 | Wire.write(DS3231_REG_ALARM_2); 817 | #else 818 | Wire.send(DS3231_REG_ALARM_2); 819 | #endif 820 | Wire.endTransmission(); 821 | 822 | Wire.requestFrom(DS3231_ADDRESS, 3); 823 | 824 | for (int i = 2; i >= 0; i--) 825 | { 826 | #if ARDUINO >= 100 827 | values[i] = bcd2dec(Wire.read() & 0b01111111); 828 | #else 829 | values[i] = bcd2dec(Wire.receive() & 0b01111111); 830 | #endif 831 | } 832 | 833 | a.day = values[0]; 834 | a.hour = values[1]; 835 | a.minute = values[2]; 836 | a.second = 0; 837 | 838 | return a; 839 | } 840 | 841 | DS3231_alarm2_t DS3231::getAlarmType2(void) 842 | { 843 | uint8_t values[3]; 844 | uint8_t mode = 0; 845 | 846 | Wire.beginTransmission(DS3231_ADDRESS); 847 | #if ARDUINO >= 100 848 | Wire.write(DS3231_REG_ALARM_2); 849 | #else 850 | Wire.send(DS3231_REG_ALARM_2); 851 | #endif 852 | Wire.endTransmission(); 853 | 854 | Wire.requestFrom(DS3231_ADDRESS, 3); 855 | 856 | for (int i = 2; i >= 0; i--) 857 | { 858 | #if ARDUINO >= 100 859 | values[i] = bcd2dec(Wire.read()); 860 | #else 861 | values[i] = bcd2dec(Wire.receive()); 862 | #endif 863 | } 864 | 865 | mode |= ((values[2] & 0b01000000) >> 5); 866 | mode |= ((values[1] & 0b01000000) >> 4); 867 | mode |= ((values[0] & 0b01000000) >> 3); 868 | mode |= ((values[0] & 0b00100000) >> 1); 869 | 870 | return (DS3231_alarm2_t)mode; 871 | } 872 | 873 | void DS3231::setAlarm2(uint8_t dydw, uint8_t hour, uint8_t minute, DS3231_alarm2_t mode, bool armed) 874 | { 875 | minute = dec2bcd(minute); 876 | hour = dec2bcd(hour); 877 | dydw = dec2bcd(dydw); 878 | 879 | switch(mode) 880 | { 881 | case DS3231_EVERY_MINUTE: 882 | minute |= 0b10000000; 883 | hour |= 0b10000000; 884 | dydw |= 0b10000000; 885 | break; 886 | 887 | case DS3231_MATCH_M: 888 | minute &= 0b01111111; 889 | hour |= 0b10000000; 890 | dydw |= 0b10000000; 891 | break; 892 | 893 | case DS3231_MATCH_H_M: 894 | minute &= 0b01111111; 895 | hour &= 0b01111111; 896 | dydw |= 0b10000000; 897 | break; 898 | 899 | case DS3231_MATCH_DT_H_M: 900 | minute &= 0b01111111; 901 | hour &= 0b01111111; 902 | dydw &= 0b01111111; 903 | break; 904 | 905 | case DS3231_MATCH_DY_H_M: 906 | minute &= 0b01111111; 907 | hour &= 0b01111111; 908 | dydw &= 0b01111111; 909 | dydw |= 0b01000000; 910 | break; 911 | } 912 | 913 | Wire.beginTransmission(DS3231_ADDRESS); 914 | #if ARDUINO >= 100 915 | Wire.write(DS3231_REG_ALARM_2); 916 | Wire.write(minute); 917 | Wire.write(hour); 918 | Wire.write(dydw); 919 | #else 920 | Wire.send(DS3231_REG_ALARM_2); 921 | Wire.send(minute); 922 | Wire.send(hour); 923 | Wire.send(dydw); 924 | #endif 925 | 926 | Wire.endTransmission(); 927 | 928 | armAlarm2(armed); 929 | 930 | clearAlarm2(); 931 | } 932 | 933 | void DS3231::armAlarm2(bool armed) 934 | { 935 | uint8_t value; 936 | value = readRegister8(DS3231_REG_CONTROL); 937 | 938 | if (armed) 939 | { 940 | value |= 0b00000010; 941 | } else 942 | { 943 | value &= 0b11111101; 944 | } 945 | 946 | writeRegister8(DS3231_REG_CONTROL, value); 947 | } 948 | 949 | bool DS3231::isArmed2(void) 950 | { 951 | uint8_t value; 952 | value = readRegister8(DS3231_REG_CONTROL); 953 | value &= 0b00000010; 954 | value >>= 1; 955 | return value; 956 | } 957 | 958 | 959 | void DS3231::clearAlarm2(void) 960 | { 961 | uint8_t value; 962 | 963 | value = readRegister8(DS3231_REG_STATUS); 964 | value &= 0b11111101; 965 | 966 | writeRegister8(DS3231_REG_STATUS, value); 967 | } 968 | 969 | 970 | bool DS3231::isAlarm2(bool clear) 971 | { 972 | uint8_t alarm; 973 | 974 | alarm = readRegister8(DS3231_REG_STATUS); 975 | alarm &= 0b00000010; 976 | 977 | if (alarm && clear) 978 | { 979 | clearAlarm2(); 980 | } 981 | 982 | return alarm; 983 | } 984 | 985 | uint8_t DS3231::bcd2dec(uint8_t bcd) 986 | { 987 | return ((bcd / 16) * 10) + (bcd % 16); 988 | } 989 | 990 | uint8_t DS3231::dec2bcd(uint8_t dec) 991 | { 992 | return ((dec / 10) * 16) + (dec % 10); 993 | } 994 | 995 | char *DS3231::strDayOfWeek(uint8_t dayOfWeek) 996 | { 997 | switch (dayOfWeek) { 998 | case 1: 999 | return (char*) "Monday"; 1000 | break; 1001 | case 2: 1002 | return (char*) "Tuesday"; 1003 | break; 1004 | case 3: 1005 | return (char*) "Wednesday"; 1006 | break; 1007 | case 4: 1008 | return (char*) "Thursday"; 1009 | break; 1010 | case 5: 1011 | return (char*) "Friday"; 1012 | break; 1013 | case 6: 1014 | return (char*) "Saturday"; 1015 | break; 1016 | case 7: 1017 | return (char*) "Sunday"; 1018 | break; 1019 | default: 1020 | return (char*) "Unknown"; 1021 | } 1022 | } 1023 | 1024 | char *DS3231::strMonth(uint8_t month) 1025 | { 1026 | switch (month) { 1027 | case 1: 1028 | return (char*) "January"; 1029 | break; 1030 | case 2: 1031 | return (char*) "February"; 1032 | break; 1033 | case 3: 1034 | return (char*) "March"; 1035 | break; 1036 | case 4: 1037 | return (char*) "April"; 1038 | break; 1039 | case 5: 1040 | return (char*) "May"; 1041 | break; 1042 | case 6: 1043 | return (char*) "June"; 1044 | break; 1045 | case 7: 1046 | return (char*) "July"; 1047 | break; 1048 | case 8: 1049 | return (char*) "August"; 1050 | break; 1051 | case 9: 1052 | return (char*) "September"; 1053 | break; 1054 | case 10: 1055 | return (char*) "October"; 1056 | break; 1057 | case 11: 1058 | return (char*) "November"; 1059 | break; 1060 | case 12: 1061 | return (char*) "December"; 1062 | break; 1063 | default: 1064 | return (char*) "Unknown"; 1065 | } 1066 | } 1067 | 1068 | char *DS3231::strAmPm(uint8_t hour, bool uppercase) 1069 | { 1070 | if (hour < 12) 1071 | { 1072 | if (uppercase) 1073 | { 1074 | return (char*) "AM"; 1075 | } else 1076 | { 1077 | return (char*) "am"; 1078 | } 1079 | } else 1080 | { 1081 | if (uppercase) 1082 | { 1083 | return (char*) "PM"; 1084 | } else 1085 | { 1086 | return (char*) "pm"; 1087 | } 1088 | } 1089 | } 1090 | 1091 | char *DS3231::strDaySufix(uint8_t day) 1092 | { 1093 | if (day >= 11 && day <= 13) 1094 | { 1095 | return (char*) "th"; 1096 | } 1097 | 1098 | switch (day % 10) 1099 | { 1100 | case 1: 1101 | return (char*) "st"; 1102 | break; 1103 | case 2: 1104 | return (char*) "nd"; 1105 | break; 1106 | case 3: 1107 | return (char*) "rd"; 1108 | break; 1109 | default: 1110 | return (char*) "th"; 1111 | break; 1112 | } 1113 | } 1114 | 1115 | uint8_t DS3231::hour12(uint8_t hour24) 1116 | { 1117 | if (hour24 == 0) 1118 | { 1119 | return 12; 1120 | } 1121 | 1122 | if (hour24 > 12) 1123 | { 1124 | return (hour24 - 12); 1125 | } 1126 | 1127 | return hour24; 1128 | } 1129 | 1130 | long DS3231::time2long(uint16_t days, uint8_t hours, uint8_t minutes, uint8_t seconds) 1131 | { 1132 | return ((days * 24L + hours) * 60 + minutes) * 60 + seconds; 1133 | } 1134 | 1135 | uint16_t DS3231::dayInYear(uint16_t year, uint8_t month, uint8_t day) 1136 | { 1137 | uint16_t fromDate; 1138 | uint16_t toDate; 1139 | 1140 | fromDate = date2days(year, 1, 1); 1141 | toDate = date2days(year, month, day); 1142 | 1143 | return (toDate - fromDate); 1144 | } 1145 | 1146 | bool DS3231::isLeapYear(uint16_t year) 1147 | { 1148 | return (year % 4 == 0); 1149 | } 1150 | 1151 | uint8_t DS3231::daysInMonth(uint16_t year, uint8_t month) 1152 | { 1153 | uint8_t days; 1154 | 1155 | days = pgm_read_byte(daysArray + month - 1); 1156 | 1157 | if ((month == 2) && isLeapYear(year)) 1158 | { 1159 | ++days; 1160 | } 1161 | 1162 | return days; 1163 | } 1164 | 1165 | uint16_t DS3231::date2days(uint16_t year, uint8_t month, uint8_t day) 1166 | { 1167 | year = year - 2000; 1168 | 1169 | uint16_t days16 = day; 1170 | 1171 | for (uint8_t i = 1; i < month; ++i) 1172 | { 1173 | days16 += pgm_read_byte(daysArray + i - 1); 1174 | if ((month == 1) && isLeapYear(year)) 1175 | { 1176 | ++days16; 1177 | } 1178 | } 1179 | 1180 | return days16 + 365 * year + (year + 3) / 4 - 1; 1181 | } 1182 | 1183 | uint32_t DS3231::unixtime(void) 1184 | { 1185 | uint32_t u; 1186 | 1187 | u = time2long(date2days(t.year, t.month, t.day), t.hour, t.minute, t.second); 1188 | u += 946681200; 1189 | 1190 | return u; 1191 | } 1192 | 1193 | uint8_t DS3231::conv2d(const char* p) 1194 | { 1195 | uint8_t v = 0; 1196 | 1197 | if ('0' <= *p && *p <= '9') 1198 | { 1199 | v = *p - '0'; 1200 | } 1201 | 1202 | return 10 * v + *++p - '0'; 1203 | } 1204 | 1205 | uint8_t DS3231::dow(uint16_t y, uint8_t m, uint8_t d) 1206 | { 1207 | uint8_t dow; 1208 | 1209 | y -= m < 3; 1210 | dow = ((y + y/4 - y/100 + y/400 + pgm_read_byte(dowArray+(m-1)) + d) % 7); 1211 | 1212 | if (dow == 0) 1213 | { 1214 | return 7; 1215 | } 1216 | 1217 | return dow; 1218 | } 1219 | 1220 | void DS3231::writeRegister8(uint8_t reg, uint8_t value) 1221 | { 1222 | Wire.beginTransmission(DS3231_ADDRESS); 1223 | #if ARDUINO >= 100 1224 | Wire.write(reg); 1225 | Wire.write(value); 1226 | #else 1227 | Wire.send(reg); 1228 | Wire.send(value); 1229 | #endif 1230 | Wire.endTransmission(); 1231 | } 1232 | 1233 | uint8_t DS3231::readRegister8(uint8_t reg) 1234 | { 1235 | uint8_t value; 1236 | Wire.beginTransmission(DS3231_ADDRESS); 1237 | #if ARDUINO >= 100 1238 | Wire.write(reg); 1239 | #else 1240 | Wire.send(reg); 1241 | #endif 1242 | Wire.endTransmission(); 1243 | 1244 | Wire.requestFrom(DS3231_ADDRESS, 1); 1245 | 1246 | #if ARDUINO >= 100 1247 | value = Wire.read(); 1248 | #else 1249 | value = Wire.receive(); 1250 | #endif 1251 | 1252 | return value; 1253 | } 1254 | -------------------------------------------------------------------------------- /src/DS3231.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License 4 | 5 | Copyright (c) 2014-2023 Korneliusz Jarzębski 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #ifndef DS3231_h 29 | #define DS3231_h 30 | 31 | #if ARDUINO >= 100 32 | #include "Arduino.h" 33 | #else 34 | #include "WProgram.h" 35 | #endif 36 | 37 | #define DS3231_ADDRESS (0x68) 38 | 39 | #define DS3231_REG_TIME (0x00) 40 | #define DS3231_REG_ALARM_1 (0x07) 41 | #define DS3231_REG_ALARM_2 (0x0B) 42 | #define DS3231_REG_CONTROL (0x0E) 43 | #define DS3231_REG_STATUS (0x0F) 44 | #define DS3231_REG_TEMPERATURE (0x11) 45 | 46 | #ifndef RTCDATETIME_STRUCT_H 47 | #define RTCDATETIME_STRUCT_H 48 | struct RTCDateTime 49 | { 50 | uint16_t year; 51 | uint8_t month; 52 | uint8_t day; 53 | uint8_t hour; 54 | uint8_t minute; 55 | uint8_t second; 56 | uint8_t dayOfWeek; 57 | uint32_t unixtime; 58 | }; 59 | 60 | struct RTCAlarmTime 61 | { 62 | uint8_t day; 63 | uint8_t hour; 64 | uint8_t minute; 65 | uint8_t second; 66 | }; 67 | #endif 68 | 69 | typedef enum 70 | { 71 | DS3231_1HZ = 0x00, 72 | DS3231_4096HZ = 0x01, 73 | DS3231_8192HZ = 0x02, 74 | DS3231_32768HZ = 0x03 75 | } DS3231_sqw_t; 76 | 77 | typedef enum 78 | { 79 | DS3231_EVERY_SECOND = 0b00001111, 80 | DS3231_MATCH_S = 0b00001110, 81 | DS3231_MATCH_M_S = 0b00001100, 82 | DS3231_MATCH_H_M_S = 0b00001000, 83 | DS3231_MATCH_DT_H_M_S = 0b00000000, 84 | DS3231_MATCH_DY_H_M_S = 0b00010000 85 | } DS3231_alarm1_t; 86 | 87 | typedef enum 88 | { 89 | DS3231_EVERY_MINUTE = 0b00001110, 90 | DS3231_MATCH_M = 0b00001100, 91 | DS3231_MATCH_H_M = 0b00001000, 92 | DS3231_MATCH_DT_H_M = 0b00000000, 93 | DS3231_MATCH_DY_H_M = 0b00010000 94 | } DS3231_alarm2_t; 95 | 96 | class DS3231 97 | { 98 | public: 99 | 100 | bool begin(void); 101 | 102 | void setDateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second); 103 | void setDateTime(uint32_t t); 104 | void setDateTime(const char* date, const char* time); 105 | RTCDateTime getDateTime(void); 106 | uint8_t isReady(void); 107 | 108 | DS3231_sqw_t getOutput(void); 109 | void setOutput(DS3231_sqw_t mode); 110 | void enableOutput(bool enabled); 111 | bool isOutput(void); 112 | void enable32kHz(bool enabled); 113 | bool is32kHz(void); 114 | 115 | void forceConversion(void); 116 | float readTemperature(void); 117 | 118 | void setAlarm1(uint8_t dydw, uint8_t hour, uint8_t minute, uint8_t second, DS3231_alarm1_t mode, bool armed = true); 119 | RTCAlarmTime getAlarm1(void); 120 | DS3231_alarm1_t getAlarmType1(void); 121 | bool isAlarm1(bool clear = true); 122 | void armAlarm1(bool armed); 123 | bool isArmed1(void); 124 | void clearAlarm1(void); 125 | 126 | void setAlarm2(uint8_t dydw, uint8_t hour, uint8_t minute, DS3231_alarm2_t mode, bool armed = true); 127 | RTCAlarmTime getAlarm2(void); 128 | DS3231_alarm2_t getAlarmType2(void); 129 | bool isAlarm2(bool clear = true); 130 | void armAlarm2(bool armed); 131 | bool isArmed2(void); 132 | void clearAlarm2(void); 133 | 134 | void setBattery(bool timeBattery, bool squareBattery); 135 | 136 | char* dateFormat(const char* dateFormat, RTCDateTime dt); 137 | char* dateFormat(const char* dateFormat, RTCAlarmTime dt); 138 | 139 | static RTCDateTime loadDateTimeFromLong(uint32_t t); 140 | 141 | private: 142 | RTCDateTime t; 143 | 144 | char *strDayOfWeek(uint8_t dayOfWeek); 145 | char *strMonth(uint8_t month); 146 | char *strAmPm(uint8_t hour, bool uppercase); 147 | char *strDaySufix(uint8_t day); 148 | 149 | uint8_t hour12(uint8_t hour24); 150 | uint8_t bcd2dec(uint8_t bcd); 151 | uint8_t dec2bcd(uint8_t dec); 152 | 153 | long time2long(uint16_t days, uint8_t hours, uint8_t minutes, uint8_t seconds); 154 | uint16_t date2days(uint16_t year, uint8_t month, uint8_t day); 155 | uint8_t daysInMonth(uint16_t year, uint8_t month); 156 | uint16_t dayInYear(uint16_t year, uint8_t month, uint8_t day); 157 | bool isLeapYear(uint16_t year); 158 | uint8_t dow(uint16_t y, uint8_t m, uint8_t d); 159 | 160 | uint32_t unixtime(void); 161 | uint8_t conv2d(const char* p); 162 | 163 | void writeRegister8(uint8_t reg, uint8_t value); 164 | uint8_t readRegister8(uint8_t reg); 165 | }; 166 | 167 | #endif 168 | --------------------------------------------------------------------------------