feat: 全量同步 254 个常用的 Arduino 扩展库文件
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
|
||||
//I2C Slave Address
|
||||
const uint8_t AT24C32_ADDRESS = 0x50; // 0b0 1010 A2 A1 A0
|
||||
|
||||
template<class T_WIRE_METHOD> class EepromAt24c32
|
||||
{
|
||||
public:
|
||||
EepromAt24c32(T_WIRE_METHOD& wire, uint8_t addressBits = 0b111) :
|
||||
_address(AT24C32_ADDRESS | (addressBits & 0b00000111)),
|
||||
_wire(wire),
|
||||
_lastError(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Begin()
|
||||
{
|
||||
_wire.begin();
|
||||
}
|
||||
|
||||
uint8_t LastError()
|
||||
{
|
||||
return _lastError;
|
||||
}
|
||||
|
||||
void SetMemory(uint16_t memoryAddress, uint8_t value)
|
||||
{
|
||||
SetMemory(memoryAddress, &value, 1);
|
||||
}
|
||||
|
||||
uint8_t GetMemory(uint16_t memoryAddress)
|
||||
{
|
||||
uint8_t value;
|
||||
|
||||
GetMemory(memoryAddress, &value, 1);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// note: this method will write within a single page of eeprom.
|
||||
// Pages are 32 bytes (5 bits), so writing past a page boundary will
|
||||
// just wrap within the page of the starting memory address.
|
||||
//
|
||||
// xxxppppp pppaaaaa => p = page #, a = address within the page
|
||||
//
|
||||
// NOTE: hardware WIRE libraries often have a limit of a 32 byte send buffer. The
|
||||
// effect of this is that only 30 bytes can be sent, 2 bytes for the address to write to,
|
||||
// and then 30 bytes of the actual data.
|
||||
uint8_t SetMemory(uint16_t memoryAddress, const uint8_t* pValue, uint8_t countBytes)
|
||||
{
|
||||
uint8_t countWritten = 0;
|
||||
|
||||
beginTransmission(memoryAddress);
|
||||
|
||||
while (countBytes > 0)
|
||||
{
|
||||
_wire.write(*pValue++);
|
||||
delay(10); // per spec, memory writes
|
||||
|
||||
countBytes--;
|
||||
countWritten++;
|
||||
}
|
||||
|
||||
_lastError = _wire.endTransmission();
|
||||
|
||||
return countWritten;
|
||||
}
|
||||
|
||||
// reading data does not wrap within pages, but due to only using
|
||||
// 12 (32K) or 13 (64K) bits are used, they will wrap within the memory limits
|
||||
// of the installed EEPROM
|
||||
//
|
||||
// NOTE: hardware WIRE libraries may have a limit of a 32 byte recieve buffer. The
|
||||
// effect of this is that only 32 bytes can be read at one time.
|
||||
uint8_t GetMemory(uint16_t memoryAddress, uint8_t* pValue, uint8_t countBytes)
|
||||
{
|
||||
// set address to read from
|
||||
beginTransmission(memoryAddress);
|
||||
_lastError = _wire.endTransmission();
|
||||
|
||||
if (_lastError != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read the data
|
||||
uint8_t countRead = 0;
|
||||
|
||||
countRead = _wire.requestFrom(_address, countBytes);
|
||||
countBytes = countRead;
|
||||
|
||||
while (countBytes-- > 0)
|
||||
{
|
||||
*pValue++ = _wire.read();
|
||||
}
|
||||
|
||||
return countRead;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t _address;
|
||||
|
||||
T_WIRE_METHOD& _wire;
|
||||
uint8_t _lastError;
|
||||
|
||||
void beginTransmission(uint16_t memoryAddress)
|
||||
{
|
||||
_wire.beginTransmission(_address);
|
||||
_wire.write(memoryAddress >> 8);
|
||||
_wire.write(memoryAddress & 0xFf);
|
||||
}
|
||||
};
|
||||
272
arduino-libs/arduino-cli/libraries/Rtc_by_Makuna/src/RtcDS1302.h
Normal file
272
arduino-libs/arduino-cli/libraries/Rtc_by_Makuna/src/RtcDS1302.h
Normal file
@@ -0,0 +1,272 @@
|
||||
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
|
||||
void Begin(int sda, int scl)
|
||||
{
|
||||
_wire.begin(sda, scl);
|
||||
}
|
||||
|
||||
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__
|
||||
259
arduino-libs/arduino-cli/libraries/Rtc_by_Makuna/src/RtcDS1307.h
Normal file
259
arduino-libs/arduino-cli/libraries/Rtc_by_Makuna/src/RtcDS1307.h
Normal file
@@ -0,0 +1,259 @@
|
||||
|
||||
|
||||
#ifndef __RTCDS1307_H__
|
||||
#define __RTCDS1307_H__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "RtcDateTime.h"
|
||||
#include "RtcUtility.h"
|
||||
|
||||
//I2C Slave Address
|
||||
const uint8_t DS1307_ADDRESS = 0x68;
|
||||
|
||||
//DS1307 Register Addresses
|
||||
const uint8_t DS1307_REG_TIMEDATE = 0x00;
|
||||
const uint8_t DS1307_REG_STATUS = 0x00;
|
||||
const uint8_t DS1307_REG_CONTROL = 0x07;
|
||||
const uint8_t DS1307_REG_RAMSTART = 0x08;
|
||||
const uint8_t DS1307_REG_RAMEND = 0x3f;
|
||||
const uint8_t DS1307_REG_RAMSIZE = DS1307_REG_RAMEND - DS1307_REG_RAMSTART;
|
||||
|
||||
//DS1307 Register Data Size if not just 1
|
||||
const uint8_t DS1307_REG_TIMEDATE_SIZE = 7;
|
||||
|
||||
// DS1307 Control Register Bits
|
||||
const uint8_t DS1307_RS0 = 0;
|
||||
const uint8_t DS1307_RS1 = 1;
|
||||
const uint8_t DS1307_SQWE = 4;
|
||||
const uint8_t DS1307_OUT = 7;
|
||||
|
||||
// DS1307 Status Register Bits
|
||||
const uint8_t DS1307_CH = 7;
|
||||
|
||||
enum DS1307SquareWaveOut
|
||||
{
|
||||
DS1307SquareWaveOut_1Hz = 0b00010000,
|
||||
DS1307SquareWaveOut_4kHz = 0b00010001,
|
||||
DS1307SquareWaveOut_8kHz = 0b00010010,
|
||||
DS1307SquareWaveOut_32kHz = 0b00010011,
|
||||
DS1307SquareWaveOut_High = 0b10000000,
|
||||
DS1307SquareWaveOut_Low = 0b00000000,
|
||||
};
|
||||
|
||||
template<class T_WIRE_METHOD> class RtcDS1307
|
||||
{
|
||||
public:
|
||||
RtcDS1307(T_WIRE_METHOD& wire) :
|
||||
_wire(wire),
|
||||
_lastError(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Begin()
|
||||
{
|
||||
_wire.begin();
|
||||
}
|
||||
void Begin(int sda, int scl)
|
||||
{
|
||||
_wire.begin(sda, scl);
|
||||
}
|
||||
|
||||
uint8_t LastError()
|
||||
{
|
||||
return _lastError;
|
||||
}
|
||||
|
||||
bool IsDateTimeValid()
|
||||
{
|
||||
return GetIsRunning();
|
||||
}
|
||||
|
||||
bool GetIsRunning()
|
||||
{
|
||||
uint8_t sreg = getReg(DS1307_REG_STATUS);
|
||||
return (!(sreg & _BV(DS1307_CH)) && (_lastError == 0));
|
||||
}
|
||||
|
||||
void SetIsRunning(bool isRunning)
|
||||
{
|
||||
uint8_t sreg = getReg(DS1307_REG_STATUS);
|
||||
if (isRunning)
|
||||
{
|
||||
sreg &= ~_BV(DS1307_CH);
|
||||
}
|
||||
else
|
||||
{
|
||||
sreg |= _BV(DS1307_CH);
|
||||
}
|
||||
setReg(DS1307_REG_STATUS, sreg);
|
||||
}
|
||||
|
||||
void SetDateTime(const RtcDateTime& dt)
|
||||
{
|
||||
// retain running state
|
||||
uint8_t sreg = getReg(DS1307_REG_STATUS) & _BV(DS1307_CH);
|
||||
|
||||
// set the date time
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(DS1307_REG_TIMEDATE);
|
||||
|
||||
_wire.write(Uint8ToBcd(dt.Second()) | sreg);
|
||||
_wire.write(Uint8ToBcd(dt.Minute()));
|
||||
_wire.write(Uint8ToBcd(dt.Hour())); // 24 hour mode only
|
||||
|
||||
// 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.Day()));
|
||||
_wire.write(Uint8ToBcd(dt.Month()));
|
||||
_wire.write(Uint8ToBcd(dt.Year() - 2000));
|
||||
|
||||
_lastError = _wire.endTransmission();
|
||||
}
|
||||
|
||||
RtcDateTime GetDateTime()
|
||||
{
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(DS1307_REG_TIMEDATE);
|
||||
_lastError = _wire.endTransmission();
|
||||
if (_lastError != 0)
|
||||
{
|
||||
RtcDateTime(0);
|
||||
}
|
||||
|
||||
uint8_t bytesRead = _wire.requestFrom(DS1307_ADDRESS, DS1307_REG_TIMEDATE_SIZE);
|
||||
if (DS1307_REG_TIMEDATE_SIZE != bytesRead)
|
||||
{
|
||||
_lastError = 4;
|
||||
RtcDateTime(0);
|
||||
}
|
||||
|
||||
uint8_t second = BcdToUint8(_wire.read() & 0x7F);
|
||||
uint8_t minute = BcdToUint8(_wire.read());
|
||||
uint8_t hour = BcdToBin24Hour(_wire.read());
|
||||
|
||||
_wire.read(); // throwing away day of week as we calculate it
|
||||
|
||||
uint8_t dayOfMonth = BcdToUint8(_wire.read());
|
||||
uint8_t month = BcdToUint8(_wire.read());
|
||||
uint16_t year = BcdToUint8(_wire.read()) + 2000;
|
||||
|
||||
return RtcDateTime(year, month, dayOfMonth, hour, minute, second);
|
||||
}
|
||||
|
||||
void SetMemory(uint8_t memoryAddress, uint8_t value)
|
||||
{
|
||||
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
|
||||
if (address <= DS1307_REG_RAMEND)
|
||||
{
|
||||
setReg(address, value);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t GetMemory(uint8_t memoryAddress)
|
||||
{
|
||||
uint8_t value = 0;
|
||||
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
|
||||
if (address <= DS1307_REG_RAMEND)
|
||||
{
|
||||
value = getReg(address);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t SetMemory(uint8_t memoryAddress, const uint8_t* pValue, uint8_t countBytes)
|
||||
{
|
||||
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
|
||||
uint8_t countWritten = 0;
|
||||
if (address <= DS1307_REG_RAMEND)
|
||||
{
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(address);
|
||||
|
||||
while (countBytes > 0 && address <= DS1307_REG_RAMEND)
|
||||
{
|
||||
_wire.write(*pValue++);
|
||||
address++;
|
||||
countBytes--;
|
||||
countWritten++;
|
||||
}
|
||||
|
||||
_lastError = _wire.endTransmission();
|
||||
}
|
||||
return countWritten;
|
||||
}
|
||||
|
||||
uint8_t GetMemory(uint8_t memoryAddress, uint8_t* pValue, uint8_t countBytes)
|
||||
{
|
||||
uint8_t address = memoryAddress + DS1307_REG_RAMSTART;
|
||||
uint8_t countRead = 0;
|
||||
if (address <= DS1307_REG_RAMEND)
|
||||
{
|
||||
if (countBytes > DS1307_REG_RAMSIZE)
|
||||
{
|
||||
countBytes = DS1307_REG_RAMSIZE;
|
||||
}
|
||||
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(address);
|
||||
_lastError = _wire.endTransmission();
|
||||
if (_lastError != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
countRead = _wire.requestFrom(DS1307_ADDRESS, countBytes);
|
||||
countBytes = countRead;
|
||||
|
||||
while (countBytes-- > 0)
|
||||
{
|
||||
*pValue++ = _wire.read();
|
||||
}
|
||||
}
|
||||
|
||||
return countRead;
|
||||
}
|
||||
|
||||
void SetSquareWavePin(DS1307SquareWaveOut pinMode)
|
||||
{
|
||||
setReg(DS1307_REG_CONTROL, pinMode);
|
||||
}
|
||||
|
||||
private:
|
||||
T_WIRE_METHOD& _wire;
|
||||
uint8_t _lastError;
|
||||
|
||||
uint8_t getReg(uint8_t regAddress)
|
||||
{
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(regAddress);
|
||||
_lastError = _wire.endTransmission();
|
||||
if (_lastError != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// control register
|
||||
uint8_t bytesRead = _wire.requestFrom(DS1307_ADDRESS, (uint8_t)1);
|
||||
if (1 != bytesRead)
|
||||
{
|
||||
_lastError = 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t regValue = _wire.read();
|
||||
return regValue;
|
||||
}
|
||||
|
||||
void setReg(uint8_t regAddress, uint8_t regValue)
|
||||
{
|
||||
_wire.beginTransmission(DS1307_ADDRESS);
|
||||
_wire.write(regAddress);
|
||||
_wire.write(regValue);
|
||||
_lastError = _wire.endTransmission();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __RTCDS1307_H__
|
||||
631
arduino-libs/arduino-cli/libraries/Rtc_by_Makuna/src/RtcDS3231.h
Normal file
631
arduino-libs/arduino-cli/libraries/Rtc_by_Makuna/src/RtcDS3231.h
Normal file
@@ -0,0 +1,631 @@
|
||||
|
||||
|
||||
#ifndef __RTCDS3231_H__
|
||||
#define __RTCDS3231_H__
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "RtcDateTime.h"
|
||||
#include "RtcTemperature.h"
|
||||
#include "RtcUtility.h"
|
||||
|
||||
|
||||
//I2C Slave Address
|
||||
const uint8_t DS3231_ADDRESS = 0x68;
|
||||
|
||||
//DS3231 Register Addresses
|
||||
const uint8_t DS3231_REG_TIMEDATE = 0x00;
|
||||
const uint8_t DS3231_REG_ALARMONE = 0x07;
|
||||
const uint8_t DS3231_REG_ALARMTWO = 0x0B;
|
||||
|
||||
const uint8_t DS3231_REG_CONTROL = 0x0E;
|
||||
const uint8_t DS3231_REG_STATUS = 0x0F;
|
||||
const uint8_t DS3231_REG_AGING = 0x10;
|
||||
|
||||
const uint8_t DS3231_REG_TEMP = 0x11;
|
||||
|
||||
//DS3231 Register Data Size if not just 1
|
||||
const uint8_t DS3231_REG_TIMEDATE_SIZE = 7;
|
||||
const uint8_t DS3231_REG_ALARMONE_SIZE = 4;
|
||||
const uint8_t DS3231_REG_ALARMTWO_SIZE = 3;
|
||||
|
||||
const uint8_t DS3231_REG_TEMP_SIZE = 2;
|
||||
|
||||
// DS3231 Control Register Bits
|
||||
const uint8_t DS3231_A1IE = 0;
|
||||
const uint8_t DS3231_A2IE = 1;
|
||||
const uint8_t DS3231_INTCN = 2;
|
||||
const uint8_t DS3231_RS1 = 3;
|
||||
const uint8_t DS3231_RS2 = 4;
|
||||
const uint8_t DS3231_CONV = 5;
|
||||
const uint8_t DS3231_BBSQW = 6;
|
||||
const uint8_t DS3231_EOSC = 7;
|
||||
const uint8_t DS3231_AIEMASK = (_BV(DS3231_A1IE) | _BV(DS3231_A2IE));
|
||||
const uint8_t DS3231_RSMASK = (_BV(DS3231_RS1) | _BV(DS3231_RS2));
|
||||
|
||||
// DS3231 Status Register Bits
|
||||
const uint8_t DS3231_A1F = 0;
|
||||
const uint8_t DS3231_A2F = 1;
|
||||
const uint8_t DS3231_BSY = 2;
|
||||
const uint8_t DS3231_EN32KHZ = 3;
|
||||
const uint8_t DS3231_OSF = 7;
|
||||
const uint8_t DS3231_AIFMASK = (_BV(DS3231_A1F) | _BV(DS3231_A2F));
|
||||
|
||||
|
||||
// seconds accuracy
|
||||
enum DS3231AlarmOneControl
|
||||
{
|
||||
// bit order: A1M4 DY/DT A1M3 A1M2 A1M1
|
||||
DS3231AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch = 0x00,
|
||||
DS3231AlarmOneControl_OncePerSecond = 0x17,
|
||||
DS3231AlarmOneControl_SecondsMatch = 0x16,
|
||||
DS3231AlarmOneControl_MinutesSecondsMatch = 0x14,
|
||||
DS3231AlarmOneControl_HoursMinutesSecondsMatch = 0x10,
|
||||
DS3231AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch = 0x08,
|
||||
};
|
||||
|
||||
class DS3231AlarmOne
|
||||
{
|
||||
public:
|
||||
DS3231AlarmOne( uint8_t dayOf,
|
||||
uint8_t hour,
|
||||
uint8_t minute,
|
||||
uint8_t second,
|
||||
DS3231AlarmOneControl controlFlags) :
|
||||
_flags(controlFlags),
|
||||
_dayOf(dayOf),
|
||||
_hour(hour),
|
||||
_minute(minute),
|
||||
_second(second)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t DayOf() const
|
||||
{
|
||||
return _dayOf;
|
||||
}
|
||||
|
||||
uint8_t Hour() const
|
||||
{
|
||||
return _hour;
|
||||
}
|
||||
|
||||
uint8_t Minute() const
|
||||
{
|
||||
return _minute;
|
||||
}
|
||||
|
||||
uint8_t Second() const
|
||||
{
|
||||
return _second;
|
||||
}
|
||||
|
||||
DS3231AlarmOneControl ControlFlags() const
|
||||
{
|
||||
return _flags;
|
||||
}
|
||||
|
||||
bool operator == (const DS3231AlarmOne& other) const
|
||||
{
|
||||
return (_dayOf == other._dayOf &&
|
||||
_hour == other._hour &&
|
||||
_minute == other._minute &&
|
||||
_second == other._second &&
|
||||
_flags == other._flags);
|
||||
}
|
||||
|
||||
bool operator != (const DS3231AlarmOne& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
protected:
|
||||
DS3231AlarmOneControl _flags;
|
||||
|
||||
uint8_t _dayOf;
|
||||
uint8_t _hour;
|
||||
uint8_t _minute;
|
||||
uint8_t _second;
|
||||
};
|
||||
|
||||
// minutes accuracy
|
||||
enum DS3231AlarmTwoControl
|
||||
{
|
||||
// bit order: A2M4 DY/DT A2M3 A2M2
|
||||
DS3231AlarmTwoControl_HoursMinutesDayOfMonthMatch = 0x00,
|
||||
DS3231AlarmTwoControl_OncePerMinute = 0x0b,
|
||||
DS3231AlarmTwoControl_MinutesMatch = 0x0a,
|
||||
DS3231AlarmTwoControl_HoursMinutesMatch = 0x08,
|
||||
DS3231AlarmTwoControl_HoursMinutesDayOfWeekMatch = 0x04,
|
||||
};
|
||||
|
||||
class DS3231AlarmTwo
|
||||
{
|
||||
public:
|
||||
DS3231AlarmTwo( uint8_t dayOf,
|
||||
uint8_t hour,
|
||||
uint8_t minute,
|
||||
DS3231AlarmTwoControl controlFlags) :
|
||||
_flags(controlFlags),
|
||||
_dayOf(dayOf),
|
||||
_hour(hour),
|
||||
_minute(minute)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t DayOf() const
|
||||
{
|
||||
return _dayOf;
|
||||
}
|
||||
|
||||
uint8_t Hour() const
|
||||
{
|
||||
return _hour;
|
||||
}
|
||||
|
||||
uint8_t Minute() const
|
||||
{
|
||||
return _minute;
|
||||
}
|
||||
|
||||
DS3231AlarmTwoControl ControlFlags() const
|
||||
{
|
||||
return _flags;
|
||||
}
|
||||
|
||||
bool operator == (const DS3231AlarmTwo& other) const
|
||||
{
|
||||
return (_dayOf == other._dayOf &&
|
||||
_hour == other._hour &&
|
||||
_minute == other._minute &&
|
||||
_flags == other._flags);
|
||||
}
|
||||
|
||||
bool operator != (const DS3231AlarmTwo& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
protected:
|
||||
DS3231AlarmTwoControl _flags;
|
||||
|
||||
uint8_t _dayOf;
|
||||
uint8_t _hour;
|
||||
uint8_t _minute;
|
||||
};
|
||||
|
||||
|
||||
enum DS3231SquareWaveClock
|
||||
{
|
||||
DS3231SquareWaveClock_1Hz = 0b00000000,
|
||||
DS3231SquareWaveClock_1kHz = 0b00001000,
|
||||
DS3231SquareWaveClock_4kHz = 0b00010000,
|
||||
DS3231SquareWaveClock_8kHz = 0b00011000,
|
||||
};
|
||||
|
||||
enum DS3231SquareWavePinMode
|
||||
{
|
||||
DS3231SquareWavePin_ModeNone,
|
||||
DS3231SquareWavePin_ModeAlarmOne,
|
||||
DS3231SquareWavePin_ModeAlarmTwo,
|
||||
// note: the same as DS3231SquareWavePin_ModeAlarmOne | DS3231SquareWavePin_ModeAlarmTwo
|
||||
DS3231SquareWavePin_ModeAlarmBoth,
|
||||
DS3231SquareWavePin_ModeClock
|
||||
};
|
||||
|
||||
enum DS3231AlarmFlag
|
||||
{
|
||||
DS3231AlarmFlag_Alarm1 = 0x01,
|
||||
DS3231AlarmFlag_Alarm2 = 0x02,
|
||||
DS3231AlarmFlag_AlarmBoth = 0x03,
|
||||
};
|
||||
|
||||
template<class T_WIRE_METHOD> class RtcDS3231
|
||||
{
|
||||
public:
|
||||
RtcDS3231(T_WIRE_METHOD& wire) :
|
||||
_wire(wire),
|
||||
_lastError(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Begin()
|
||||
{
|
||||
_wire.begin();
|
||||
}
|
||||
|
||||
void Begin(int sda, int scl)
|
||||
{
|
||||
_wire.begin(sda, scl);
|
||||
}
|
||||
|
||||
uint8_t LastError()
|
||||
{
|
||||
return _lastError;
|
||||
}
|
||||
|
||||
bool IsDateTimeValid()
|
||||
{
|
||||
uint8_t status = getReg(DS3231_REG_STATUS);
|
||||
return (!(status & _BV(DS3231_OSF)) && (_lastError == 0));
|
||||
}
|
||||
|
||||
bool GetIsRunning()
|
||||
{
|
||||
uint8_t creg = getReg(DS3231_REG_CONTROL);
|
||||
return (!(creg & _BV(DS3231_EOSC)) && (_lastError == 0));
|
||||
}
|
||||
|
||||
void SetIsRunning(bool isRunning)
|
||||
{
|
||||
uint8_t creg = getReg(DS3231_REG_CONTROL);
|
||||
if (isRunning)
|
||||
{
|
||||
creg &= ~_BV(DS3231_EOSC);
|
||||
}
|
||||
else
|
||||
{
|
||||
creg |= _BV(DS3231_EOSC);
|
||||
}
|
||||
setReg(DS3231_REG_CONTROL, creg);
|
||||
}
|
||||
|
||||
void SetDateTime(const RtcDateTime& dt)
|
||||
{
|
||||
// clear the invalid flag
|
||||
uint8_t status = getReg(DS3231_REG_STATUS);
|
||||
status &= ~_BV(DS3231_OSF); // clear the flag
|
||||
setReg(DS3231_REG_STATUS, status);
|
||||
|
||||
// set the date time
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_TIMEDATE);
|
||||
|
||||
_wire.write(Uint8ToBcd(dt.Second()));
|
||||
_wire.write(Uint8ToBcd(dt.Minute()));
|
||||
_wire.write(Uint8ToBcd(dt.Hour())); // 24 hour mode only
|
||||
|
||||
uint8_t year = dt.Year() - 2000;
|
||||
uint8_t centuryFlag = 0;
|
||||
|
||||
if (year >= 100)
|
||||
{
|
||||
year -= 100;
|
||||
centuryFlag = _BV(7);
|
||||
}
|
||||
|
||||
// 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.Day()));
|
||||
_wire.write(Uint8ToBcd(dt.Month()) | centuryFlag);
|
||||
_wire.write(Uint8ToBcd(year));
|
||||
|
||||
_lastError = _wire.endTransmission();
|
||||
}
|
||||
|
||||
RtcDateTime GetDateTime()
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_TIMEDATE);
|
||||
_lastError = _wire.endTransmission();
|
||||
if (_lastError != 0)
|
||||
{
|
||||
return RtcDateTime(0);
|
||||
}
|
||||
|
||||
uint8_t bytesRead = _wire.requestFrom(DS3231_ADDRESS, DS3231_REG_TIMEDATE_SIZE);
|
||||
if (DS3231_REG_TIMEDATE_SIZE != bytesRead)
|
||||
{
|
||||
_lastError = 4;
|
||||
return RtcDateTime(0);
|
||||
}
|
||||
|
||||
uint8_t second = BcdToUint8(_wire.read() & 0x7F);
|
||||
uint8_t minute = BcdToUint8(_wire.read());
|
||||
uint8_t hour = BcdToBin24Hour(_wire.read());
|
||||
|
||||
_wire.read(); // throwing away day of week as we calculate it
|
||||
|
||||
uint8_t dayOfMonth = BcdToUint8(_wire.read());
|
||||
uint8_t monthRaw = _wire.read();
|
||||
uint16_t year = BcdToUint8(_wire.read()) + 2000;
|
||||
|
||||
if (monthRaw & _BV(7)) // century wrap flag
|
||||
{
|
||||
year += 100;
|
||||
}
|
||||
uint8_t month = BcdToUint8(monthRaw & 0x7f);
|
||||
|
||||
|
||||
return RtcDateTime(year, month, dayOfMonth, hour, minute, second);
|
||||
}
|
||||
|
||||
RtcTemperature GetTemperature()
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_TEMP);
|
||||
_lastError = _wire.endTransmission();
|
||||
if (_lastError != 0)
|
||||
{
|
||||
return RtcTemperature(0);
|
||||
}
|
||||
|
||||
// Temperature is represented as a 10-bit code with a resolution
|
||||
// of 1/4th °C and is accessable as a signed 16-bit integer at
|
||||
// locations 11h and 12h.
|
||||
//
|
||||
// | r11h | DP | r12h |
|
||||
// Bit: 15 14 13 12 11 10 9 8 . 7 6 5 4 3 2 1 0 -1 -2
|
||||
// s i i i i i i i . f f 0 0 0 0 0 0
|
||||
//
|
||||
// As it takes (8) right-shifts to register the decimal point (DP) to
|
||||
// the right of the 0th bit, the overall word scaling equals 256.
|
||||
//
|
||||
// For example, at +/- 25.25°C, concatenated registers <r11h:r12h> =
|
||||
// 256 * (+/- 25+(1/4)) = +/- 6464, or 1940h / E6C0h.
|
||||
|
||||
uint8_t bytesRead = _wire.requestFrom(DS3231_ADDRESS, DS3231_REG_TEMP_SIZE);
|
||||
if (DS3231_REG_TEMP_SIZE != bytesRead)
|
||||
{
|
||||
_lastError = 4;
|
||||
return RtcTemperature(0);
|
||||
}
|
||||
|
||||
int8_t r11h = _wire.read(); // MS byte, signed temperature
|
||||
return RtcTemperature( r11h, _wire.read() ); // LS byte is r12h
|
||||
}
|
||||
|
||||
void Enable32kHzPin(bool enable)
|
||||
{
|
||||
uint8_t sreg = getReg(DS3231_REG_STATUS);
|
||||
|
||||
if (enable == true)
|
||||
{
|
||||
sreg |= _BV(DS3231_EN32KHZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
sreg &= ~_BV(DS3231_EN32KHZ);
|
||||
}
|
||||
|
||||
setReg(DS3231_REG_STATUS, sreg);
|
||||
}
|
||||
|
||||
void SetSquareWavePin(DS3231SquareWavePinMode pinMode, bool enableWhileInBatteryBackup = true)
|
||||
{
|
||||
uint8_t creg = getReg(DS3231_REG_CONTROL);
|
||||
|
||||
// clear all relevant bits to a known "off" state
|
||||
creg &= ~(DS3231_AIEMASK | _BV(DS3231_BBSQW));
|
||||
creg |= _BV(DS3231_INTCN); // set INTCN to disables clock SQW
|
||||
|
||||
if (pinMode != DS3231SquareWavePin_ModeNone)
|
||||
{
|
||||
if (pinMode == DS3231SquareWavePin_ModeClock)
|
||||
{
|
||||
creg &= ~_BV(DS3231_INTCN); // clear INTCN to enable clock SQW
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pinMode & DS3231SquareWavePin_ModeAlarmOne)
|
||||
{
|
||||
creg |= _BV(DS3231_A1IE);
|
||||
}
|
||||
if (pinMode & DS3231SquareWavePin_ModeAlarmTwo)
|
||||
{
|
||||
creg |= _BV(DS3231_A2IE);
|
||||
}
|
||||
}
|
||||
|
||||
if (enableWhileInBatteryBackup)
|
||||
{
|
||||
creg |= _BV(DS3231_BBSQW); // set enable int/sqw while in battery backup flag
|
||||
}
|
||||
}
|
||||
setReg(DS3231_REG_CONTROL, creg);
|
||||
}
|
||||
|
||||
void SetSquareWavePinClockFrequency(DS3231SquareWaveClock freq)
|
||||
{
|
||||
uint8_t creg = getReg(DS3231_REG_CONTROL);
|
||||
|
||||
creg &= ~DS3231_RSMASK; // Set to 0
|
||||
creg |= (freq & DS3231_RSMASK); // Set freq bits
|
||||
|
||||
setReg(DS3231_REG_CONTROL, creg);
|
||||
}
|
||||
|
||||
|
||||
void SetAlarmOne(const DS3231AlarmOne& alarm)
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_ALARMONE);
|
||||
|
||||
_wire.write(Uint8ToBcd(alarm.Second()) | ((alarm.ControlFlags() & 0x01) << 7));
|
||||
_wire.write(Uint8ToBcd(alarm.Minute()) | ((alarm.ControlFlags() & 0x02) << 6));
|
||||
_wire.write(Uint8ToBcd(alarm.Hour()) | ((alarm.ControlFlags() & 0x04) << 5)); // 24 hour mode only
|
||||
|
||||
uint8_t rtcDow = alarm.DayOf();
|
||||
if (alarm.ControlFlags() == DS3231AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch)
|
||||
{
|
||||
rtcDow = RtcDateTime::ConvertDowToRtc(rtcDow);
|
||||
}
|
||||
|
||||
_wire.write(Uint8ToBcd(rtcDow) | ((alarm.ControlFlags() & 0x18) << 3));
|
||||
|
||||
_lastError = _wire.endTransmission();
|
||||
}
|
||||
|
||||
void SetAlarmTwo(const DS3231AlarmTwo& alarm)
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_ALARMTWO);
|
||||
|
||||
_wire.write(Uint8ToBcd(alarm.Minute()) | ((alarm.ControlFlags() & 0x01) << 7));
|
||||
_wire.write(Uint8ToBcd(alarm.Hour()) | ((alarm.ControlFlags() & 0x02) << 6)); // 24 hour mode only
|
||||
|
||||
// convert our Day of Week to Rtc Day of Week if needed
|
||||
uint8_t rtcDow = alarm.DayOf();
|
||||
if (alarm.ControlFlags() == DS3231AlarmTwoControl_HoursMinutesDayOfWeekMatch)
|
||||
{
|
||||
rtcDow = RtcDateTime::ConvertDowToRtc(rtcDow);
|
||||
}
|
||||
|
||||
_wire.write(Uint8ToBcd(rtcDow) | ((alarm.ControlFlags() & 0x0c) << 4));
|
||||
|
||||
_lastError = _wire.endTransmission();
|
||||
}
|
||||
|
||||
DS3231AlarmOne GetAlarmOne()
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_ALARMONE);
|
||||
_lastError = _wire.endTransmission();
|
||||
if (_lastError != 0)
|
||||
{
|
||||
return DS3231AlarmOne(0, 0, 0, 0, DS3231AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch);
|
||||
}
|
||||
|
||||
uint8_t bytesRead = _wire.requestFrom(DS3231_ADDRESS, DS3231_REG_ALARMONE_SIZE);
|
||||
if (DS3231_REG_ALARMONE_SIZE != bytesRead)
|
||||
{
|
||||
_lastError = 4;
|
||||
return DS3231AlarmOne(0, 0, 0, 0, DS3231AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch);
|
||||
}
|
||||
|
||||
uint8_t raw = _wire.read();
|
||||
uint8_t flags = (raw & 0x80) >> 7;
|
||||
uint8_t second = BcdToUint8(raw & 0x7F);
|
||||
|
||||
raw = _wire.read();
|
||||
flags |= (raw & 0x80) >> 6;
|
||||
uint8_t minute = BcdToUint8(raw & 0x7F);
|
||||
|
||||
raw = _wire.read();
|
||||
flags |= (raw & 0x80) >> 5;
|
||||
uint8_t hour = BcdToBin24Hour(raw & 0x7f);
|
||||
|
||||
raw = _wire.read();
|
||||
flags |= (raw & 0xc0) >> 3;
|
||||
uint8_t dayOf = BcdToUint8(raw & 0x3f);
|
||||
|
||||
if (flags == DS3231AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch)
|
||||
{
|
||||
dayOf = RtcDateTime::ConvertRtcToDow(dayOf);
|
||||
}
|
||||
|
||||
return DS3231AlarmOne(dayOf, hour, minute, second, (DS3231AlarmOneControl)flags);
|
||||
}
|
||||
|
||||
DS3231AlarmTwo GetAlarmTwo()
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(DS3231_REG_ALARMTWO);
|
||||
_lastError = _wire.endTransmission();
|
||||
if (_lastError != 0)
|
||||
{
|
||||
return DS3231AlarmTwo(0, 0, 0, DS3231AlarmTwoControl_HoursMinutesDayOfMonthMatch);
|
||||
}
|
||||
|
||||
uint8_t bytesRead = _wire.requestFrom(DS3231_ADDRESS, DS3231_REG_ALARMTWO_SIZE);
|
||||
if (DS3231_REG_ALARMTWO_SIZE != bytesRead)
|
||||
{
|
||||
_lastError = 4;
|
||||
return DS3231AlarmTwo(0, 0, 0, DS3231AlarmTwoControl_HoursMinutesDayOfMonthMatch);
|
||||
}
|
||||
|
||||
uint8_t raw = _wire.read();
|
||||
uint8_t flags = (raw & 0x80) >> 7;
|
||||
uint8_t minute = BcdToUint8(raw & 0x7F);
|
||||
|
||||
raw = _wire.read();
|
||||
flags |= (raw & 0x80) >> 6;
|
||||
uint8_t hour = BcdToBin24Hour(raw & 0x7f);
|
||||
|
||||
raw = _wire.read();
|
||||
flags |= (raw & 0xc0) >> 4;
|
||||
uint8_t dayOf = BcdToUint8(raw & 0x3f);
|
||||
|
||||
if (flags == DS3231AlarmTwoControl_HoursMinutesDayOfWeekMatch)
|
||||
{
|
||||
dayOf = RtcDateTime::ConvertRtcToDow(dayOf);
|
||||
}
|
||||
|
||||
return DS3231AlarmTwo(dayOf, hour, minute, (DS3231AlarmTwoControl)flags);
|
||||
}
|
||||
|
||||
// Latch must be called after an alarm otherwise it will not
|
||||
// trigger again
|
||||
DS3231AlarmFlag LatchAlarmsTriggeredFlags()
|
||||
{
|
||||
uint8_t sreg = getReg(DS3231_REG_STATUS);
|
||||
uint8_t alarmFlags = (sreg & DS3231_AIFMASK);
|
||||
sreg &= ~DS3231_AIFMASK; // clear the flags
|
||||
setReg(DS3231_REG_STATUS, sreg);
|
||||
return (DS3231AlarmFlag)alarmFlags;
|
||||
}
|
||||
|
||||
void ForceTemperatureCompensationUpdate(bool block)
|
||||
{
|
||||
uint8_t creg = getReg(DS3231_REG_CONTROL);
|
||||
creg |= _BV(DS3231_CONV); // Write CONV bit
|
||||
setReg(DS3231_REG_CONTROL, creg);
|
||||
|
||||
while (block && (creg & _BV(DS3231_CONV)) != 0)
|
||||
{
|
||||
// Block until CONV is 0
|
||||
creg = getReg(DS3231_REG_CONTROL);
|
||||
}
|
||||
}
|
||||
|
||||
int8_t GetAgingOffset()
|
||||
{
|
||||
return getReg(DS3231_REG_AGING);
|
||||
}
|
||||
|
||||
void SetAgingOffset(int8_t value)
|
||||
{
|
||||
setReg(DS3231_REG_AGING, value);
|
||||
}
|
||||
|
||||
private:
|
||||
T_WIRE_METHOD& _wire;
|
||||
uint8_t _lastError;
|
||||
|
||||
uint8_t getReg(uint8_t regAddress)
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(regAddress);
|
||||
_lastError = _wire.endTransmission();
|
||||
if (_lastError != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// control register
|
||||
uint8_t bytesRead = _wire.requestFrom(DS3231_ADDRESS, (uint8_t)1);
|
||||
if (1 != bytesRead)
|
||||
{
|
||||
_lastError = 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t regValue = _wire.read();
|
||||
return regValue;
|
||||
}
|
||||
|
||||
void setReg(uint8_t regAddress, uint8_t regValue)
|
||||
{
|
||||
_wire.beginTransmission(DS3231_ADDRESS);
|
||||
_wire.write(regAddress);
|
||||
_wire.write(regValue);
|
||||
_lastError = _wire.endTransmission();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // __RTCDS3231_H__
|
||||
699
arduino-libs/arduino-cli/libraries/Rtc_by_Makuna/src/RtcDS3234.h
Normal file
699
arduino-libs/arduino-cli/libraries/Rtc_by_Makuna/src/RtcDS3234.h
Normal file
@@ -0,0 +1,699 @@
|
||||
|
||||
|
||||
#ifndef __RTCDS3234_H__
|
||||
#define __RTCDS3234_H__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#include "RtcDateTime.h"
|
||||
#include "RtcTemperature.h"
|
||||
#include "RtcUtility.h"
|
||||
|
||||
|
||||
//DS3234 Register Addresses
|
||||
const uint8_t DS3234_REG_WRITE_FLAG = 0x80;
|
||||
|
||||
const uint8_t DS3234_REG_TIMEDATE = 0x00;
|
||||
|
||||
const uint8_t DS3234_REG_ALARMONE = 0x07;
|
||||
const uint8_t DS3234_REG_ALARMTWO = 0x0B;
|
||||
|
||||
const uint8_t DS3234_REG_CONTROL = 0x0E;
|
||||
const uint8_t DS3234_REG_STATUS = 0x0F;
|
||||
const uint8_t DS3234_REG_AGING = 0x10;
|
||||
|
||||
const uint8_t DS3234_REG_TEMP = 0x11;
|
||||
|
||||
const uint8_t DS3234_REG_RAM_ADDRESS = 0x18;
|
||||
const uint8_t DS3234_REG_RAM_DATA = 0x19;
|
||||
|
||||
const uint8_t DS3234_RAMSTART = 0x00;
|
||||
const uint8_t DS3234_RAMEND = 0xFF;
|
||||
const uint8_t DS3234_RAMSIZE = DS3234_RAMEND - DS3234_RAMSTART;
|
||||
|
||||
// DS3234 Control Register Bits
|
||||
const uint8_t DS3234_A1IE = 0;
|
||||
const uint8_t DS3234_A2IE = 1;
|
||||
const uint8_t DS3234_INTCN = 2;
|
||||
const uint8_t DS3234_RS1 = 3;
|
||||
const uint8_t DS3234_RS2 = 4;
|
||||
const uint8_t DS3234_CONV = 5;
|
||||
const uint8_t DS3234_BBSQW = 6;
|
||||
const uint8_t DS3234_EOSC = 7;
|
||||
const uint8_t DS3234_AIEMASK = (_BV(DS3234_A1IE) | _BV(DS3234_A2IE));
|
||||
const uint8_t DS3234_RSMASK = (_BV(DS3234_RS1) | _BV(DS3234_RS2));
|
||||
|
||||
// DS3234 Status Register Bits
|
||||
const uint8_t DS3234_A1F = 0;
|
||||
const uint8_t DS3234_A2F = 1;
|
||||
const uint8_t DS3234_BSY = 2;
|
||||
const uint8_t DS3234_EN32KHZ = 3;
|
||||
const uint8_t DS3234_CRATE0 = 4;
|
||||
const uint8_t DS3234_CRATE1 = 5;
|
||||
const uint8_t DS3234_BB32KHZ = 6;
|
||||
const uint8_t DS3234_OSF = 7;
|
||||
const uint8_t DS3234_AIFMASK = (_BV(DS3234_A1F) | _BV(DS3234_A2F));
|
||||
const uint8_t DS3234_CRATEMASK = (_BV(DS3234_CRATE0) | _BV(DS3234_CRATE1));
|
||||
|
||||
// seconds accuracy
|
||||
enum DS3234AlarmOneControl
|
||||
{
|
||||
// bit order: A1M4 DY/DT A1M3 A1M2 A1M1
|
||||
DS3234AlarmOneControl_HoursMinutesSecondsDayOfMonthMatch = 0x00,
|
||||
DS3234AlarmOneControl_OncePerSecond = 0x17,
|
||||
DS3234AlarmOneControl_SecondsMatch = 0x16,
|
||||
DS3234AlarmOneControl_MinutesSecondsMatch = 0x14,
|
||||
DS3234AlarmOneControl_HoursMinutesSecondsMatch = 0x10,
|
||||
DS3234AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch = 0x08,
|
||||
};
|
||||
|
||||
class DS3234AlarmOne
|
||||
{
|
||||
public:
|
||||
DS3234AlarmOne( uint8_t dayOf,
|
||||
uint8_t hour,
|
||||
uint8_t minute,
|
||||
uint8_t second,
|
||||
DS3234AlarmOneControl controlFlags) :
|
||||
_flags(controlFlags),
|
||||
_dayOf(dayOf),
|
||||
_hour(hour),
|
||||
_minute(minute),
|
||||
_second(second)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t DayOf() const
|
||||
{
|
||||
return _dayOf;
|
||||
}
|
||||
|
||||
uint8_t Hour() const
|
||||
{
|
||||
return _hour;
|
||||
}
|
||||
|
||||
uint8_t Minute() const
|
||||
{
|
||||
return _minute;
|
||||
}
|
||||
|
||||
uint8_t Second() const
|
||||
{
|
||||
return _second;
|
||||
}
|
||||
|
||||
DS3234AlarmOneControl ControlFlags() const
|
||||
{
|
||||
return _flags;
|
||||
}
|
||||
|
||||
bool operator == (const DS3234AlarmOne& other) const
|
||||
{
|
||||
return (_dayOf == other._dayOf &&
|
||||
_hour == other._hour &&
|
||||
_minute == other._minute &&
|
||||
_second == other._second &&
|
||||
_flags == other._flags);
|
||||
}
|
||||
|
||||
bool operator != (const DS3234AlarmOne& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
protected:
|
||||
DS3234AlarmOneControl _flags;
|
||||
|
||||
uint8_t _dayOf;
|
||||
uint8_t _hour;
|
||||
uint8_t _minute;
|
||||
uint8_t _second;
|
||||
};
|
||||
|
||||
// minutes accuracy
|
||||
enum DS3234AlarmTwoControl
|
||||
{
|
||||
// bit order: A2M4 DY/DT A2M3 A2M2
|
||||
DS3234AlarmTwoControl_HoursMinutesDayOfMonthMatch = 0x00,
|
||||
DS3234AlarmTwoControl_OncePerMinute = 0x0b,
|
||||
DS3234AlarmTwoControl_MinutesMatch = 0x0a,
|
||||
DS3234AlarmTwoControl_HoursMinutesMatch = 0x08,
|
||||
DS3234AlarmTwoControl_HoursMinutesDayOfWeekMatch = 0x04,
|
||||
};
|
||||
|
||||
class DS3234AlarmTwo
|
||||
{
|
||||
public:
|
||||
DS3234AlarmTwo( uint8_t dayOf,
|
||||
uint8_t hour,
|
||||
uint8_t minute,
|
||||
DS3234AlarmTwoControl controlFlags) :
|
||||
_flags(controlFlags),
|
||||
_dayOf(dayOf),
|
||||
_hour(hour),
|
||||
_minute(minute)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t DayOf() const
|
||||
{
|
||||
return _dayOf;
|
||||
}
|
||||
|
||||
uint8_t Hour() const
|
||||
{
|
||||
return _hour;
|
||||
}
|
||||
|
||||
uint8_t Minute() const
|
||||
{
|
||||
return _minute;
|
||||
}
|
||||
|
||||
DS3234AlarmTwoControl ControlFlags() const
|
||||
{
|
||||
return _flags;
|
||||
}
|
||||
|
||||
bool operator == (const DS3234AlarmTwo& other) const
|
||||
{
|
||||
return (_dayOf == other._dayOf &&
|
||||
_hour == other._hour &&
|
||||
_minute == other._minute &&
|
||||
_flags == other._flags);
|
||||
}
|
||||
|
||||
bool operator != (const DS3234AlarmTwo& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
protected:
|
||||
DS3234AlarmTwoControl _flags;
|
||||
|
||||
uint8_t _dayOf;
|
||||
uint8_t _hour;
|
||||
uint8_t _minute;
|
||||
};
|
||||
|
||||
|
||||
enum DS3234SquareWaveClock
|
||||
{
|
||||
DS3234SquareWaveClock_1Hz = 0b00000000,
|
||||
DS3234SquareWaveClock_1kHz = 0b00001000,
|
||||
DS3234SquareWaveClock_4kHz = 0b00010000,
|
||||
DS3234SquareWaveClock_8kHz = 0b00011000,
|
||||
};
|
||||
|
||||
enum DS3234SquareWavePinMode
|
||||
{
|
||||
DS3234SquareWavePin_ModeNone,
|
||||
DS3234SquareWavePin_ModeBatteryBackup,
|
||||
DS3234SquareWavePin_ModeClock,
|
||||
DS3234SquareWavePin_ModeAlarmOne,
|
||||
DS3234SquareWavePin_ModeAlarmTwo,
|
||||
DS3234SquareWavePin_ModeAlarmBoth
|
||||
};
|
||||
|
||||
enum DS3234TempCompensationRate
|
||||
{
|
||||
DS3234TempCompensationRate_64Seconds,
|
||||
DS3234TempCompensationRate_128Seconds,
|
||||
DS3234TempCompensationRate_256Seconds,
|
||||
DS3234TempCompensationRate_512Seconds,
|
||||
};
|
||||
|
||||
enum DS3234AlarmFlag
|
||||
{
|
||||
DS3234AlarmFlag_Alarm1 = 0x01,
|
||||
DS3234AlarmFlag_Alarm2 = 0x02,
|
||||
DS3234AlarmFlag_AlarmBoth = 0x03,
|
||||
};
|
||||
|
||||
const SPISettings c_Ds3234SpiSettings(1000000, MSBFIRST, SPI_MODE1); // CPHA must be used, so mode 1 or mode 3 are valid
|
||||
|
||||
template<class T_SPI_METHOD> class RtcDS3234
|
||||
{
|
||||
public:
|
||||
RtcDS3234(T_SPI_METHOD& spi, uint8_t csPin) :
|
||||
_spi(spi),
|
||||
_csPin(csPin)
|
||||
{
|
||||
}
|
||||
|
||||
void Begin()
|
||||
{
|
||||
UnselectChip();
|
||||
pinMode(_csPin, OUTPUT);
|
||||
}
|
||||
|
||||
bool IsDateTimeValid()
|
||||
{
|
||||
uint8_t status = getReg(DS3234_REG_STATUS);
|
||||
return !(status & _BV(DS3234_OSF));
|
||||
}
|
||||
|
||||
bool GetIsRunning()
|
||||
{
|
||||
uint8_t creg = getReg(DS3234_REG_CONTROL);
|
||||
return !(creg & _BV(DS3234_EOSC));
|
||||
}
|
||||
|
||||
void SetIsRunning(bool isRunning)
|
||||
{
|
||||
uint8_t creg = getReg(DS3234_REG_CONTROL);
|
||||
if (isRunning)
|
||||
{
|
||||
creg &= ~_BV(DS3234_EOSC);
|
||||
}
|
||||
else
|
||||
{
|
||||
creg |= _BV(DS3234_EOSC);
|
||||
}
|
||||
setReg(DS3234_REG_CONTROL, creg);
|
||||
}
|
||||
|
||||
void SetDateTime(const RtcDateTime& dt)
|
||||
{
|
||||
// clear the invalid flag
|
||||
uint8_t status = getReg(DS3234_REG_STATUS);
|
||||
status &= ~_BV(DS3234_OSF); // clear the flag
|
||||
setReg(DS3234_REG_STATUS, status);
|
||||
|
||||
// set the date time
|
||||
_spi.beginTransaction(c_Ds3234SpiSettings);
|
||||
SelectChip();
|
||||
_spi.transfer(DS3234_REG_TIMEDATE | DS3234_REG_WRITE_FLAG);
|
||||
|
||||
_spi.transfer(Uint8ToBcd(dt.Second()));
|
||||
_spi.transfer(Uint8ToBcd(dt.Minute()));
|
||||
_spi.transfer(Uint8ToBcd(dt.Hour())); // 24 hour mode only
|
||||
|
||||
uint8_t year = dt.Year() - 2000;
|
||||
uint8_t centuryFlag = 0;
|
||||
|
||||
if (year >= 100)
|
||||
{
|
||||
year -= 100;
|
||||
centuryFlag = _BV(7);
|
||||
}
|
||||
|
||||
// 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());
|
||||
|
||||
_spi.transfer(Uint8ToBcd(rtcDow));
|
||||
|
||||
_spi.transfer(Uint8ToBcd(dt.Day()));
|
||||
_spi.transfer(Uint8ToBcd(dt.Month()) | centuryFlag);
|
||||
_spi.transfer(Uint8ToBcd(year));
|
||||
UnselectChip();
|
||||
_spi.endTransaction();
|
||||
}
|
||||
|
||||
RtcDateTime GetDateTime()
|
||||
{
|
||||
_spi.beginTransaction(c_Ds3234SpiSettings);
|
||||
SelectChip();
|
||||
|
||||
_spi.transfer(DS3234_REG_TIMEDATE);
|
||||
|
||||
uint8_t second = BcdToUint8(_spi.transfer(0));
|
||||
uint8_t minute = BcdToUint8(_spi.transfer(0));
|
||||
uint8_t hour = BcdToBin24Hour(_spi.transfer(0));
|
||||
|
||||
_spi.transfer(0); // throwing away day of week as we calculate it
|
||||
|
||||
uint8_t dayOfMonth = BcdToUint8(_spi.transfer(0));
|
||||
uint8_t monthRaw = _spi.transfer(0);
|
||||
uint16_t year = BcdToUint8(_spi.transfer(0)) + 2000;
|
||||
|
||||
UnselectChip();
|
||||
_spi.endTransaction();
|
||||
|
||||
if (monthRaw & _BV(7)) // century wrap flag
|
||||
{
|
||||
year += 100;
|
||||
}
|
||||
uint8_t month = BcdToUint8(monthRaw & 0x7f);
|
||||
|
||||
return RtcDateTime(year, month, dayOfMonth, hour, minute, second);
|
||||
}
|
||||
|
||||
RtcTemperature GetTemperature()
|
||||
{
|
||||
_spi.beginTransaction(c_Ds3234SpiSettings);
|
||||
SelectChip();
|
||||
_spi.transfer(DS3234_REG_TEMP);
|
||||
|
||||
// Temperature is represented as a 10-bit code with a resolution
|
||||
// of 1/4th °C and is accessable as a signed 16-bit integer at
|
||||
// locations 11h and 12h.
|
||||
//
|
||||
// | r11h | DP | r12h |
|
||||
// Bit: 15 14 13 12 11 10 9 8 . 7 6 5 4 3 2 1 0 -1 -2
|
||||
// s i i i i i i i . f f 0 0 0 0 0 0
|
||||
//
|
||||
// As it takes (8) right-shifts to register the decimal point (DP) to
|
||||
// the right of the 0th bit, the overall word scaling equals 256.
|
||||
//
|
||||
// For example, at +/- 25.25°C, concatenated registers <r11h:r12h> =
|
||||
// 256 * (+/- 25+(1/4)) = +/- 6464, or 1940h / E6C0h.
|
||||
|
||||
int8_t ms = _spi.transfer(0); // MS byte, signed temperature
|
||||
uint8_t ls = _spi.transfer(0); // LS byte is r12h
|
||||
|
||||
UnselectChip();
|
||||
_spi.endTransaction();
|
||||
|
||||
return RtcTemperature(ms, ls); // LS byte is r12h
|
||||
}
|
||||
|
||||
void Enable32kHzPin(bool enable)
|
||||
{
|
||||
uint8_t sreg = getReg(DS3234_REG_STATUS);
|
||||
|
||||
if (enable == true)
|
||||
{
|
||||
sreg |= _BV(DS3234_EN32KHZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
sreg &= ~_BV(DS3234_EN32KHZ);
|
||||
}
|
||||
|
||||
setReg(DS3234_REG_STATUS, sreg);
|
||||
}
|
||||
|
||||
void SetSquareWavePin(DS3234SquareWavePinMode pinMode)
|
||||
{
|
||||
uint8_t creg = getReg(DS3234_REG_CONTROL);
|
||||
|
||||
// clear all relevant bits to a known "off" state
|
||||
creg &= ~(DS3234_AIEMASK | _BV(DS3234_BBSQW));
|
||||
creg |= _BV(DS3234_INTCN); // set INTCN to disables SQW
|
||||
|
||||
switch (pinMode)
|
||||
{
|
||||
case DS3234SquareWavePin_ModeNone:
|
||||
break;
|
||||
|
||||
case DS3234SquareWavePin_ModeBatteryBackup:
|
||||
creg |= _BV(DS3234_BBSQW); // set battery backup flag
|
||||
creg &= ~_BV(DS3234_INTCN); // clear INTCN to enable SQW
|
||||
break;
|
||||
|
||||
case DS3234SquareWavePin_ModeClock:
|
||||
creg &= ~_BV(DS3234_INTCN); // clear INTCN to enable SQW
|
||||
break;
|
||||
|
||||
case DS3234SquareWavePin_ModeAlarmOne:
|
||||
creg |= _BV(DS3234_A1IE);
|
||||
break;
|
||||
|
||||
case DS3234SquareWavePin_ModeAlarmTwo:
|
||||
creg |= _BV(DS3234_A2IE);
|
||||
break;
|
||||
|
||||
case DS3234SquareWavePin_ModeAlarmBoth:
|
||||
creg |= _BV(DS3234_A1IE) | _BV(DS3234_A2IE);
|
||||
break;
|
||||
}
|
||||
|
||||
setReg(DS3234_REG_CONTROL, creg);
|
||||
}
|
||||
|
||||
void SetSquareWavePinClockFrequency(DS3234SquareWaveClock freq)
|
||||
{
|
||||
uint8_t creg = getReg(DS3234_REG_CONTROL);
|
||||
|
||||
creg &= ~DS3234_RSMASK; // Set to 0
|
||||
creg |= (freq & DS3234_RSMASK); // Set freq bits
|
||||
|
||||
setReg(DS3234_REG_CONTROL, creg);
|
||||
}
|
||||
|
||||
|
||||
void SetAlarmOne(const DS3234AlarmOne& alarm)
|
||||
{
|
||||
_spi.beginTransaction(c_Ds3234SpiSettings);
|
||||
SelectChip();
|
||||
|
||||
_spi.transfer(DS3234_REG_ALARMONE | DS3234_REG_WRITE_FLAG);
|
||||
|
||||
_spi.transfer(Uint8ToBcd(alarm.Second()) | ((alarm.ControlFlags() & 0x01) << 7));
|
||||
_spi.transfer(Uint8ToBcd(alarm.Minute()) | ((alarm.ControlFlags() & 0x02) << 6));
|
||||
_spi.transfer(Uint8ToBcd(alarm.Hour()) | ((alarm.ControlFlags() & 0x04) << 5)); // 24 hour mode only
|
||||
|
||||
uint8_t rtcDow = alarm.DayOf();
|
||||
if (alarm.ControlFlags() == DS3234AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch)
|
||||
{
|
||||
rtcDow = RtcDateTime::ConvertDowToRtc(rtcDow);
|
||||
}
|
||||
|
||||
_spi.transfer(Uint8ToBcd(rtcDow) | ((alarm.ControlFlags() & 0x18) << 3));
|
||||
|
||||
UnselectChip();
|
||||
_spi.endTransaction();
|
||||
}
|
||||
|
||||
void SetAlarmTwo(const DS3234AlarmTwo& alarm)
|
||||
{
|
||||
_spi.beginTransaction(c_Ds3234SpiSettings);
|
||||
SelectChip();
|
||||
|
||||
_spi.transfer(DS3234_REG_ALARMTWO | DS3234_REG_WRITE_FLAG);
|
||||
|
||||
_spi.transfer(Uint8ToBcd(alarm.Minute()) | ((alarm.ControlFlags() & 0x01) << 7));
|
||||
_spi.transfer(Uint8ToBcd(alarm.Hour()) | ((alarm.ControlFlags() & 0x02) << 6)); // 24 hour mode only
|
||||
|
||||
// convert our Day of Week to Rtc Day of Week if needed
|
||||
uint8_t rtcDow = alarm.DayOf();
|
||||
if (alarm.ControlFlags() == DS3234AlarmTwoControl_HoursMinutesDayOfWeekMatch)
|
||||
{
|
||||
rtcDow = RtcDateTime::ConvertDowToRtc(rtcDow);
|
||||
}
|
||||
|
||||
_spi.transfer(Uint8ToBcd(rtcDow) | ((alarm.ControlFlags() & 0x0c) << 4));
|
||||
|
||||
UnselectChip();
|
||||
_spi.endTransaction();
|
||||
}
|
||||
|
||||
DS3234AlarmOne GetAlarmOne()
|
||||
{
|
||||
_spi.beginTransaction(c_Ds3234SpiSettings);
|
||||
SelectChip();
|
||||
|
||||
_spi.transfer(DS3234_REG_ALARMONE);
|
||||
|
||||
uint8_t raw = _spi.transfer(0);
|
||||
uint8_t flags = (raw & 0x80) >> 7;
|
||||
uint8_t second = BcdToUint8(raw & 0x7F);
|
||||
|
||||
raw = _spi.transfer(0);
|
||||
flags |= (raw & 0x80) >> 6;
|
||||
uint8_t minute = BcdToUint8(raw & 0x7F);
|
||||
|
||||
raw = _spi.transfer(0);
|
||||
flags |= (raw & 0x80) >> 5;
|
||||
uint8_t hour = BcdToBin24Hour(raw & 0x7f);
|
||||
|
||||
raw = _spi.transfer(0);
|
||||
flags |= (raw & 0xc0) >> 3;
|
||||
uint8_t dayOf = BcdToUint8(raw & 0x3f);
|
||||
|
||||
UnselectChip();
|
||||
_spi.endTransaction();
|
||||
|
||||
if (flags == DS3234AlarmOneControl_HoursMinutesSecondsDayOfWeekMatch)
|
||||
{
|
||||
dayOf = RtcDateTime::ConvertRtcToDow(dayOf);
|
||||
}
|
||||
|
||||
return DS3234AlarmOne(dayOf, hour, minute, second, (DS3234AlarmOneControl)flags);
|
||||
}
|
||||
|
||||
DS3234AlarmTwo GetAlarmTwo()
|
||||
{
|
||||
_spi.beginTransaction(c_Ds3234SpiSettings);
|
||||
SelectChip();
|
||||
|
||||
_spi.transfer(DS3234_REG_ALARMTWO);
|
||||
|
||||
uint8_t raw = _spi.transfer(0);
|
||||
uint8_t flags = (raw & 0x80) >> 7;
|
||||
uint8_t minute = BcdToUint8(raw & 0x7F);
|
||||
|
||||
raw = _spi.transfer(0);
|
||||
flags |= (raw & 0x80) >> 6;
|
||||
uint8_t hour = BcdToBin24Hour(raw & 0x7f);
|
||||
|
||||
raw = _spi.transfer(0);
|
||||
flags |= (raw & 0xc0) >> 4;
|
||||
uint8_t dayOf = BcdToUint8(raw & 0x3f);
|
||||
|
||||
UnselectChip();
|
||||
_spi.endTransaction();
|
||||
|
||||
if (flags == DS3234AlarmTwoControl_HoursMinutesDayOfWeekMatch)
|
||||
{
|
||||
dayOf = RtcDateTime::ConvertRtcToDow(dayOf);
|
||||
}
|
||||
|
||||
return DS3234AlarmTwo(dayOf, hour, minute, (DS3234AlarmTwoControl)flags);
|
||||
}
|
||||
|
||||
// Latch must be called after an alarm otherwise it will not
|
||||
// trigger again
|
||||
DS3234AlarmFlag LatchAlarmsTriggeredFlags()
|
||||
{
|
||||
uint8_t sreg = getReg(DS3234_REG_STATUS);
|
||||
uint8_t alarmFlags = (sreg & DS3234_AIFMASK);
|
||||
sreg &= ~DS3234_AIFMASK; // clear the flags
|
||||
setReg(DS3234_REG_STATUS, sreg);
|
||||
return (DS3234AlarmFlag)alarmFlags;
|
||||
}
|
||||
|
||||
void SetTemperatureCompensationRate(DS3234TempCompensationRate rate)
|
||||
{
|
||||
uint8_t sreg = getReg(DS3234_REG_STATUS);
|
||||
|
||||
sreg &= ~DS3234_CRATEMASK;
|
||||
sreg |= (rate << DS3234_CRATE0);
|
||||
|
||||
setReg(DS3234_REG_STATUS, sreg);
|
||||
}
|
||||
|
||||
DS3234TempCompensationRate GetTemperatureCompensationRate()
|
||||
{
|
||||
uint8_t sreg = getReg(DS3234_REG_STATUS);
|
||||
return (sreg & DS3234_CRATEMASK) >> DS3234_CRATE0;
|
||||
}
|
||||
|
||||
void ForceTemperatureCompensationUpdate(bool block)
|
||||
{
|
||||
uint8_t creg = getReg(DS3234_REG_CONTROL);
|
||||
creg |= _BV(DS3234_CONV); // Write CONV bit
|
||||
setReg(DS3234_REG_CONTROL, creg);
|
||||
|
||||
while (block && (creg & _BV(DS3234_CONV)) != 0)
|
||||
{
|
||||
// Block until CONV is 0
|
||||
creg = getReg(DS3234_REG_CONTROL);
|
||||
}
|
||||
}
|
||||
|
||||
int8_t GetAgingOffset()
|
||||
{
|
||||
return getReg(DS3234_REG_AGING);
|
||||
}
|
||||
|
||||
void SetAgingOffset(int8_t value)
|
||||
{
|
||||
setReg(DS3234_REG_AGING, value);
|
||||
}
|
||||
|
||||
void SetMemory(uint8_t memoryAddress, uint8_t value)
|
||||
{
|
||||
SetMemory(memoryAddress, &value, 1);
|
||||
}
|
||||
|
||||
uint8_t GetMemory(uint8_t memoryAddress)
|
||||
{
|
||||
uint8_t value;
|
||||
|
||||
GetMemory(memoryAddress, &value, 1);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t SetMemory(uint8_t memoryAddress, const uint8_t* pValue, uint8_t countBytes)
|
||||
{
|
||||
uint8_t countWritten = 0;
|
||||
|
||||
setReg(DS3234_REG_RAM_ADDRESS, memoryAddress);
|
||||
|
||||
_spi.beginTransaction(c_Ds3234SpiSettings);
|
||||
SelectChip();
|
||||
_spi.transfer(DS3234_REG_RAM_DATA | DS3234_REG_WRITE_FLAG);
|
||||
|
||||
while (countBytes > 0)
|
||||
{
|
||||
_spi.transfer(*pValue++);
|
||||
|
||||
countBytes--;
|
||||
countWritten++;
|
||||
}
|
||||
|
||||
UnselectChip();
|
||||
_spi.endTransaction();
|
||||
|
||||
return countWritten;
|
||||
}
|
||||
|
||||
uint8_t GetMemory(uint8_t memoryAddress, uint8_t* pValue, uint8_t countBytes)
|
||||
{
|
||||
// set address to read from
|
||||
setReg(DS3234_REG_RAM_ADDRESS, memoryAddress);
|
||||
|
||||
_spi.beginTransaction(c_Ds3234SpiSettings);
|
||||
SelectChip();
|
||||
_spi.transfer(DS3234_REG_RAM_DATA);
|
||||
|
||||
// read the data
|
||||
uint8_t countRead = 0;
|
||||
|
||||
while (countBytes-- > 0)
|
||||
{
|
||||
*pValue++ = _spi.transfer(0);
|
||||
countRead++;
|
||||
}
|
||||
|
||||
UnselectChip();
|
||||
_spi.endTransaction();
|
||||
|
||||
return countRead;
|
||||
}
|
||||
|
||||
private:
|
||||
T_SPI_METHOD& _spi;
|
||||
uint8_t _csPin;
|
||||
|
||||
void SelectChip()
|
||||
{
|
||||
digitalWrite(_csPin, LOW);
|
||||
}
|
||||
void UnselectChip()
|
||||
{
|
||||
digitalWrite(_csPin, HIGH);
|
||||
}
|
||||
|
||||
uint8_t getReg(uint8_t regAddress)
|
||||
{
|
||||
uint8_t regValue;
|
||||
_spi.beginTransaction(c_Ds3234SpiSettings);
|
||||
SelectChip();
|
||||
_spi.transfer(regAddress);
|
||||
regValue = _spi.transfer(0);
|
||||
UnselectChip();
|
||||
_spi.endTransaction();
|
||||
|
||||
return regValue;
|
||||
}
|
||||
|
||||
void setReg(uint8_t regAddress, uint8_t regValue)
|
||||
{
|
||||
_spi.beginTransaction(c_Ds3234SpiSettings);
|
||||
SelectChip();
|
||||
_spi.transfer(regAddress | DS3234_REG_WRITE_FLAG);
|
||||
_spi.transfer(regValue);
|
||||
UnselectChip();
|
||||
_spi.endTransaction();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // __RTCDS3234_H__
|
||||
@@ -0,0 +1,211 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "RtcDateTime.h"
|
||||
|
||||
const uint8_t c_daysInMonth[] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };
|
||||
|
||||
RtcDateTime::RtcDateTime(uint32_t secondsFrom2000)
|
||||
{
|
||||
_initWithSecondsFrom2000<uint32_t>(secondsFrom2000);
|
||||
}
|
||||
|
||||
bool RtcDateTime::IsValid() const
|
||||
{
|
||||
// this just tests the most basic validity of the value ranges
|
||||
// and valid leap years
|
||||
// It does not check any time zone or daylight savings time
|
||||
if ((_month > 0 && _month < 13) &&
|
||||
(_dayOfMonth > 0 && _dayOfMonth < 32) &&
|
||||
(_hour < 24) &&
|
||||
(_minute < 60) &&
|
||||
(_second < 60))
|
||||
{
|
||||
// days in a month tests
|
||||
//
|
||||
if (_month == 2)
|
||||
{
|
||||
if (_dayOfMonth > 29)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (_dayOfMonth > 28)
|
||||
{
|
||||
// leap day
|
||||
// check year to make sure its a leap year
|
||||
uint16_t year = Year();
|
||||
|
||||
if ((year % 4) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((year % 100) == 0 &&
|
||||
(year % 400) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_dayOfMonth == 31)
|
||||
{
|
||||
if ((((_month - 1) % 7) % 2) == 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t StringToUint8(const char* pString)
|
||||
{
|
||||
uint8_t value = 0;
|
||||
|
||||
// skip leading 0 and spaces
|
||||
while ('0' == *pString || *pString == ' ')
|
||||
{
|
||||
pString++;
|
||||
}
|
||||
|
||||
// calculate number until we hit non-numeral char
|
||||
while ('0' <= *pString && *pString <= '9')
|
||||
{
|
||||
value *= 10;
|
||||
value += *pString - '0';
|
||||
pString++;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
RtcDateTime::RtcDateTime(const char* date, const char* time)
|
||||
{
|
||||
// sample input: date = "Dec 06 2009", time = "12:34:56"
|
||||
_yearFrom2000 = StringToUint8(date + 9);
|
||||
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
|
||||
switch (date[0])
|
||||
{
|
||||
case 'J':
|
||||
if ( date[1] == 'a' )
|
||||
_month = 1;
|
||||
else if ( date[2] == 'n' )
|
||||
_month = 6;
|
||||
else
|
||||
_month = 7;
|
||||
break;
|
||||
case 'F':
|
||||
_month = 2;
|
||||
break;
|
||||
case 'A':
|
||||
_month = date[1] == 'p' ? 4 : 8;
|
||||
break;
|
||||
case 'M':
|
||||
_month = date[2] == 'r' ? 3 : 5;
|
||||
break;
|
||||
case 'S':
|
||||
_month = 9;
|
||||
break;
|
||||
case 'O':
|
||||
_month = 10;
|
||||
break;
|
||||
case 'N':
|
||||
_month = 11;
|
||||
break;
|
||||
case 'D':
|
||||
_month = 12;
|
||||
break;
|
||||
}
|
||||
_dayOfMonth = StringToUint8(date + 4);
|
||||
_hour = StringToUint8(time);
|
||||
_minute = StringToUint8(time + 3);
|
||||
_second = StringToUint8(time + 6);
|
||||
}
|
||||
|
||||
template <typename T> T DaysSinceFirstOfYear2000(uint16_t year, uint8_t month, uint8_t dayOfMonth)
|
||||
{
|
||||
T days = dayOfMonth;
|
||||
for (uint8_t indexMonth = 1; indexMonth < month; ++indexMonth)
|
||||
{
|
||||
days += pgm_read_byte(c_daysInMonth + indexMonth - 1);
|
||||
}
|
||||
if (month > 2 && year % 4 == 0)
|
||||
{
|
||||
days++;
|
||||
}
|
||||
return days + 365 * year + (year + 3) / 4 - 1;
|
||||
}
|
||||
|
||||
template <typename T> T SecondsIn(T days, uint8_t hours, uint8_t minutes, uint8_t seconds)
|
||||
{
|
||||
return ((days * 24L + hours) * 60 + minutes) * 60 + seconds;
|
||||
}
|
||||
|
||||
uint8_t RtcDateTime::DayOfWeek() const
|
||||
{
|
||||
uint16_t days = DaysSinceFirstOfYear2000<uint16_t>(_yearFrom2000, _month, _dayOfMonth);
|
||||
return (days + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
|
||||
}
|
||||
|
||||
// 32-bit time; as seconds since 1/1/2000
|
||||
uint32_t RtcDateTime::TotalSeconds() const
|
||||
{
|
||||
uint16_t days = DaysSinceFirstOfYear2000<uint16_t>(_yearFrom2000, _month, _dayOfMonth);
|
||||
return SecondsIn<uint32_t>(days, _hour, _minute, _second);
|
||||
}
|
||||
|
||||
// 64-bit time; as seconds since 1/1/2000
|
||||
uint64_t RtcDateTime::TotalSeconds64() const
|
||||
{
|
||||
uint32_t days = DaysSinceFirstOfYear2000<uint32_t>(_yearFrom2000, _month, _dayOfMonth);
|
||||
return SecondsIn<uint64_t>(days, _hour, _minute, _second);
|
||||
}
|
||||
|
||||
// total days since 1/1/2000
|
||||
uint16_t RtcDateTime::TotalDays() const
|
||||
{
|
||||
return DaysSinceFirstOfYear2000<uint16_t>(_yearFrom2000, _month, _dayOfMonth);
|
||||
}
|
||||
|
||||
void RtcDateTime::InitWithIso8601(const char* date)
|
||||
{
|
||||
// sample input: date = "Sat, 06 Dec 2009 12:34:56 GMT"
|
||||
_yearFrom2000 = StringToUint8(date + 13);
|
||||
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
|
||||
switch (date[8])
|
||||
{
|
||||
case 'J':
|
||||
if (date[1 + 8] == 'a')
|
||||
_month = 1;
|
||||
else if (date[2 + 8] == 'n')
|
||||
_month = 6;
|
||||
else
|
||||
_month = 7;
|
||||
break;
|
||||
case 'F':
|
||||
_month = 2;
|
||||
break;
|
||||
case 'A':
|
||||
_month = date[1 + 8] == 'p' ? 4 : 8;
|
||||
break;
|
||||
case 'M':
|
||||
_month = date[2 + 8] == 'r' ? 3 : 5;
|
||||
break;
|
||||
case 'S':
|
||||
_month = 9;
|
||||
break;
|
||||
case 'O':
|
||||
_month = 10;
|
||||
break;
|
||||
case 'N':
|
||||
_month = 11;
|
||||
break;
|
||||
case 'D':
|
||||
_month = 12;
|
||||
break;
|
||||
}
|
||||
_dayOfMonth = StringToUint8(date + 5);
|
||||
_hour = StringToUint8(date + 17);
|
||||
_minute = StringToUint8(date + 20);
|
||||
_second = StringToUint8(date + 23);
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
|
||||
|
||||
#ifndef __RTCDATETIME_H__
|
||||
#define __RTCDATETIME_H__
|
||||
|
||||
// ESP32 complains if not included
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
enum DayOfWeek
|
||||
{
|
||||
DayOfWeek_Sunday = 0,
|
||||
DayOfWeek_Monday,
|
||||
DayOfWeek_Tuesday,
|
||||
DayOfWeek_Wednesday,
|
||||
DayOfWeek_Thursday,
|
||||
DayOfWeek_Friday,
|
||||
DayOfWeek_Saturday,
|
||||
};
|
||||
|
||||
const uint16_t c_OriginYear = 2000;
|
||||
const uint32_t c_Epoch32OfOriginYear = 946684800;
|
||||
extern const uint8_t c_daysInMonth[] PROGMEM;
|
||||
|
||||
class RtcDateTime
|
||||
{
|
||||
public:
|
||||
RtcDateTime(uint32_t secondsFrom2000 = 0);
|
||||
RtcDateTime(uint16_t year,
|
||||
uint8_t month,
|
||||
uint8_t dayOfMonth,
|
||||
uint8_t hour,
|
||||
uint8_t minute,
|
||||
uint8_t second) :
|
||||
_yearFrom2000((year >= c_OriginYear) ? year - c_OriginYear : year),
|
||||
_month(month),
|
||||
_dayOfMonth(dayOfMonth),
|
||||
_hour(hour),
|
||||
_minute(minute),
|
||||
_second(second)
|
||||
{
|
||||
}
|
||||
|
||||
// RtcDateTime compileDateTime(__DATE__, __TIME__);
|
||||
RtcDateTime(const char* date, const char* time);
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
uint16_t Year() const
|
||||
{
|
||||
return c_OriginYear + _yearFrom2000;
|
||||
}
|
||||
uint8_t Month() const
|
||||
{
|
||||
return _month;
|
||||
}
|
||||
uint8_t Day() const
|
||||
{
|
||||
return _dayOfMonth;
|
||||
}
|
||||
uint8_t Hour() const
|
||||
{
|
||||
return _hour;
|
||||
}
|
||||
uint8_t Minute() const
|
||||
{
|
||||
return _minute;
|
||||
}
|
||||
uint8_t Second() const
|
||||
{
|
||||
return _second;
|
||||
}
|
||||
// 0 = Sunday, 1 = Monday, ... 6 = Saturday
|
||||
uint8_t DayOfWeek() const;
|
||||
|
||||
// 32-bit time; as seconds since 1/1/2000
|
||||
uint32_t TotalSeconds() const;
|
||||
|
||||
// 64-bit time; as seconds since 1/1/2000
|
||||
uint64_t TotalSeconds64() const;
|
||||
|
||||
// total days since 1/1/2000
|
||||
uint16_t TotalDays() const;
|
||||
|
||||
// add seconds
|
||||
void operator += (uint32_t seconds)
|
||||
{
|
||||
RtcDateTime after = RtcDateTime( TotalSeconds() + seconds );
|
||||
*this = after;
|
||||
}
|
||||
|
||||
// remove seconds
|
||||
void operator -= (uint32_t seconds)
|
||||
{
|
||||
RtcDateTime before = RtcDateTime( TotalSeconds() - seconds );
|
||||
*this = before;
|
||||
}
|
||||
|
||||
// allows for comparisons to just work (==, <, >, <=, >=, !=)
|
||||
operator uint32_t() const
|
||||
{
|
||||
return TotalSeconds();
|
||||
}
|
||||
|
||||
// Epoch32 support
|
||||
uint32_t Epoch32Time() const
|
||||
{
|
||||
return TotalSeconds() + c_Epoch32OfOriginYear;
|
||||
}
|
||||
void InitWithEpoch32Time(uint32_t time)
|
||||
{
|
||||
_initWithSecondsFrom2000<uint32_t>(time - c_Epoch32OfOriginYear);
|
||||
}
|
||||
|
||||
// Epoch64 support
|
||||
uint64_t Epoch64Time() const
|
||||
{
|
||||
return TotalSeconds64() + c_Epoch32OfOriginYear;
|
||||
}
|
||||
void InitWithEpoch64Time(uint64_t time)
|
||||
{
|
||||
_initWithSecondsFrom2000<uint64_t>(time - c_Epoch32OfOriginYear);
|
||||
}
|
||||
|
||||
void InitWithIso8601(const char* date);
|
||||
|
||||
|
||||
// convert our Day of Week to Rtc Day of Week
|
||||
// RTC Hardware Day of Week is 1-7, 1 = Monday
|
||||
static uint8_t ConvertDowToRtc(uint8_t dow)
|
||||
{
|
||||
if (dow == 0)
|
||||
{
|
||||
dow = 7;
|
||||
}
|
||||
return dow;
|
||||
}
|
||||
|
||||
// convert Rtc Day of Week to our Day of Week
|
||||
static uint8_t ConvertRtcToDow(uint8_t rtcDow)
|
||||
{
|
||||
return (rtcDow % 7);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t _yearFrom2000;
|
||||
uint8_t _month;
|
||||
uint8_t _dayOfMonth;
|
||||
uint8_t _hour;
|
||||
uint8_t _minute;
|
||||
uint8_t _second;
|
||||
|
||||
template <typename T> void _initWithSecondsFrom2000(T secondsFrom2000)
|
||||
{
|
||||
_second = secondsFrom2000 % 60;
|
||||
T timeFrom2000 = secondsFrom2000 / 60;
|
||||
_minute = timeFrom2000 % 60;
|
||||
timeFrom2000 /= 60;
|
||||
_hour = timeFrom2000 % 24;
|
||||
T days = timeFrom2000 / 24;
|
||||
T leapDays;
|
||||
|
||||
for (_yearFrom2000 = 0;; ++_yearFrom2000)
|
||||
{
|
||||
leapDays = (_yearFrom2000 % 4 == 0) ? 1 : 0;
|
||||
if (days < 365U + leapDays)
|
||||
break;
|
||||
days -= 365 + leapDays;
|
||||
}
|
||||
for (_month = 1;; ++_month)
|
||||
{
|
||||
uint8_t daysPerMonth = pgm_read_byte(c_daysInMonth + _month - 1);
|
||||
if (leapDays && _month == 2)
|
||||
daysPerMonth++;
|
||||
if (days < daysPerMonth)
|
||||
break;
|
||||
days -= daysPerMonth;
|
||||
}
|
||||
_dayOfMonth = days + 1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // __RTCDATETIME_H__
|
||||
@@ -0,0 +1,153 @@
|
||||
|
||||
|
||||
#ifndef __RTCTEMPERATURE_H__
|
||||
#define __RTCTEMPERATURE_H__
|
||||
|
||||
|
||||
class RtcTemperature
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
// a) Merge RTC registers into signed scaled temperature (x256),
|
||||
// then bind to RTC resolution.
|
||||
// | r11h | DP | r12h |
|
||||
// Bit: 15 14 13 12 11 10 9 8 . 7 6 5 4 3 2 1 0 -1 -2
|
||||
// s i i i i i i i . f f 0 0 0 0 0 0
|
||||
//
|
||||
// b) Rescale to (x4) by right-shifting (6) bits
|
||||
// | | DP | |
|
||||
// Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 . 1 0 -1 -2
|
||||
// s s s s s s s i i i i i i i f f 0 0
|
||||
RtcTemperature(int8_t highByteDegreesC, uint8_t lowByteDegreesC)
|
||||
{
|
||||
int16_t scaledDegC = ((highByteDegreesC << 8) | (lowByteDegreesC & 0xC0)) >> 6;
|
||||
_centiDegC = scaledDegC * 100 / 4;
|
||||
}
|
||||
|
||||
RtcTemperature(int16_t centiDegC = 0) :
|
||||
_centiDegC(centiDegC)
|
||||
{
|
||||
}
|
||||
|
||||
// Float temperature Celsius
|
||||
float AsFloatDegC()
|
||||
{
|
||||
return (float)_centiDegC / 100.0f;
|
||||
}
|
||||
|
||||
// Float temperature Fahrenheit
|
||||
float AsFloatDegF()
|
||||
{
|
||||
return AsFloatDegC() * 1.8f + 32.0f;
|
||||
}
|
||||
|
||||
// centi degrees (1/100th of a degree),
|
||||
int16_t AsCentiDegC()
|
||||
{
|
||||
return _centiDegC;
|
||||
}
|
||||
|
||||
void Print(Stream& target, uint8_t decimals = 2, char decimal = '.')
|
||||
{
|
||||
int16_t decimalDivisor = 1;
|
||||
int16_t integerPart;
|
||||
int16_t decimalPart;
|
||||
|
||||
{
|
||||
int16_t rounded = abs(_centiDegC);
|
||||
// round up as needed
|
||||
if (decimals == 0)
|
||||
{
|
||||
rounded += 50;
|
||||
}
|
||||
else if (decimals == 1)
|
||||
{
|
||||
rounded += 5;
|
||||
decimalDivisor = 10;
|
||||
}
|
||||
|
||||
integerPart = rounded / 100;
|
||||
decimalPart = (rounded % 100) / decimalDivisor;
|
||||
}
|
||||
|
||||
// test for zero before printing negative sign to not print-0.00
|
||||
if (_centiDegC < 0 && (integerPart != 0 || decimalPart != 0))
|
||||
{
|
||||
target.print('-');
|
||||
}
|
||||
|
||||
// print integer part
|
||||
target.print(integerPart);
|
||||
|
||||
// print decimal part
|
||||
if (decimals != 0)
|
||||
{
|
||||
target.print(decimal);
|
||||
|
||||
if (decimalPart != 0)
|
||||
{
|
||||
target.print(decimalPart);
|
||||
}
|
||||
else
|
||||
{
|
||||
// append zeros as requested
|
||||
while (decimals > 0)
|
||||
{
|
||||
target.print('0');
|
||||
decimals--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const RtcTemperature& other) const
|
||||
{
|
||||
return (_centiDegC == other._centiDegC);
|
||||
};
|
||||
|
||||
bool operator>(const RtcTemperature& other) const
|
||||
{
|
||||
return (_centiDegC > other._centiDegC);
|
||||
};
|
||||
|
||||
bool operator<(const RtcTemperature& other) const
|
||||
{
|
||||
return (_centiDegC < other._centiDegC);
|
||||
};
|
||||
|
||||
bool operator>=(const RtcTemperature& other) const
|
||||
{
|
||||
return (_centiDegC >= other._centiDegC);
|
||||
};
|
||||
|
||||
bool operator<=(const RtcTemperature& other) const
|
||||
{
|
||||
return (_centiDegC <= other._centiDegC);
|
||||
};
|
||||
|
||||
bool operator!=(const RtcTemperature& other) const
|
||||
{
|
||||
return (_centiDegC != other._centiDegC);
|
||||
};
|
||||
|
||||
RtcTemperature operator-(const RtcTemperature& right)
|
||||
{
|
||||
RtcTemperature result;
|
||||
|
||||
result._centiDegC = (_centiDegC - right._centiDegC);
|
||||
return result;
|
||||
}
|
||||
|
||||
RtcTemperature operator+(const RtcTemperature& right)
|
||||
{
|
||||
RtcTemperature result;
|
||||
|
||||
result._centiDegC = (_centiDegC + right._centiDegC);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
int16_t _centiDegC; // 1/100th of a degree temperature (100 x degC)
|
||||
};
|
||||
|
||||
#endif // __RTCTEMPERATURE_H__
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "RtcUtility.h"
|
||||
|
||||
uint8_t BcdToUint8(uint8_t val)
|
||||
{
|
||||
return val - 6 * (val >> 4);
|
||||
}
|
||||
|
||||
uint8_t Uint8ToBcd(uint8_t val)
|
||||
{
|
||||
return val + 6 * (val / 10);
|
||||
}
|
||||
|
||||
uint8_t BcdToBin24Hour(uint8_t bcdHour)
|
||||
{
|
||||
uint8_t hour;
|
||||
if (bcdHour & 0x40)
|
||||
{
|
||||
// 12 hour mode, convert to 24
|
||||
bool isPm = ((bcdHour & 0x20) != 0);
|
||||
|
||||
hour = BcdToUint8(bcdHour & 0x1f);
|
||||
if (isPm)
|
||||
{
|
||||
hour += 12;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hour = BcdToUint8(bcdHour);
|
||||
}
|
||||
return hour;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
#ifndef __RTCUTILITY_H__
|
||||
#define __RTCUTILITY_H__
|
||||
|
||||
// ESP32 complains if not included
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
// Arduino has no standard for attributing methods used for ISRs
|
||||
// even though some platforms require it, so to simplify the problem
|
||||
// for end users, this provides a standard ISR_ATTR
|
||||
#if !defined(ISR_ATTR)
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
#define ISR_ATTR ICACHE_RAM_ATTR
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#define ISR_ATTR ICACHE_RAM_ATTR
|
||||
#else
|
||||
#define ISR_ATTR
|
||||
#endif
|
||||
|
||||
#endif // !defined(ISR_ATTR)
|
||||
|
||||
|
||||
// for some reason, the DUE board support does not define this, even though other non AVR archs do
|
||||
#ifndef _BV
|
||||
#define _BV(b) (1UL << (b))
|
||||
#endif
|
||||
|
||||
extern uint8_t BcdToUint8(uint8_t val);
|
||||
extern uint8_t Uint8ToBcd(uint8_t val);
|
||||
extern uint8_t BcdToBin24Hour(uint8_t bcdHour);
|
||||
|
||||
#endif // __RTCUTILITY_H__
|
||||
@@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
|
||||
//ThreeWire command Read/Write flag
|
||||
const uint8_t THREEWIRE_READFLAG = 0x01;
|
||||
|
||||
class ThreeWire
|
||||
{
|
||||
public:
|
||||
ThreeWire(uint8_t ioPin, uint8_t clkPin, uint8_t cePin) :
|
||||
_ioPin(ioPin),
|
||||
_clkPin(clkPin),
|
||||
_cePin(cePin)
|
||||
{
|
||||
}
|
||||
|
||||
void begin() {
|
||||
resetPins();
|
||||
}
|
||||
|
||||
void end() {
|
||||
resetPins();
|
||||
}
|
||||
|
||||
void beginTransmission(uint8_t command) {
|
||||
digitalWrite(_cePin, LOW); // default, not enabled
|
||||
pinMode(_cePin, OUTPUT);
|
||||
|
||||
digitalWrite(_clkPin, LOW); // default, clock low
|
||||
pinMode(_clkPin, OUTPUT);
|
||||
|
||||
pinMode(_ioPin, OUTPUT);
|
||||
|
||||
digitalWrite(_cePin, HIGH); // start the session
|
||||
delayMicroseconds(4); // tCC = 4us
|
||||
|
||||
write(command, (command & THREEWIRE_READFLAG) == THREEWIRE_READFLAG);
|
||||
}
|
||||
|
||||
void endTransmission() {
|
||||
digitalWrite(_cePin, LOW);
|
||||
delayMicroseconds(4); // tCWH = 4us
|
||||
}
|
||||
|
||||
void write(uint8_t value, bool isDataRequestCommand = false) {
|
||||
for (uint8_t bit = 0; bit < 8; bit++) {
|
||||
digitalWrite(_ioPin, value & 0x01);
|
||||
delayMicroseconds(1); // tDC = 200ns
|
||||
|
||||
// clock up, data is read by DS1302
|
||||
digitalWrite(_clkPin, HIGH);
|
||||
delayMicroseconds(1); // tCH = 1000ns, tCDH = 800ns
|
||||
|
||||
// for the last bit before a read
|
||||
// Set IO line for input before the clock down
|
||||
if (bit == 7 && isDataRequestCommand) {
|
||||
pinMode(_ioPin, INPUT);
|
||||
}
|
||||
|
||||
digitalWrite(_clkPin, LOW);
|
||||
delayMicroseconds(1); // tCL=1000ns, tCDD=800ns
|
||||
|
||||
value >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t read() {
|
||||
uint8_t value = 0;
|
||||
|
||||
for (uint8_t bit = 0; bit < 8; bit++) {
|
||||
// first bit is present on io pin, so only clock the other
|
||||
// bits
|
||||
value |= (digitalRead(_ioPin) << bit);
|
||||
|
||||
// Clock up, prepare for next
|
||||
digitalWrite(_clkPin, HIGH);
|
||||
delayMicroseconds(1);
|
||||
|
||||
// Clock down, value is ready after some time.
|
||||
digitalWrite(_clkPin, LOW);
|
||||
delayMicroseconds(1); // tCL=1000ns, tCDD=800ns
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t _ioPin;
|
||||
const uint8_t _clkPin;
|
||||
const uint8_t _cePin;
|
||||
|
||||
void resetPins() {
|
||||
// just making sure they are in a default low power use state
|
||||
// as required state is set when transmissions are started
|
||||
// three wire devices have internal pull downs so they will be low
|
||||
pinMode(_clkPin, INPUT);
|
||||
pinMode(_ioPin, INPUT);
|
||||
pinMode(_cePin, INPUT);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user