Realtime clock library for DS1307 and DS3231m
Dependents: vfd_modular_clock_mbed
ds3231m.cpp
- Committer:
- perjg
- Date:
- 2015-08-10
- Revision:
- 2:6119507e6713
- Parent:
- 1:3fe5649f1e02
File content as of revision 2:6119507e6713:
/* * RTC library - mbed * (C) 2011-15 Akafugu Corporation * * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * */ #include "ds3231m.h" #define DS3231M_SLAVE_ADDR 0xD0 DS3231M::DS3231M(I2C& i2c) : RTC() , m_i2c(i2c) { m_i2c.frequency(100000); } void DS3231M::begin() { } time_t DS3231M::time() { return m_time; } struct tm* DS3231M::getTime() { char rtc[7]; rtc[0] = 0; // second register, 0 int w = m_i2c.write(DS3231M_SLAVE_ADDR, rtc, 1); int r = m_i2c.read(DS3231M_SLAVE_ADDR, rtc, 7); // Clear clock halt bit from read data //rtc[0] &= ~(_BV(CH_BIT)); m_tm.tm_sec = bcd2dec(rtc[0]); m_tm.tm_min = bcd2dec(rtc[1]); m_tm.tm_hour = bcd2dec(rtc[2]); m_tm.tm_wday = bcd2dec(rtc[3])-1; m_tm.tm_mday = bcd2dec(rtc[4]); m_tm.tm_mon = bcd2dec(rtc[5])-1; // tm_mon is 0-11 m_tm.tm_year = bcd2dec(rtc[6]); return &m_tm; } void DS3231M::getTime(uint8_t* hour, uint8_t* min, uint8_t* sec) { char rtc[3]; rtc[0] = 0; // second register, 0 int w = m_i2c.write(DS3231M_SLAVE_ADDR, rtc, 1); int r = m_i2c.read(DS3231M_SLAVE_ADDR, rtc, 3); // Clear clock halt bit from read data //rtc[0] &= ~(_BV(CH_BIT)); if (sec) *sec = bcd2dec(rtc[0]); if (min) *min = bcd2dec(rtc[1]); if (hour) *hour = bcd2dec(rtc[2]); } void DS3231M::setTime(time_t t) { struct tm * timeinfo; timeinfo = localtime (&t); setTime(timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); } void DS3231M::setTime(uint8_t hour, uint8_t min, uint8_t sec) { write_byte(dec2bcd(sec), 0); write_byte(dec2bcd(min), 1); write_byte(dec2bcd(hour), 2); } void DS3231M::setTime(struct tm* tm) { write_byte(dec2bcd(tm->tm_sec), 0); write_byte(dec2bcd(tm->tm_min), 1); write_byte(dec2bcd(tm->tm_hour), 2); write_byte(dec2bcd(tm->tm_wday+1), 3); write_byte(dec2bcd(tm->tm_mday), 4); write_byte(dec2bcd(tm->tm_mon+1), 5); write_byte(dec2bcd(tm->tm_year), 6); } void DS3231M::setAlarm(time_t t) { struct tm * timeinfo; timeinfo = localtime (&t); setAlarm(timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); } void DS3231M::setAlarm(uint8_t hour, uint8_t min, uint8_t sec) { /* * 07h: A1M1:0 Alarm 1 seconds * 08h: A1M2:0 Alarm 1 minutes * 09h: A1M3:0 Alarm 1 hour (bit6 is am/pm flag in 12h mode) * 0ah: A1M4:1 Alarm 1 day/date (bit6: 1 for day, 0 for date) * Sets alarm to fire when hour, minute and second matches */ write_byte(dec2bcd(sec), 0x07); // second write_byte(dec2bcd(min), 0x08); // minute write_byte(dec2bcd(hour), 0x09); // hour write_byte(0x81, 0x0a); // day (upper bit must be set) // clear alarm flag uint8_t val = read_byte(0x0f); write_byte(val & ~0x01, 0x0f); } struct tm* DS3231M::getAlarm(void) { struct tm * timeinfo = getTime(); uint8_t hour, min, sec; getAlarm(&hour, &min, &sec); timeinfo->tm_hour = hour; timeinfo->tm_min = min; timeinfo->tm_sec = sec; return timeinfo; } void DS3231M::getAlarm(uint8_t* hour, uint8_t* min, uint8_t* sec) { *sec = bcd2dec(read_byte(0x07) & ~0x80); *min = bcd2dec(read_byte(0x08) & ~0x80); *hour = bcd2dec(read_byte(0x09) & ~0x80); } bool DS3231M::checkAlarm(void) { // Alarm 1 flag (A1F) in bit 0 uint8_t val = read_byte(0x0f); // clear flag when set if (val & 1) write_byte(val & ~0x01, 0x0f); return val & 1 ? 1 : 0; } void DS3231M::SQWEnable(bool enable) { uint8_t control = read_byte(0x0E); // read control register if (enable) { control |= 0x40; // set BBSQW to 1 control &= ~0x04; // set INTCN to 0 } else { control &= ~0x40; // set BBSQW to 0 } // write control back write_byte(control, 0x0E); } void DS3231M::SQWSetFreq(enum RTC_SQW_FREQ freq) { uint8_t control = read_byte(0x0E); // read control register control &= ~0x18; // Set to 0 control |= (freq << 4); // Set freq bitmask // write control back write_byte(control, 0x0E); } void DS3231M::Osc32kHzEnable(bool enable) { uint8_t status = read_byte(0x0F); // read status if (enable) status |= 0x08; // set to 1 else status &= ~0x08; // Set to 0 // write status back write_byte(status, 0x0F); } void DS3231M::getTemp(int8_t* i, uint8_t* f) { char data[2]; // msb, lsb *i = 0; *f = 0; data[0] = 0x11; int w = m_i2c.write(DS3231M_SLAVE_ADDR, data, 1); int r = m_i2c.read(DS3231M_SLAVE_ADDR, data, 2); // integer part in entire byte *i = (uint8_t)data[0]; // fractional part in top two bits (increments of 0.25) *f = ((uint8_t)data[1] >> 6) * 25; // float value can be read like so: // float temp = ((((short)data[0] << 8) | (short)data[1]) >> 6) / 4.0f; } void DS3231M::forceTempConversion(uint8_t block) { // read control register (0x0E) uint8_t control = read_byte(0x0E); // read control register control |= 0x20; // Set CONV bit // write new control register value write_byte(control, 0x0E); if (!block) return; uint8_t data; // Temp conversion is ready when control register becomes 0 do { // Block until CONV is 0 data = read_byte(0x0E); } while ((data & 0x20) != 0); } uint8_t DS3231M::read_byte(uint8_t offset) { char buf[1]; buf[0] = offset; int w = m_i2c.write(DS3231M_SLAVE_ADDR, buf, 1); int r = m_i2c.read(DS3231M_SLAVE_ADDR, buf, 1); //error = ((w!=0) || (r!=0)); return buf[0]; } void DS3231M::write_byte(uint8_t b, uint8_t offset) { char buf[2]; buf[0] = offset; buf[1] = b; int w = m_i2c.write(DS3231M_SLAVE_ADDR, buf, 2); //error=(w!=0); } void DS3231M::write_addr(uint8_t addr) { /* Wire.beginTransmission(RTC_ADDR); Wire.write(addr); Wire.endTransmission(); */ }