DS3231 External RTC I2C

Fork of DS3231 by Bird Techstep

Committer:
techstep
Date:
Wed Aug 06 03:03:29 2014 +0000
Revision:
1:1607610a4ee9
Parent:
0:e4fbbd93299b
Child:
2:fc6317727d1d
DS3231

Who changed what in which revision?

UserRevisionLine numberNew contents of line
techstep 0:e4fbbd93299b 1 /*****************************************************************************
techstep 0:e4fbbd93299b 2 * Type : C++
techstep 0:e4fbbd93299b 3 * File : DS3231.cpp
techstep 0:e4fbbd93299b 4 * Dec. : DS3231 + AT24C32 IIC Module Precision RTC Module Memory Module
techstep 0:e4fbbd93299b 5 * Copyright (c) 2013-2014, Bird Techstep, tbird_th@hotmail.com
techstep 0:e4fbbd93299b 6 *
techstep 0:e4fbbd93299b 7 * Remark Original codr from DS3231 Library [Arduino]
techstep 0:e4fbbd93299b 8 *
techstep 0:e4fbbd93299b 9 * Permission is hereby granted, free of charge, to any person obtaining a copy
techstep 0:e4fbbd93299b 10 * of this software and associated documentation files (the "Software"), to deal
techstep 0:e4fbbd93299b 11 * in the Software without restriction, including without limitation the rights
techstep 0:e4fbbd93299b 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
techstep 0:e4fbbd93299b 13 * copies of the Software, and to permit persons to whom the Software is
techstep 0:e4fbbd93299b 14 * furnished to do so, subject to the following conditions:
techstep 0:e4fbbd93299b 15 *
techstep 0:e4fbbd93299b 16 * The above copyright notice and this permission notice shall be included in
techstep 0:e4fbbd93299b 17 * all copies or substantial portions of the Software.
techstep 0:e4fbbd93299b 18 *
techstep 0:e4fbbd93299b 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
techstep 0:e4fbbd93299b 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
techstep 0:e4fbbd93299b 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
techstep 0:e4fbbd93299b 22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
techstep 0:e4fbbd93299b 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
techstep 0:e4fbbd93299b 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
techstep 0:e4fbbd93299b 25 * THE SOFTWARE.
techstep 0:e4fbbd93299b 26 *****************************************************************************/
techstep 0:e4fbbd93299b 27 #include "DS3231.h"
techstep 0:e4fbbd93299b 28 #define CLOCK_ADDRESS 0x68
techstep 0:e4fbbd93299b 29 #define ADDR char(CLOCK_ADDRESS<<1)
techstep 1:1607610a4ee9 30 #define SINCE 1900
techstep 0:e4fbbd93299b 31
techstep 0:e4fbbd93299b 32 // Constructor
techstep 0:e4fbbd93299b 33 DS3231::DS3231(PinName sda_pin, PinName scl_pin) : _i2c(sda_pin, scl_pin) {
techstep 0:e4fbbd93299b 34 _i2c.frequency(100000);
techstep 0:e4fbbd93299b 35 }
techstep 0:e4fbbd93299b 36 /*****************************************
techstep 0:e4fbbd93299b 37 Public Functions
techstep 0:e4fbbd93299b 38 *****************************************/
techstep 0:e4fbbd93299b 39
techstep 0:e4fbbd93299b 40 void DS3231::getTime(uint8_t& year, uint8_t& month, uint8_t& date, uint8_t& DoW, uint8_t& hour, uint8_t& minute, uint8_t& second) {
techstep 0:e4fbbd93299b 41 uint8_t tempBuffer;
techstep 0:e4fbbd93299b 42 bool PM;
techstep 0:e4fbbd93299b 43 bool h12;
techstep 0:e4fbbd93299b 44
techstep 1:1607610a4ee9 45 char data[7];
techstep 1:1607610a4ee9 46 char cmd;
techstep 1:1607610a4ee9 47 cmd = 0x00;
techstep 1:1607610a4ee9 48 _i2c.write(ADDR, &cmd, 1 );
techstep 1:1607610a4ee9 49 _i2c.read( ADDR, data, 7 );
techstep 0:e4fbbd93299b 50
techstep 1:1607610a4ee9 51 second = bcdToDec(data[0]);
techstep 1:1607610a4ee9 52 minute = bcdToDec(data[1]);
techstep 1:1607610a4ee9 53 tempBuffer = bcdToDec(data[2]);
techstep 0:e4fbbd93299b 54
techstep 0:e4fbbd93299b 55 h12 = tempBuffer & 0x40;
techstep 0:e4fbbd93299b 56 if (h12) {
techstep 0:e4fbbd93299b 57 PM = tempBuffer & 0x20;
techstep 0:e4fbbd93299b 58 hour = bcdToDec(tempBuffer & 0x1F);
techstep 0:e4fbbd93299b 59 } else {
techstep 0:e4fbbd93299b 60 hour = bcdToDec(tempBuffer & 0x3F);
techstep 0:e4fbbd93299b 61 }
techstep 1:1607610a4ee9 62 DoW = bcdToDec(data[3]);
techstep 1:1607610a4ee9 63 date = bcdToDec(data[4]);
techstep 1:1607610a4ee9 64 month = bcdToDec(data[5] & 0x7F);
techstep 1:1607610a4ee9 65 year = bcdToDec(data[6]);
techstep 0:e4fbbd93299b 66 }
techstep 0:e4fbbd93299b 67
techstep 0:e4fbbd93299b 68 int8_t DS3231::getSecond(void) {
techstep 0:e4fbbd93299b 69 char data;
techstep 0:e4fbbd93299b 70 char cmd;
techstep 0:e4fbbd93299b 71 cmd = 0x00;
techstep 0:e4fbbd93299b 72 _i2c.write(ADDR, &cmd, 1 );
techstep 0:e4fbbd93299b 73 _i2c.read( ADDR, &data, 1 );
techstep 0:e4fbbd93299b 74 return(bcdToDec(data));
techstep 0:e4fbbd93299b 75 }
techstep 0:e4fbbd93299b 76
techstep 0:e4fbbd93299b 77 uint8_t DS3231::getMinute(void) {
techstep 0:e4fbbd93299b 78 char data;
techstep 0:e4fbbd93299b 79 char cmd;
techstep 0:e4fbbd93299b 80 cmd = 0x01;
techstep 0:e4fbbd93299b 81 _i2c.write(ADDR, &cmd, 1 );
techstep 0:e4fbbd93299b 82 _i2c.read( ADDR, &data, 1 );
techstep 0:e4fbbd93299b 83 return(bcdToDec(data));
techstep 0:e4fbbd93299b 84 }
techstep 0:e4fbbd93299b 85
techstep 0:e4fbbd93299b 86 uint8_t DS3231::getHour(bool& h12, bool& PM) {
techstep 0:e4fbbd93299b 87 char temp_buffer;
techstep 0:e4fbbd93299b 88 char hour;
techstep 0:e4fbbd93299b 89 char cmd;
techstep 0:e4fbbd93299b 90 cmd = 0x02;
techstep 0:e4fbbd93299b 91 _i2c.write(ADDR, &cmd, 1 );
techstep 0:e4fbbd93299b 92 _i2c.read( ADDR, &temp_buffer, 1 );
techstep 0:e4fbbd93299b 93
techstep 0:e4fbbd93299b 94 h12 = temp_buffer & 0x40;
techstep 0:e4fbbd93299b 95 if (h12) {
techstep 0:e4fbbd93299b 96 PM = temp_buffer & 0x20;
techstep 0:e4fbbd93299b 97 hour = bcdToDec(temp_buffer & 0x1F);
techstep 0:e4fbbd93299b 98 } else {
techstep 0:e4fbbd93299b 99 hour = bcdToDec(temp_buffer & 0x3F);
techstep 0:e4fbbd93299b 100 }
techstep 0:e4fbbd93299b 101 return hour;
techstep 0:e4fbbd93299b 102 }
techstep 0:e4fbbd93299b 103
techstep 0:e4fbbd93299b 104 uint8_t DS3231::getDoW(void) {
techstep 0:e4fbbd93299b 105 char data;
techstep 0:e4fbbd93299b 106 char cmd;
techstep 0:e4fbbd93299b 107 cmd = 0x03;
techstep 0:e4fbbd93299b 108 _i2c.write(ADDR, &cmd, 1 );
techstep 0:e4fbbd93299b 109 _i2c.read( ADDR, &data, 1 );
techstep 0:e4fbbd93299b 110 return(bcdToDec(data));
techstep 0:e4fbbd93299b 111 }
techstep 0:e4fbbd93299b 112
techstep 0:e4fbbd93299b 113 uint8_t DS3231::getDate(void) {
techstep 0:e4fbbd93299b 114 char data;
techstep 0:e4fbbd93299b 115 char cmd;
techstep 0:e4fbbd93299b 116 cmd = 0x04;
techstep 0:e4fbbd93299b 117 _i2c.write(ADDR, &cmd, 1 );
techstep 0:e4fbbd93299b 118 _i2c.read( ADDR, &data, 1 );
techstep 0:e4fbbd93299b 119 return(bcdToDec(data));
techstep 0:e4fbbd93299b 120 }
techstep 0:e4fbbd93299b 121
techstep 0:e4fbbd93299b 122 uint8_t DS3231::getMonth(bool& Century) {
techstep 0:e4fbbd93299b 123 char temp_buffer;
techstep 0:e4fbbd93299b 124 char cmd;
techstep 0:e4fbbd93299b 125 cmd = 0x05;
techstep 0:e4fbbd93299b 126 _i2c.write(ADDR, &cmd, 1 );
techstep 0:e4fbbd93299b 127 _i2c.read( ADDR, &temp_buffer, 1 );
techstep 0:e4fbbd93299b 128
techstep 0:e4fbbd93299b 129 Century = temp_buffer & 0x80;
techstep 0:e4fbbd93299b 130 return (bcdToDec(temp_buffer & 0x7F)) ;
techstep 0:e4fbbd93299b 131 }
techstep 0:e4fbbd93299b 132
techstep 0:e4fbbd93299b 133 uint8_t DS3231::getYear(void) {
techstep 0:e4fbbd93299b 134 char data;
techstep 0:e4fbbd93299b 135 char cmd;
techstep 0:e4fbbd93299b 136 cmd = 0x06;
techstep 0:e4fbbd93299b 137 _i2c.write(ADDR, &cmd, 1 );
techstep 0:e4fbbd93299b 138 _i2c.read( ADDR, &data, 1 );
techstep 0:e4fbbd93299b 139 return(bcdToDec(data));
techstep 0:e4fbbd93299b 140 }
techstep 0:e4fbbd93299b 141
techstep 0:e4fbbd93299b 142 void DS3231::setSecond(uint8_t Second) {
techstep 0:e4fbbd93299b 143 // Sets the seconds
techstep 0:e4fbbd93299b 144 // This function also resets the Oscillator Stop Flag, which is set
techstep 0:e4fbbd93299b 145 // whenever power is interrupted.
techstep 0:e4fbbd93299b 146 char cmd[2];
techstep 0:e4fbbd93299b 147 cmd[0] = 0x00;
techstep 0:e4fbbd93299b 148 cmd[1] = decToBcd(Second);
techstep 0:e4fbbd93299b 149 _i2c.write(ADDR, cmd, 2);
techstep 0:e4fbbd93299b 150
techstep 0:e4fbbd93299b 151 // Clear OSF flag
techstep 0:e4fbbd93299b 152 uint8_t temp_buffer = readControlByte(1);
techstep 0:e4fbbd93299b 153 writeControlByte((temp_buffer & 0x7F), 1);
techstep 0:e4fbbd93299b 154 }
techstep 0:e4fbbd93299b 155
techstep 0:e4fbbd93299b 156 void DS3231::setMinute(uint8_t Minute) {
techstep 0:e4fbbd93299b 157 // Sets the minutes
techstep 0:e4fbbd93299b 158 char cmd[2];
techstep 0:e4fbbd93299b 159 cmd[0] = 0x01;
techstep 0:e4fbbd93299b 160 cmd[1] = decToBcd(Minute);
techstep 0:e4fbbd93299b 161 _i2c.write(ADDR, cmd, 2);
techstep 0:e4fbbd93299b 162 }
techstep 0:e4fbbd93299b 163
techstep 0:e4fbbd93299b 164 void DS3231::setHour(uint8_t Hour) {
techstep 0:e4fbbd93299b 165 // Sets the hour, without changing 12/24h mode.
techstep 0:e4fbbd93299b 166 // The hour must be in 24h format.
techstep 0:e4fbbd93299b 167
techstep 0:e4fbbd93299b 168 bool h12;
techstep 0:e4fbbd93299b 169
techstep 0:e4fbbd93299b 170 // Start by figuring out what the 12/24 mode is
techstep 0:e4fbbd93299b 171 char data;
techstep 0:e4fbbd93299b 172 char cmd;
techstep 0:e4fbbd93299b 173 cmd = 0x02;
techstep 0:e4fbbd93299b 174 _i2c.write(ADDR, &cmd, 1 );
techstep 0:e4fbbd93299b 175 _i2c.read( ADDR, &data, 1 );
techstep 0:e4fbbd93299b 176
techstep 0:e4fbbd93299b 177 h12 = (data & 0x40);
techstep 0:e4fbbd93299b 178 // if h12 is true, it's 12h mode; false is 24h.
techstep 0:e4fbbd93299b 179
techstep 0:e4fbbd93299b 180 if (h12) {
techstep 0:e4fbbd93299b 181 // 12 hour
techstep 0:e4fbbd93299b 182 if (Hour > 12) {
techstep 0:e4fbbd93299b 183 Hour = decToBcd(Hour-12) | 0x60;
techstep 0:e4fbbd93299b 184 } else {
techstep 0:e4fbbd93299b 185 Hour = decToBcd(Hour) & 0xDF;
techstep 0:e4fbbd93299b 186 }
techstep 0:e4fbbd93299b 187 } else {
techstep 0:e4fbbd93299b 188 // 24 hour
techstep 0:e4fbbd93299b 189 Hour = decToBcd(Hour) & 0xBF;
techstep 0:e4fbbd93299b 190 }
techstep 0:e4fbbd93299b 191 char cmdHour[2];
techstep 0:e4fbbd93299b 192 cmdHour[0] = 0x02;
techstep 0:e4fbbd93299b 193 cmdHour[1] = Hour;
techstep 0:e4fbbd93299b 194 _i2c.write(ADDR, cmdHour, 2);
techstep 0:e4fbbd93299b 195 }
techstep 0:e4fbbd93299b 196
techstep 0:e4fbbd93299b 197 void DS3231::setDoW(uint8_t DoW) {
techstep 0:e4fbbd93299b 198 // Sets the Day of Week
techstep 0:e4fbbd93299b 199 char cmd[2];
techstep 0:e4fbbd93299b 200 cmd[0] = 0x03;
techstep 0:e4fbbd93299b 201 cmd[1] = decToBcd(DoW);
techstep 0:e4fbbd93299b 202 _i2c.write(ADDR, cmd, 2 );
techstep 0:e4fbbd93299b 203 }
techstep 0:e4fbbd93299b 204
techstep 0:e4fbbd93299b 205 void DS3231::setDate(uint8_t Date) {
techstep 0:e4fbbd93299b 206 // Sets the Date
techstep 0:e4fbbd93299b 207 char cmd[2];
techstep 0:e4fbbd93299b 208 cmd[0] = 0x04;
techstep 0:e4fbbd93299b 209 cmd[1] = decToBcd(Date);
techstep 0:e4fbbd93299b 210 _i2c.write(ADDR, cmd, 2 );
techstep 0:e4fbbd93299b 211 }
techstep 0:e4fbbd93299b 212
techstep 0:e4fbbd93299b 213 void DS3231::setMonth(uint8_t Month) {
techstep 0:e4fbbd93299b 214 // Sets the month
techstep 0:e4fbbd93299b 215 char cmd[2];
techstep 0:e4fbbd93299b 216 cmd[0] = 0x05;
techstep 0:e4fbbd93299b 217 cmd[1] = decToBcd(Month);
techstep 0:e4fbbd93299b 218 _i2c.write(ADDR, cmd, 2 );
techstep 0:e4fbbd93299b 219 }
techstep 0:e4fbbd93299b 220
techstep 0:e4fbbd93299b 221 void DS3231::setYear(uint8_t Year) {
techstep 0:e4fbbd93299b 222 // Sets the year
techstep 0:e4fbbd93299b 223 char cmd[2];
techstep 0:e4fbbd93299b 224 cmd[0] = 0x06;
techstep 0:e4fbbd93299b 225 cmd[1] = decToBcd(Year);
techstep 0:e4fbbd93299b 226 _i2c.write(ADDR, cmd, 2 );
techstep 0:e4fbbd93299b 227 }
techstep 0:e4fbbd93299b 228
techstep 0:e4fbbd93299b 229 void DS3231::setClockMode(bool h12) {
techstep 0:e4fbbd93299b 230 // sets the mode to 12-hour (true) or 24-hour (false).
techstep 0:e4fbbd93299b 231 // One thing that bothers me about how I've written this is that
techstep 0:e4fbbd93299b 232 // if the read and right happen at the right hourly millisecnd,
techstep 0:e4fbbd93299b 233 // the clock will be set back an hour. Not sure how to do it better,
techstep 0:e4fbbd93299b 234 // though, and as long as one doesn't set the mode frequently it's
techstep 0:e4fbbd93299b 235 // a very minimal risk.
techstep 0:e4fbbd93299b 236 // It's zero risk if you call this BEFORE setting the hour, since
techstep 0:e4fbbd93299b 237 // the setHour() function doesn't change this mode.
techstep 0:e4fbbd93299b 238
techstep 0:e4fbbd93299b 239 char temp_buffer;
techstep 0:e4fbbd93299b 240 char cmd;
techstep 0:e4fbbd93299b 241 cmd = 0x02;
techstep 0:e4fbbd93299b 242
techstep 0:e4fbbd93299b 243 // Start by reading byte 0x02.
techstep 0:e4fbbd93299b 244 _i2c.write(ADDR, &cmd, 1 );
techstep 0:e4fbbd93299b 245 _i2c.read( ADDR, &temp_buffer, 1 );
techstep 0:e4fbbd93299b 246
techstep 0:e4fbbd93299b 247 // Set the flag to the requested value:
techstep 0:e4fbbd93299b 248 if (h12) {
techstep 0:e4fbbd93299b 249 temp_buffer = temp_buffer | 0x40;
techstep 0:e4fbbd93299b 250 } else {
techstep 0:e4fbbd93299b 251 temp_buffer = temp_buffer & 0xBF;
techstep 0:e4fbbd93299b 252 }
techstep 0:e4fbbd93299b 253
techstep 0:e4fbbd93299b 254 // Write the byte
techstep 0:e4fbbd93299b 255 _i2c.write(ADDR, &cmd, 1 );
techstep 0:e4fbbd93299b 256 _i2c.write(temp_buffer);
techstep 0:e4fbbd93299b 257 }
techstep 0:e4fbbd93299b 258
techstep 0:e4fbbd93299b 259 float DS3231::getTemperature(void) {
techstep 0:e4fbbd93299b 260 // Checks the internal thermometer on the DS3231 and returns the
techstep 0:e4fbbd93299b 261 // temperature as a floating-point value.
techstep 1:1607610a4ee9 262 char temp[2];
techstep 0:e4fbbd93299b 263 char cmd;
techstep 0:e4fbbd93299b 264 cmd = 0x11;
techstep 1:1607610a4ee9 265 _i2c.write(ADDR, &cmd, 1);
techstep 1:1607610a4ee9 266 _i2c.read( ADDR, temp, 2);
techstep 1:1607610a4ee9 267 return float(temp[0]) + 0.25*(temp[1]>>6);
techstep 0:e4fbbd93299b 268 }
techstep 0:e4fbbd93299b 269
techstep 0:e4fbbd93299b 270 void DS3231::getA1Time(uint8_t& A1Day, uint8_t& A1Hour, uint8_t& A1Minute, uint8_t& A1Second, uint8_t& AlarmBits, bool& A1Dy, bool& A1h12, bool& A1PM) {
techstep 0:e4fbbd93299b 271 uint8_t temp_buffer;
techstep 1:1607610a4ee9 272 char data[4];
techstep 1:1607610a4ee9 273 char cmd;
techstep 1:1607610a4ee9 274 cmd = 0x07;
techstep 1:1607610a4ee9 275 _i2c.write(ADDR, &cmd, 1);
techstep 1:1607610a4ee9 276 _i2c.read( ADDR, data, 4);
techstep 0:e4fbbd93299b 277
techstep 1:1607610a4ee9 278 temp_buffer = data[0]; // Get A1M1 and A1 Seconds
techstep 0:e4fbbd93299b 279 A1Second = bcdToDec(temp_buffer & 0x7F);
techstep 0:e4fbbd93299b 280 // put A1M1 bit in position 0 of DS3231_AlarmBits.
techstep 0:e4fbbd93299b 281 AlarmBits = AlarmBits | (temp_buffer & 0x80)>>7;
techstep 0:e4fbbd93299b 282
techstep 1:1607610a4ee9 283 temp_buffer = data[1]; // Get A1M2 and A1 minutes
techstep 0:e4fbbd93299b 284 A1Minute = bcdToDec(temp_buffer & 0x7F);
techstep 0:e4fbbd93299b 285 // put A1M2 bit in position 1 of DS3231_AlarmBits.
techstep 0:e4fbbd93299b 286 AlarmBits = AlarmBits | (temp_buffer & 0x80)>>6;
techstep 0:e4fbbd93299b 287
techstep 1:1607610a4ee9 288 temp_buffer = data[2]; // Get A1M3 and A1 Hour
techstep 0:e4fbbd93299b 289 // put A1M3 bit in position 2 of DS3231_AlarmBits.
techstep 0:e4fbbd93299b 290 AlarmBits = AlarmBits | (temp_buffer & 0x80)>>5;
techstep 0:e4fbbd93299b 291 // determine A1 12/24 mode
techstep 0:e4fbbd93299b 292 A1h12 = temp_buffer & 0x40;
techstep 0:e4fbbd93299b 293 if (A1h12) {
techstep 0:e4fbbd93299b 294 A1PM = temp_buffer & 0x20; // determine am/pm
techstep 0:e4fbbd93299b 295 A1Hour = bcdToDec(temp_buffer & 0x1F); // 12-hour
techstep 0:e4fbbd93299b 296 } else {
techstep 0:e4fbbd93299b 297 A1Hour = bcdToDec(temp_buffer & 0x3F); // 24-hour
techstep 0:e4fbbd93299b 298 }
techstep 0:e4fbbd93299b 299
techstep 1:1607610a4ee9 300 temp_buffer = data[3]; // Get A1M4 and A1 Day/Date
techstep 0:e4fbbd93299b 301 // put A1M3 bit in position 3 of DS3231_AlarmBits.
techstep 0:e4fbbd93299b 302 AlarmBits = AlarmBits | (temp_buffer & 0x80)>>4;
techstep 0:e4fbbd93299b 303 // determine A1 day or date flag
techstep 0:e4fbbd93299b 304 A1Dy = (temp_buffer & 0x40)>>6;
techstep 0:e4fbbd93299b 305 if (A1Dy) {
techstep 0:e4fbbd93299b 306 // alarm is by day of week, not date.
techstep 0:e4fbbd93299b 307 A1Day = bcdToDec(temp_buffer & 0x0F);
techstep 0:e4fbbd93299b 308 } else {
techstep 0:e4fbbd93299b 309 // alarm is by date, not day of week.
techstep 0:e4fbbd93299b 310 A1Day = bcdToDec(temp_buffer & 0x3F);
techstep 0:e4fbbd93299b 311 }
techstep 0:e4fbbd93299b 312 }
techstep 0:e4fbbd93299b 313
techstep 0:e4fbbd93299b 314 void DS3231::getA2Time(uint8_t& A2Day, uint8_t& A2Hour, uint8_t& A2Minute, uint8_t& AlarmBits, bool& A2Dy, bool& A2h12, bool& A2PM) {
techstep 0:e4fbbd93299b 315 uint8_t temp_buffer;
techstep 1:1607610a4ee9 316 char data[3];
techstep 1:1607610a4ee9 317 char cmd;
techstep 1:1607610a4ee9 318 cmd = 0x0B;
techstep 1:1607610a4ee9 319 _i2c.write(ADDR, &cmd, 1);
techstep 1:1607610a4ee9 320 _i2c.read( ADDR, data, 4);
techstep 0:e4fbbd93299b 321
techstep 0:e4fbbd93299b 322 //I2C.requestFrom(CLOCK_ADDRESS, 3);
techstep 1:1607610a4ee9 323 temp_buffer = data[0]; // Get A2M2 and A2 Minutes
techstep 0:e4fbbd93299b 324 A2Minute = bcdToDec(temp_buffer & 0x7F);
techstep 0:e4fbbd93299b 325 // put A2M2 bit in position 4 of DS3231_AlarmBits.
techstep 0:e4fbbd93299b 326 AlarmBits = AlarmBits | (temp_buffer & 0x80)>>3;
techstep 0:e4fbbd93299b 327
techstep 1:1607610a4ee9 328 temp_buffer = data[1]; // Get A2M3 and A2 Hour
techstep 0:e4fbbd93299b 329 // put A2M3 bit in position 5 of DS3231_AlarmBits.
techstep 0:e4fbbd93299b 330 AlarmBits = AlarmBits | (temp_buffer & 0x80)>>2;
techstep 0:e4fbbd93299b 331 // determine A2 12/24 mode
techstep 0:e4fbbd93299b 332 A2h12 = temp_buffer & 0x40;
techstep 0:e4fbbd93299b 333 if (A2h12) {
techstep 0:e4fbbd93299b 334 A2PM = temp_buffer & 0x20; // determine am/pm
techstep 0:e4fbbd93299b 335 A2Hour = bcdToDec(temp_buffer & 0x1F); // 12-hour
techstep 0:e4fbbd93299b 336 } else {
techstep 0:e4fbbd93299b 337 A2Hour = bcdToDec(temp_buffer & 0x3F); // 24-hour
techstep 0:e4fbbd93299b 338 }
techstep 0:e4fbbd93299b 339
techstep 1:1607610a4ee9 340 temp_buffer = data[2]; // Get A2M4 and A1 Day/Date
techstep 0:e4fbbd93299b 341 // put A2M4 bit in position 6 of DS3231_AlarmBits.
techstep 0:e4fbbd93299b 342 AlarmBits = AlarmBits | (temp_buffer & 0x80)>>1;
techstep 0:e4fbbd93299b 343 // determine A2 day or date flag
techstep 0:e4fbbd93299b 344 A2Dy = (temp_buffer & 0x40)>>6;
techstep 0:e4fbbd93299b 345 if (A2Dy) {
techstep 0:e4fbbd93299b 346 // alarm is by day of week, not date.
techstep 0:e4fbbd93299b 347 A2Day = bcdToDec(temp_buffer & 0x0F);
techstep 0:e4fbbd93299b 348 } else {
techstep 0:e4fbbd93299b 349 // alarm is by date, not day of week.
techstep 0:e4fbbd93299b 350 A2Day = bcdToDec(temp_buffer & 0x3F);
techstep 0:e4fbbd93299b 351 }
techstep 0:e4fbbd93299b 352 }
techstep 0:e4fbbd93299b 353
techstep 0:e4fbbd93299b 354 void DS3231::setA1Time(uint8_t A1Day, uint8_t A1Hour, uint8_t A1Minute, uint8_t A1Second, uint8_t AlarmBits, bool A1Dy, bool A1h12, bool A1PM) {
techstep 0:e4fbbd93299b 355 // Sets the alarm-1 date and time on the DS3231, using A1* information
techstep 0:e4fbbd93299b 356 uint8_t temp_buffer;
techstep 0:e4fbbd93299b 357
techstep 1:1607610a4ee9 358 char data[4];
techstep 1:1607610a4ee9 359 data[0] = 0x07; // A1 starts at 07h
techstep 1:1607610a4ee9 360 data[1] = decToBcd(A1Second) | ((AlarmBits & 0x01) << 7); // Send A1 second and A1M1
techstep 1:1607610a4ee9 361 data[2] = decToBcd(A1Minute) | ((AlarmBits & 0x02) << 6); // Send A1 Minute and A1M2
techstep 1:1607610a4ee9 362
techstep 0:e4fbbd93299b 363 // Figure out A1 hour
techstep 0:e4fbbd93299b 364 if (A1h12) {
techstep 0:e4fbbd93299b 365 // Start by converting existing time to h12 if it was given in 24h.
techstep 0:e4fbbd93299b 366 if (A1Hour > 12) {
techstep 0:e4fbbd93299b 367 // well, then, this obviously isn't a h12 time, is it?
techstep 0:e4fbbd93299b 368 A1Hour = A1Hour - 12;
techstep 0:e4fbbd93299b 369 A1PM = true;
techstep 0:e4fbbd93299b 370 }
techstep 0:e4fbbd93299b 371 if (A1PM) {
techstep 0:e4fbbd93299b 372 // Afternoon
techstep 0:e4fbbd93299b 373 // Convert the hour to BCD and add appropriate flags.
techstep 0:e4fbbd93299b 374 temp_buffer = decToBcd(A1Hour) | 0x60;
techstep 0:e4fbbd93299b 375 } else {
techstep 0:e4fbbd93299b 376 // Morning
techstep 0:e4fbbd93299b 377 // Convert the hour to BCD and add appropriate flags.
techstep 0:e4fbbd93299b 378 temp_buffer = decToBcd(A1Hour) | 0x40;
techstep 0:e4fbbd93299b 379 }
techstep 0:e4fbbd93299b 380 } else {
techstep 0:e4fbbd93299b 381 // Now for 24h
techstep 0:e4fbbd93299b 382 temp_buffer = decToBcd(A1Hour);
techstep 0:e4fbbd93299b 383 }
techstep 0:e4fbbd93299b 384 temp_buffer = temp_buffer | ((AlarmBits & 0x04)<<5);
techstep 0:e4fbbd93299b 385 // A1 hour is figured out, send it
techstep 0:e4fbbd93299b 386 //I2C.write(temp_buffer);
techstep 0:e4fbbd93299b 387 _i2c.write(temp_buffer);
techstep 0:e4fbbd93299b 388
techstep 0:e4fbbd93299b 389 // Figure out A1 day/date and A1M4
techstep 0:e4fbbd93299b 390 temp_buffer = ((AlarmBits & 0x08)<<4) | decToBcd(A1Day);
techstep 0:e4fbbd93299b 391 if (A1Dy) {
techstep 0:e4fbbd93299b 392 // Set A1 Day/Date flag (Otherwise it's zero)
techstep 0:e4fbbd93299b 393 temp_buffer = temp_buffer | 0x40;
techstep 0:e4fbbd93299b 394 }
techstep 1:1607610a4ee9 395 data[3] = temp_buffer;
techstep 1:1607610a4ee9 396 _i2c.write(ADDR, data, 4);
techstep 1:1607610a4ee9 397
techstep 0:e4fbbd93299b 398 }
techstep 0:e4fbbd93299b 399
techstep 0:e4fbbd93299b 400 void DS3231::setA2Time(uint8_t A2Day, uint8_t A2Hour, uint8_t A2Minute, uint8_t AlarmBits, bool A2Dy, bool A2h12, bool A2PM) {
techstep 0:e4fbbd93299b 401 // Sets the alarm-2 date and time on the DS3231, using A2* information
techstep 0:e4fbbd93299b 402 uint8_t temp_buffer;
techstep 0:e4fbbd93299b 403
techstep 1:1607610a4ee9 404 char data[4];
techstep 1:1607610a4ee9 405 data[0] = 0x0B; // A2 starts at 0Bh
techstep 1:1607610a4ee9 406 data[1] = decToBcd(A2Minute) | ((AlarmBits & 0x10) << 3); // Send A2 Minute and A2M2
techstep 0:e4fbbd93299b 407
techstep 0:e4fbbd93299b 408 // Figure out A2 hour
techstep 0:e4fbbd93299b 409 if (A2h12) {
techstep 0:e4fbbd93299b 410 // Start by converting existing time to h12 if it was given in 24h.
techstep 0:e4fbbd93299b 411 if (A2Hour > 12) {
techstep 0:e4fbbd93299b 412 // well, then, this obviously isn't a h12 time, is it?
techstep 0:e4fbbd93299b 413 A2Hour = A2Hour - 12;
techstep 0:e4fbbd93299b 414 A2PM = true;
techstep 0:e4fbbd93299b 415 }
techstep 0:e4fbbd93299b 416 if (A2PM) {
techstep 0:e4fbbd93299b 417 // Afternoon
techstep 0:e4fbbd93299b 418 // Convert the hour to BCD and add appropriate flags.
techstep 0:e4fbbd93299b 419 temp_buffer = decToBcd(A2Hour) | 0x60;
techstep 0:e4fbbd93299b 420 } else {
techstep 0:e4fbbd93299b 421 // Morning
techstep 0:e4fbbd93299b 422 // Convert the hour to BCD and add appropriate flags.
techstep 0:e4fbbd93299b 423 temp_buffer = decToBcd(A2Hour) | 0x40;
techstep 0:e4fbbd93299b 424 }
techstep 0:e4fbbd93299b 425 } else {
techstep 0:e4fbbd93299b 426 // Now for 24h
techstep 0:e4fbbd93299b 427 temp_buffer = decToBcd(A2Hour);
techstep 0:e4fbbd93299b 428 }
techstep 0:e4fbbd93299b 429 // add in A2M3 bit
techstep 0:e4fbbd93299b 430 temp_buffer = temp_buffer | ((AlarmBits & 0x20)<<2);
techstep 0:e4fbbd93299b 431 // A2 hour is figured out, send it
techstep 1:1607610a4ee9 432 data[2] = temp_buffer;
techstep 0:e4fbbd93299b 433
techstep 0:e4fbbd93299b 434 // Figure out A2 day/date and A2M4
techstep 0:e4fbbd93299b 435 temp_buffer = ((AlarmBits & 0x40)<<1) | decToBcd(A2Day);
techstep 0:e4fbbd93299b 436 if (A2Dy) {
techstep 0:e4fbbd93299b 437 // Set A2 Day/Date flag (Otherwise it's zero)
techstep 0:e4fbbd93299b 438 temp_buffer = temp_buffer | 0x40;
techstep 0:e4fbbd93299b 439 }
techstep 1:1607610a4ee9 440 data[3] = temp_buffer;
techstep 1:1607610a4ee9 441 _i2c.write(ADDR, data, 4);
techstep 1:1607610a4ee9 442
techstep 0:e4fbbd93299b 443 }
techstep 0:e4fbbd93299b 444
techstep 0:e4fbbd93299b 445 void DS3231::turnOnAlarm(uint8_t Alarm) {
techstep 0:e4fbbd93299b 446 // turns on alarm number "Alarm". Defaults to 2 if Alarm is not 1.
techstep 0:e4fbbd93299b 447 uint8_t temp_buffer = readControlByte(0);
techstep 0:e4fbbd93299b 448 // modify control byte
techstep 0:e4fbbd93299b 449 if (Alarm == 1) {
techstep 0:e4fbbd93299b 450 temp_buffer = temp_buffer | 0x05;
techstep 0:e4fbbd93299b 451 } else {
techstep 0:e4fbbd93299b 452 temp_buffer = temp_buffer | 0x06;
techstep 0:e4fbbd93299b 453 }
techstep 0:e4fbbd93299b 454 writeControlByte(temp_buffer, 0);
techstep 0:e4fbbd93299b 455 }
techstep 0:e4fbbd93299b 456
techstep 0:e4fbbd93299b 457 void DS3231::turnOffAlarm(uint8_t Alarm) {
techstep 0:e4fbbd93299b 458 // turns off alarm number "Alarm". Defaults to 2 if Alarm is not 1.
techstep 0:e4fbbd93299b 459 // Leaves interrupt pin alone.
techstep 0:e4fbbd93299b 460 uint8_t temp_buffer = readControlByte(0);
techstep 0:e4fbbd93299b 461 // modify control byte
techstep 0:e4fbbd93299b 462 if (Alarm == 1) {
techstep 0:e4fbbd93299b 463 temp_buffer = temp_buffer & 0xFE;
techstep 0:e4fbbd93299b 464 } else {
techstep 0:e4fbbd93299b 465 temp_buffer = temp_buffer & 0xFD;
techstep 0:e4fbbd93299b 466 }
techstep 0:e4fbbd93299b 467 writeControlByte(temp_buffer, 0);
techstep 0:e4fbbd93299b 468 }
techstep 0:e4fbbd93299b 469
techstep 0:e4fbbd93299b 470 bool DS3231::checkAlarmEnabled(uint8_t Alarm) {
techstep 0:e4fbbd93299b 471 // Checks whether the given alarm is enabled.
techstep 0:e4fbbd93299b 472 uint8_t result = 0x0;
techstep 0:e4fbbd93299b 473 uint8_t temp_buffer = readControlByte(0);
techstep 0:e4fbbd93299b 474 if (Alarm == 1) {
techstep 0:e4fbbd93299b 475 result = temp_buffer & 0x01;
techstep 0:e4fbbd93299b 476 } else {
techstep 0:e4fbbd93299b 477 result = temp_buffer & 0x02;
techstep 0:e4fbbd93299b 478 }
techstep 0:e4fbbd93299b 479 return result;
techstep 0:e4fbbd93299b 480 }
techstep 0:e4fbbd93299b 481
techstep 0:e4fbbd93299b 482 bool DS3231::checkIfAlarm(uint8_t Alarm) {
techstep 0:e4fbbd93299b 483 // Checks whether alarm 1 or alarm 2 flag is on, returns T/F accordingly.
techstep 0:e4fbbd93299b 484 // Turns flag off, also.
techstep 0:e4fbbd93299b 485 // defaults to checking alarm 2, unless Alarm == 1.
techstep 0:e4fbbd93299b 486 uint8_t result;
techstep 0:e4fbbd93299b 487 uint8_t temp_buffer = readControlByte(1);
techstep 0:e4fbbd93299b 488 if (Alarm == 1) {
techstep 0:e4fbbd93299b 489 // Did alarm 1 go off?
techstep 0:e4fbbd93299b 490 result = temp_buffer & 0x01;
techstep 0:e4fbbd93299b 491 // clear flag
techstep 0:e4fbbd93299b 492 temp_buffer = temp_buffer & 0xFE;
techstep 0:e4fbbd93299b 493 } else {
techstep 0:e4fbbd93299b 494 // Did alarm 2 go off?
techstep 0:e4fbbd93299b 495 result = temp_buffer & 0x02;
techstep 0:e4fbbd93299b 496 // clear flag
techstep 0:e4fbbd93299b 497 temp_buffer = temp_buffer & 0xFD;
techstep 0:e4fbbd93299b 498 }
techstep 0:e4fbbd93299b 499 writeControlByte(temp_buffer, 1);
techstep 0:e4fbbd93299b 500 return result;
techstep 0:e4fbbd93299b 501 }
techstep 0:e4fbbd93299b 502
techstep 0:e4fbbd93299b 503 void DS3231::enableOscillator(bool TF, bool battery, uint8_t frequency) {
techstep 0:e4fbbd93299b 504 // turns oscillator on or off. True is on, false is off.
techstep 0:e4fbbd93299b 505 // if battery is true, turns on even for battery-only operation,
techstep 0:e4fbbd93299b 506 // otherwise turns off if Vcc is off.
techstep 0:e4fbbd93299b 507 // frequency must be 0, 1, 2, or 3.
techstep 0:e4fbbd93299b 508 // 0 = 1 Hz
techstep 0:e4fbbd93299b 509 // 1 = 1.024 kHz
techstep 0:e4fbbd93299b 510 // 2 = 4.096 kHz
techstep 0:e4fbbd93299b 511 // 3 = 8.192 kHz (Default if frequency byte is out of range)
techstep 0:e4fbbd93299b 512 if (frequency > 3) frequency = 3;
techstep 0:e4fbbd93299b 513 // read control byte in, but zero out current state of RS2 and RS1.
techstep 0:e4fbbd93299b 514 uint8_t temp_buffer = readControlByte(0) & 0xE7;
techstep 0:e4fbbd93299b 515 if (battery) {
techstep 0:e4fbbd93299b 516 // turn on BBSQW flag
techstep 0:e4fbbd93299b 517 temp_buffer = temp_buffer | 0x40;
techstep 0:e4fbbd93299b 518 } else {
techstep 0:e4fbbd93299b 519 // turn off BBSQW flag
techstep 0:e4fbbd93299b 520 temp_buffer = temp_buffer & 0xBF;
techstep 0:e4fbbd93299b 521 }
techstep 0:e4fbbd93299b 522 if (TF) {
techstep 0:e4fbbd93299b 523 // set ~EOSC to 0 and INTCN to zero.
techstep 0:e4fbbd93299b 524 temp_buffer = temp_buffer & 0x7B;
techstep 0:e4fbbd93299b 525 } else {
techstep 0:e4fbbd93299b 526 // set ~EOSC to 1, leave INTCN as is.
techstep 0:e4fbbd93299b 527 temp_buffer = temp_buffer | 0x80;
techstep 0:e4fbbd93299b 528 }
techstep 0:e4fbbd93299b 529 // shift frequency into bits 3 and 4 and set.
techstep 0:e4fbbd93299b 530 frequency = frequency << 3;
techstep 0:e4fbbd93299b 531 temp_buffer = temp_buffer | frequency;
techstep 0:e4fbbd93299b 532 // And write the control bits
techstep 0:e4fbbd93299b 533 writeControlByte(temp_buffer, 0);
techstep 0:e4fbbd93299b 534 }
techstep 0:e4fbbd93299b 535
techstep 0:e4fbbd93299b 536 void DS3231::enable32kHz(bool TF) {
techstep 0:e4fbbd93299b 537 // turn 32kHz pin on or off
techstep 0:e4fbbd93299b 538 uint8_t temp_buffer = readControlByte(1);
techstep 0:e4fbbd93299b 539 if (TF) {
techstep 0:e4fbbd93299b 540 // turn on 32kHz pin
techstep 0:e4fbbd93299b 541 temp_buffer = temp_buffer | 0x08;
techstep 0:e4fbbd93299b 542 } else {
techstep 0:e4fbbd93299b 543 // turn off 32kHz pin
techstep 0:e4fbbd93299b 544 temp_buffer = temp_buffer & 0xF7;
techstep 0:e4fbbd93299b 545 }
techstep 0:e4fbbd93299b 546 writeControlByte(temp_buffer, 1);
techstep 0:e4fbbd93299b 547 }
techstep 0:e4fbbd93299b 548
techstep 0:e4fbbd93299b 549 bool DS3231::oscillatorCheck() {
techstep 0:e4fbbd93299b 550 // Returns false if the oscillator has been off for some reason.
techstep 0:e4fbbd93299b 551 // If this is the case, the time is probably not correct.
techstep 0:e4fbbd93299b 552 uint8_t temp_buffer = readControlByte(1);
techstep 0:e4fbbd93299b 553 bool result = true;
techstep 0:e4fbbd93299b 554 if (temp_buffer & 0x80) {
techstep 0:e4fbbd93299b 555 // Oscillator Stop Flag (OSF) is set, so return false.
techstep 0:e4fbbd93299b 556 result = false;
techstep 0:e4fbbd93299b 557 }
techstep 0:e4fbbd93299b 558 return result;
techstep 0:e4fbbd93299b 559 }
techstep 0:e4fbbd93299b 560
techstep 0:e4fbbd93299b 561 /*****************************************
techstep 0:e4fbbd93299b 562 Private Functions
techstep 0:e4fbbd93299b 563 *****************************************/
techstep 0:e4fbbd93299b 564 uint8_t DS3231::decToBcd(uint8_t val) {
techstep 0:e4fbbd93299b 565 // Convert normal decimal numbers to binary coded decimal
techstep 0:e4fbbd93299b 566 return ( (val/10*16) + (val%10) );
techstep 0:e4fbbd93299b 567 }
techstep 0:e4fbbd93299b 568
techstep 0:e4fbbd93299b 569 uint8_t DS3231::bcdToDec(uint8_t val) {
techstep 0:e4fbbd93299b 570 // Convert binary coded decimal to normal decimal numbers
techstep 0:e4fbbd93299b 571 return ( (val/16*10) + (val%16) );
techstep 0:e4fbbd93299b 572 }
techstep 0:e4fbbd93299b 573
techstep 0:e4fbbd93299b 574 uint8_t DS3231::readControlByte(bool which) {
techstep 0:e4fbbd93299b 575 // Read selected control byte
techstep 0:e4fbbd93299b 576 // first byte (0) is 0x0e, second (1) is 0x0f
techstep 1:1607610a4ee9 577 char data;
techstep 1:1607610a4ee9 578 char cmd[2];
techstep 1:1607610a4ee9 579 cmd[0] = 0x0F;
techstep 1:1607610a4ee9 580 cmd[1] = 0x0E;
techstep 1:1607610a4ee9 581
techstep 0:e4fbbd93299b 582 if (which) {
techstep 0:e4fbbd93299b 583 // second control byte
techstep 1:1607610a4ee9 584 _i2c.write(ADDR, &cmd[0], 1 );
techstep 0:e4fbbd93299b 585 } else {
techstep 0:e4fbbd93299b 586 // first control byte
techstep 1:1607610a4ee9 587 _i2c.write(ADDR, &cmd[1], 1 );
techstep 0:e4fbbd93299b 588 }
techstep 1:1607610a4ee9 589 _i2c.read( ADDR, &data, 1 );
techstep 1:1607610a4ee9 590 return data;
techstep 0:e4fbbd93299b 591 }
techstep 0:e4fbbd93299b 592
techstep 0:e4fbbd93299b 593 void DS3231::writeControlByte(uint8_t control, bool which) {
techstep 0:e4fbbd93299b 594 // Write the selected control byte.
techstep 0:e4fbbd93299b 595 // which=false -> 0x0e, true->0x0f.
techstep 1:1607610a4ee9 596 char data1[2];
techstep 1:1607610a4ee9 597 char data2[2];
techstep 1:1607610a4ee9 598 data1[0] = 0x0F;
techstep 1:1607610a4ee9 599 data1[1] = control;
techstep 1:1607610a4ee9 600 data2[0] = 0x0E;
techstep 1:1607610a4ee9 601 data2[1] = control;
techstep 0:e4fbbd93299b 602
techstep 0:e4fbbd93299b 603 if (which) {
techstep 1:1607610a4ee9 604 _i2c.read( ADDR, data1, 2);
techstep 0:e4fbbd93299b 605 } else {
techstep 1:1607610a4ee9 606 _i2c.read( ADDR, data2, 2);
techstep 0:e4fbbd93299b 607 }
techstep 1:1607610a4ee9 608
techstep 0:e4fbbd93299b 609 }
techstep 0:e4fbbd93299b 610