You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

266 lines
6.9 KiB

#ifndef __RTCDS1302_H__
#define __RTCDS1302_H__
#include <Arduino.h>
#include "RtcDateTime.h"
#include "RtcUtility.h"
//DS1302 Register Addresses
const uint8_t DS1302_REG_TIMEDATE = 0x80;
const uint8_t DS1302_REG_TIMEDATE_BURST = 0xBE;
const uint8_t DS1302_REG_TCR = 0x90;
const uint8_t DS1302_REG_RAM_BURST = 0xFE;
const uint8_t DS1302_REG_RAMSTART = 0xc0;
const uint8_t DS1302_REG_RAMEND = 0xfd;
// ram read and write addresses are interleaved
const uint8_t DS1302RamSize = 31;
// DS1302 Trickle Charge Control Register Bits
enum DS1302TcrResistor {
DS1302TcrResistor_Disabled = 0,
DS1302TcrResistor_2KOhm = B00000001,
DS1302TcrResistor_4KOhm = B00000010,
DS1302TcrResistor_8KOhm = B00000011,
DS1302TcrResistor_MASK = B00000011,
};
enum DS1302TcrDiodes {
DS1302TcrDiodes_None = 0,
DS1302TcrDiodes_One = B00000100,
DS1302TcrDiodes_Two = B00001000,
DS1302TcrDiodes_Disabled = B00001100,
DS1302TcrDiodes_MASK = B00001100,
};
enum DS1302TcrStatus {
DS1302TcrStatus_Enabled = B10100000,
DS1302TcrStatus_Disabled = B01010000,
DS1302TcrStatus_MASK = B11110000,
};
const uint8_t DS1302Tcr_Disabled = DS1302TcrStatus_Disabled | DS1302TcrDiodes_Disabled | DS1302TcrResistor_Disabled;
// DS1302 Clock Halt Register & Bits
const uint8_t DS1302_REG_CH = 0x80; // bit in the seconds register
const uint8_t DS1302_CH = 7;
// Write Protect Register & Bits
const uint8_t DS1302_REG_WP = 0x8E;
const uint8_t DS1302_WP = 7;
template<class T_WIRE_METHOD> class RtcDS1302
{
public:
RtcDS1302(T_WIRE_METHOD& wire) :
_wire(wire)
{
}
void Begin()
{
_wire.begin();
}
bool GetIsWriteProtected()
{
uint8_t wp = getReg(DS1302_REG_WP);
return !!(wp & _BV(DS1302_WP));
}
void SetIsWriteProtected(bool isWriteProtected)
{
uint8_t wp = getReg(DS1302_REG_WP);
if (isWriteProtected)
{
wp |= _BV(DS1302_WP);
}
else
{
wp &= ~_BV(DS1302_WP);
}
setReg(DS1302_REG_WP, wp);
}
bool IsDateTimeValid()
{
return GetDateTime().IsValid();
}
bool GetIsRunning()
{
uint8_t ch = getReg(DS1302_REG_CH);
return !(ch & _BV(DS1302_CH));
}
void SetIsRunning(bool isRunning)
{
uint8_t ch = getReg(DS1302_REG_CH);
if (isRunning)
{
ch &= ~_BV(DS1302_CH);
}
else
{
ch |= _BV(DS1302_CH);
}
setReg(DS1302_REG_CH, ch);
}
uint8_t GetTrickleChargeSettings()
{
uint8_t setting = getReg(DS1302_REG_TCR);
return setting;
}
void SetTrickleChargeSettings(uint8_t setting)
{
if ((setting & DS1302TcrResistor_MASK) == DS1302TcrResistor_Disabled) {
// invalid resistor setting, set to disabled
setting = DS1302Tcr_Disabled;
goto apply;
}
if ((setting & DS1302TcrDiodes_MASK) == DS1302TcrDiodes_Disabled ||
(setting & DS1302TcrDiodes_MASK) == DS1302TcrDiodes_None) {
// invalid diode setting, set to disabled
setting = DS1302Tcr_Disabled;
goto apply;
}
if ((setting & DS1302TcrStatus_MASK) != DS1302TcrStatus_Enabled) {
// invalid status setting, set to disabled
setting = DS1302Tcr_Disabled;
goto apply;
}
apply:
setReg(DS1302_REG_TCR, setting);
}
void SetDateTime(const RtcDateTime& dt)
{
// set the date time
_wire.beginTransmission(DS1302_REG_TIMEDATE_BURST);
_wire.write(Uint8ToBcd(dt.Second()));
_wire.write(Uint8ToBcd(dt.Minute()));
_wire.write(Uint8ToBcd(dt.Hour())); // 24 hour mode only
_wire.write(Uint8ToBcd(dt.Day()));
_wire.write(Uint8ToBcd(dt.Month()));
// RTC Hardware Day of Week is 1-7, 1 = Monday
// convert our Day of Week to Rtc Day of Week
uint8_t rtcDow = RtcDateTime::ConvertDowToRtc(dt.DayOfWeek());
_wire.write(Uint8ToBcd(rtcDow));
_wire.write(Uint8ToBcd(dt.Year() - 2000));
_wire.write(0); // no write protect, as all of this is ignored if it is protected
_wire.endTransmission();
}
RtcDateTime GetDateTime()
{
_wire.beginTransmission(DS1302_REG_TIMEDATE_BURST | THREEWIRE_READFLAG);
uint8_t second = BcdToUint8(_wire.read() & 0x7F);
uint8_t minute = BcdToUint8(_wire.read());
uint8_t hour = BcdToBin24Hour(_wire.read());
uint8_t dayOfMonth = BcdToUint8(_wire.read());
uint8_t month = BcdToUint8(_wire.read());
_wire.read(); // throwing away day of week as we calculate it
uint16_t year = BcdToUint8(_wire.read()) + 2000;
_wire.read(); // throwing away write protect flag
_wire.endTransmission();
return RtcDateTime(year, month, dayOfMonth, hour, minute, second);
}
void SetMemory(uint8_t memoryAddress, uint8_t value)
{
// memory addresses interleaved read and write addresses
// so we need to calculate the offset
uint8_t address = memoryAddress * 2 + DS1302_REG_RAMSTART;
if (address <= DS1302_REG_RAMEND)
{
setReg(address, value);
}
}
uint8_t GetMemory(uint8_t memoryAddress)
{
uint8_t value = 0;
// memory addresses interleaved read and write addresses
// so we need to calculate the offset
uint8_t address = memoryAddress * 2 + DS1302_REG_RAMSTART;
if (address <= DS1302_REG_RAMEND)
{
value = getReg(address);
}
return value;
}
uint8_t SetMemory(const uint8_t* pValue, uint8_t countBytes)
{
uint8_t countWritten = 0;
_wire.beginTransmission(DS1302_REG_RAM_BURST);
while (countBytes > 0 && countWritten < DS1302RamSize)
{
_wire.write(*pValue++);
countBytes--;
countWritten++;
}
_wire.endTransmission();
return countWritten;
}
uint8_t GetMemory(uint8_t* pValue, uint8_t countBytes)
{
uint8_t countRead = 0;
_wire.beginTransmission(DS1302_REG_RAM_BURST | THREEWIRE_READFLAG);
while (countBytes > 0 && countRead < DS1302RamSize)
{
*pValue++ = _wire.read();
countRead++;
countBytes--;
}
_wire.endTransmission();
return countRead;
}
private:
T_WIRE_METHOD& _wire;
uint8_t getReg(uint8_t regAddress)
{
_wire.beginTransmission(regAddress | THREEWIRE_READFLAG);
uint8_t regValue = _wire.read();
_wire.endTransmission();
return regValue;
}
void setReg(uint8_t regAddress, uint8_t regValue)
{
_wire.beginTransmission(regAddress);
_wire.write(regValue);
_wire.endTransmission();
}
};
#endif // __RTCDS1302_H__