The Arduino library had a few errors I had to fix to get it to compile for an Argon.
I purchased this mainly because I wanted an RTC and needed a 1HZ square wave output with low power consumption.
This board consumes 240nA of current at 3.3v, 4 extra nA if you enable the 1Hz Square Wave output for a total of 243nA.
The .ino code below sets the RTC via Internet time.
/*
Prints the time from the RV-8803 Real-Time Clock
By: Andy England
SparkFun Electronics
Date: 2/27/2020
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
Feel like supporting our work? Buy a board from SparkFun!
https://www.sparkfun.com/products/14642
This example shows how to print the time from the RTC.
Hardware Connections:
Plug the RTC into the Qwiic port on your microcontroller or on your Qwiic shield/adapter.
If you are using an adapter cable, here is the wire color scheme:
Black=GND, Red=3.3V, Blue=SDA, Yellow=SCL
Open the serial monitor at 115200 baud
*/
//SYSTEM_THREAD(ENABLED);
//SYSTEM_MODE(SEMI_AUTOMATIC);
#include "application.h"
#include "SparkFun_RV8803.h"
RV8803 rtc;
//The below variables control what the date and time will be set to
int sec = 0;
int minute = 6;
int hour = 16; //Set things in 24 hour mode
int date = 10;
int month = 9;
int year = 2020;
int weekday = 4;
void setup() {
Wire.begin();
Serial.begin(115200);
Serial.println("Set Time on RTC");
if (rtc.begin() == false) {
Serial.println("Something went wrong, check wiring");
}
else
{
Serial.println("RTC online!");
}
//Use the time from the Arduino compiler (build time) to set the RTC
//Keep in mind that Arduino does not get the new compiler time every time it compiles. To ensure the proper time is loaded, open up a fresh version of the IDE and load the sketch.
//Also note that due to upload times, compiler time may be a little bit off on seconds/hundredths
//if (rtc.setToCompilerTime() == false) {
// Serial.println("Something went wrong setting the time");
//}
}
void loop() {
//Use the time from the Arduino compiler (build time) to set the RTC
//Keep in mind that Arduino does not get the new compiler time every time it compiles. To ensure the proper time is loaded, open up a fresh version of the IDE and load the sketch.
//Also note that due to upload times, compiler time may be a little bit off on seconds/hundredths
//if (rtc.setToCompilerTime() == false) {
// Serial.println("Something went wrong setting the time");
//}
Time.zone(-4); //Set Time Zone for you.
//Uncomment the below code to set the RTC to your own time
if (rtc.setTime(Time.second(), Time.minute(), Time.hour(), Time.weekday(), Time.day(), Time.month(), Time.year()) == false) {
Serial.println("Something went wrong setting the time");
}
//rtc.set24Hour(); //Uncomment this line if you'd like to set the RTC to 24 hour mode
}
Below is the SparkFun_RV8803.h file:
/******************************************************************************
SparkFun_RV8803.h
RV8803 Arduino Library
Andy England @ SparkFun Electronics
March 3, 2020
https://github.com/sparkfun/Qwiic_RTC
Resources:
Uses Wire.h for i2c operation
Uses SPI.h for SPI operation
Development environment specifics:
Arduino IDE 1.6.4
This code is released under the [MIT License](http://opensource.org/licenses/MIT).
Please review the LICENSE.md file included with this example. If you have any questions
or concerns with licensing, please contact techsupport@sparkfun.com.
Distributed as-is; no warranty is given.
******************************************************************************/
#pragma once
#include "application.h"
//#include "Wire.h"
//The 7-bit I2C address of the RV8803
#define RV8803_ADDR 0x32
#define SUNDAY 0x01
#define MONDAY 0x02
#define TUESDAY 0x04
#define WEDNESDAY 0x08
#define THURSDAY 0x10
#define FRIDAY 0x20
#define SATURDAY 0x40
//Register names:
#define RV8803_RAM 0x07
#define RV8803_HUNDREDTHS 0x10
#define RV8803_SECONDS 0x11
#define RV8803_MINUTES 0x12
#define RV8803_HOURS 0x13
#define RV8803_WEEKDAYS 0x14
#define RV8803_DATE 0x15
#define RV8803_MONTHS 0x16
#define RV8803_YEARS 0x17
#define RV8803_MINUTES_ALARM 0x18
#define RV8803_HOURS_ALARM 0x19
#define RV8803_WEEKDAYS_DATE_ALARM 0x1A
#define RV8803_TIMER_0 0x1B
#define RV8803_TIMER_1 0x1C
#define RV8803_EXTENSION 0x1D
#define RV8803_FLAG 0x1E
#define RV8803_CONTROL 0x1F
#define RV8803_HUNDREDTHS_CAPTURE 0x20
#define RV8803_SECONDS_CAPTURE 0x21
#define RV8803_OFFSET 0x2C
#define RV8803_EVENT_CONTROL 0x2F
//Enable Bits for Alarm Registers
#define ALARM_ENABLE 7
//Extension Register Bits
#define EXTENSION_TEST 7
#define EXTENSION_WADA 6
#define EXTENSION_USEL 5
#define EXTENSION_TE 4
#define EXTENSION_FD 2
#define EXTENSION_TD 0
//Flag Register Bits
#define FLAG_UPDATE 5
#define FLAG_TIMER 4
#define FLAG_ALARM 3
#define FLAG_EVI 2
#define FLAG_V2F 1
#define FLAG_V1F 0
//Interrupt Control Register Bits
#define UPDATE_INTERRUPT 5
#define TIMER_INTERRUPT 4
#define ALARM_INTERRUPT 3 //
#define EVI_INTERRUPT 2 //External Event Interrupt
#define CONTROL_RESET 0
//Event Control Bits
#define EVENT_ECP 7
#define EVENT_EHL 6
#define EVENT_ET 4
#define EVENT_ERST 0
//Possible Settings
#define TWELVE_HOUR_MODE true
#define TWENTYFOUR_HOUR_MODE false
#define COUNTDOWN_TIMER_FREQUENCY_4096_HZ 0b00
#define COUNTDOWN_TIMER_FREQUENCY_64_HZ 0b01
#define COUNTDOWN_TIMER_FREQUENCY_1_HZ 0b10
#define COUNTDOWN_TIMER_FREQUENCY_1_DIV60 0b11
#define CLOCK_OUT_FREQUENCY_32768_HZ 0b00
#define CLOCK_OUT_FREQUENCY_1024_HZ 0b01
#define CLOCK_OUT_FREQUENCY_1_HZ 0b10
#define COUNTDOWN_TIMER_ON true
#define COUNTDOWN_TIMER_OFF false
#define TIME_UPDATE_1_SECOND false
#define TIME_UPDATE_1_MINUTE true
#define ENABLE_EVI_CALIBRATION true
#define DISABLE_EVI_CALIBRATION false
#define EVI_DEBOUNCE_NONE 0b00
#define EVI_DEBOUNCE_256HZ 0b01
#define EVI_DEBOUNCE_64HZ 0b10
#define EVI_DEBOUNCE_8HZ 0b11
#define RISING_EDGE true
#define FALLING_EDGE false
#define EVI_CAPTURE_ENABLE true
#define EVI_CAPTURE_DISABLE false
#define ENABLE true
#define DISABLE false
#define TIME_ARRAY_LENGTH 8 // Total number of writable values in device
enum time_order {
TIME_HUNDREDTHS, // 0
TIME_SECONDS, // 1
TIME_MINUTES, // 2
TIME_HOURS, // 3
TIME_WEEKDAY, // 4
TIME_DATE, // 5
TIME_MONTH, // 6
TIME_YEAR, // 7
};
class RV8803
{
public:
RV8803( void );
bool begin(TwoWire &wirePort = Wire);
void set12Hour();
void set24Hour();
bool is12Hour(); //Returns true if 12hour bit is set
bool isPM(); //Returns true if is12Hour and PM bit is set
char* stringDateUSA(); //Return date in mm-dd-yyyy
char* stringDate(); //Return date in dd-mm-yyyy
char* stringTime(); //Return time hh:mm:ss with AM/PM if in 12 hour mode
char* stringTimestamp(); //Return timestamp in hh:mm:ss:hh, note that this must be read the same minute that the timestamp occurs or the minute will be wrong
char* stringTime8601(); //Return time in ISO 8601 format yyyy-mm-ddThh:mm:ss
bool setTime(uint8_t sec, uint8_t min, uint8_t hour, uint8_t weekday, uint8_t date, uint8_t month, uint16_t year);
bool setTime(uint8_t * time, uint8_t len);
bool setEpoch(uint32_t value);
bool setHundredthsToZero();
bool setSeconds(uint8_t value);
bool setMinutes(uint8_t value);
bool setHours(uint8_t value);
bool setDate(uint8_t value);
bool setWeekday(uint8_t value);
bool setMonth(uint8_t value);
bool setYear(uint16_t value);
bool updateTime(); //Update the local array with the RTC registers
uint8_t getHundredths();
uint8_t getSeconds();
uint8_t getMinutes();
uint8_t getHours();
uint8_t getDate();
uint8_t getWeekday();
uint8_t getMonth();
uint16_t getYear();
uint32_t getEpoch();
uint8_t getHundredthsCapture();
uint8_t getSecondsCapture();
bool setToCompilerTime(); //Uses the hours, mins, etc from compile time to set RTC
bool setCalibrationOffset(float ppm);
float getCalibrationOffset();
bool setEVICalibration(bool eviCalibration);
bool setEVIDebounceTime(uint8_t debounceTime);
bool setEVIEdgeDetection(bool edge);
bool setEVIEventCapture(bool capture);
bool getEVICalibration();
uint8_t getEVIDebounceTime();
bool getEVIEdgeDetection();
bool getEVIEventCapture();
bool setCountdownTimerEnable(bool timerState); //Starts and stops our countdown timer
bool setCountdownTimerClockTicks(uint16_t clockTicks);
bool setCountdownTimerFrequency(uint8_t countdownTimerFrequency);
bool setClockOutTimerFrequency(uint8_t clockOutTimerFrequency);
uint8_t getClockOutTimerFrequency();
bool getCountdownTimerEnable();
uint16_t getCountdownTimerClockTicks();
uint8_t getCountdownTimerFrequency();
bool setPeriodicTimeUpdateFrequency(bool timeUpdateFrequency);
bool getPeriodicTimeUpdateFrequency();
void setItemsToMatchForAlarm(bool minuteAlarm, bool hourAlarm, bool weekdayAlarm, bool dateAlarm); //0 to 7, alarm goes off with match of second, minute, hour, etc
bool setAlarmMinute(uint8_t minute);
bool setAlarmHour(uint8_t hour);
bool setAlarmWeekday(uint8_t weekday);
bool setAlarmDate(uint8_t date);
uint8_t getAlarmMinute();
uint8_t getAlarmHour();
uint8_t getAlarmWeekday();
uint8_t getAlarmDate();
bool enableHardwareInterrupt(uint8_t source); //Enables a given interrupt within Interrupt Enable register
bool disableHardwareInterrupt(uint8_t source); //Disables a given interrupt within Interrupt Enable register
bool disableAllInterrupts();
bool getInterruptFlag(uint8_t flagToGet);
bool clearInterruptFlag(uint8_t flagToClear);
bool clearAllInterruptFlags();
//Values in RTC are stored in Binary Coded Decimal. These functions convert to/from Decimal
uint8_t BCDtoDEC(uint8_t val);
uint8_t DECtoBCD(uint8_t val);
bool readBit(uint8_t regAddr, uint8_t bitAddr);
uint8_t readTwoBits(uint8_t regAddr, uint8_t bitAddr);
bool writeBit(uint8_t regAddr, uint8_t bitAddr, bool bitToWrite);
bool writeBit(uint8_t regAddr, uint8_t bitAddr, uint8_t bitToWrite);
uint8_t readRegister(uint8_t addr);
bool writeRegister(uint8_t addr, uint8_t val);
bool readMultipleRegisters(uint8_t addr, uint8_t * dest, uint8_t len);
bool writeMultipleRegisters(uint8_t addr, uint8_t * values, uint8_t len);
private:
uint8_t _time[TIME_ARRAY_LENGTH];
bool _isTwelveHour = true;
TwoWire *_i2cPort;
};
Here is the
/******************************************************************************
SparkFun_RV8803.h
RV8803 Arduino Library
Andy England @ SparkFun Electronics
March 3, 2020
https://github.com/sparkfun/SparkFun_RV-8803_Arduino_Library
Development environment specifics:
Arduino IDE 1.6.4
This code is released under the [MIT License](http://opensource.org/licenses/MIT).
Please review the LICENSE.md file included with this example. If you have any questions
or concerns with licensing, please contact techsupport@sparkfun.com.
Distributed as-is; no warranty is given.
******************************************************************************/
#include <time.h>
#include "SparkFun_RV8803.h"
//****************************************************************************//
//
// Settings and configuration
//
//****************************************************************************//
// Parse the __DATE__ predefined macro to generate date defaults:
// __Date__ Format: MMM DD YYYY (First D may be a space if <10)
// <MONTH>
#define BUILD_MONTH_JAN ((__DATE__[0] == 'J') && (__DATE__[1] == 'a')) ? 1 : 0
#define BUILD_MONTH_FEB (__DATE__[0] == 'F') ? 2 : 0
#define BUILD_MONTH_MAR ((__DATE__[0] == 'M') && (__DATE__[1] == 'a') && (__DATE__[2] == 'r')) ? 3 : 0
#define BUILD_MONTH_APR ((__DATE__[0] == 'A') && (__DATE__[1] == 'p')) ? 4 : 0
#define BUILD_MONTH_MAY ((__DATE__[0] == 'M') && (__DATE__[1] == 'a') && (__DATE__[2] == 'y')) ? 5 : 0
#define BUILD_MONTH_JUN ((__DATE__[0] == 'J') && (__DATE__[1] == 'u') && (__DATE__[2] == 'n')) ? 6 : 0
#define BUILD_MONTH_JUL ((__DATE__[0] == 'J') && (__DATE__[1] == 'u') && (__DATE__[2] == 'l')) ? 7 : 0
#define BUILD_MONTH_AUG ((__DATE__[0] == 'A') && (__DATE__[1] == 'u')) ? 8 : 0
#define BUILD_MONTH_SEP (__DATE__[0] == 'S') ? 9 : 0
#define BUILD_MONTH_OCT (__DATE__[0] == 'O') ? 10 : 0
#define BUILD_MONTH_NOV (__DATE__[0] == 'N') ? 11 : 0
#define BUILD_MONTH_DEC (__DATE__[0] == 'D') ? 12 : 0
#define BUILD_MONTH BUILD_MONTH_JAN | BUILD_MONTH_FEB | BUILD_MONTH_MAR | \
BUILD_MONTH_APR | BUILD_MONTH_MAY | BUILD_MONTH_JUN | \
BUILD_MONTH_JUL | BUILD_MONTH_AUG | BUILD_MONTH_SEP | \
BUILD_MONTH_OCT | BUILD_MONTH_NOV | BUILD_MONTH_DEC
// <DATE>
#define BUILD_DATE_0 ((__DATE__[4] == ' ') ? 0 : (__DATE__[4] - 0x30))
#define BUILD_DATE_1 (__DATE__[5] - 0x30)
#define BUILD_DATE ((BUILD_DATE_0 * 10) + BUILD_DATE_1)
// <YEAR>
#define BUILD_YEAR (((__DATE__[7] - 0x30) * 1000) + ((__DATE__[8] - 0x30) * 100) + \
((__DATE__[9] - 0x30) * 10) + ((__DATE__[10] - 0x30) * 1))
// Parse the __TIME__ predefined macro to generate time defaults:
// __TIME__ Format: HH:MM:SS (First number of each is padded by 0 if <10)
// <HOUR>
#define BUILD_HOUR_0 ((__TIME__[0] == ' ') ? 0 : (__TIME__[0] - 0x30))
#define BUILD_HOUR_1 (__TIME__[1] - 0x30)
#define BUILD_HOUR ((BUILD_HOUR_0 * 10) + BUILD_HOUR_1)
// <MINUTE>
#define BUILD_MINUTE_0 ((__TIME__[3] == ' ') ? 0 : (__TIME__[3] - 0x30))
#define BUILD_MINUTE_1 (__TIME__[4] - 0x30)
#define BUILD_MINUTE ((BUILD_MINUTE_0 * 10) + BUILD_MINUTE_1)
// <SECOND>
#define BUILD_SECOND_0 ((__TIME__[6] == ' ') ? 0 : (__TIME__[6] - 0x30))
#define BUILD_SECOND_1 (__TIME__[7] - 0x30)
#define BUILD_SECOND ((BUILD_SECOND_0 * 10) + BUILD_SECOND_1)
RV8803::RV8803( void )
{
}
bool RV8803::begin(TwoWire &wirePort)
{
_i2cPort = &wirePort;
_i2cPort->beginTransmission(RV8803_ADDR);
if (_i2cPort->endTransmission() != 0)
{
return (false); //Error: Sensor did not ack
}
return(true);
}
//Configures the microcontroller to convert to 12 hour mode.
void RV8803::set12Hour()
{
_isTwelveHour = TWELVE_HOUR_MODE;
}
//Configures the microcontroller to not convert from the default 24 hour mode.
void RV8803::set24Hour()
{
_isTwelveHour = TWENTYFOUR_HOUR_MODE;
}
//Returns true if the microcontroller has been configured for 12 hour mode
bool RV8803::is12Hour()
{
return _isTwelveHour;
}
//Returns true if the microcontroller is in 12 hour mode and the RTC has an hours value greater than or equal to 12 (Noon).
bool RV8803::isPM()
{
if (is12Hour())
{
return BCDtoDEC(_time[TIME_HOURS]) >= 12;
}
else
{
return false;
}
}
//Returns the date in MM/DD/YYYY format.
char* RV8803::stringDateUSA()
{
static char date[11]; //Max of mm/dd/yyyy with \0 terminator
sprintf(date, "%02d/%02d/20%02d", BCDtoDEC(_time[TIME_MONTH]), BCDtoDEC(_time[TIME_DATE]), BCDtoDEC(_time[TIME_YEAR]));
return(date);
}
//Returns the date in the DD/MM/YYYY format.
char* RV8803::stringDate()
{
static char date[11]; //Max of dd/mm/yyyy with \0 terminator
sprintf(date, "%02d/%02d/20%02d", BCDtoDEC(_time[TIME_DATE]), BCDtoDEC(_time[TIME_MONTH]), BCDtoDEC(_time[TIME_YEAR]));
return(date);
}
//Returns the time in hh:mm:ss (Adds AM/PM if in 12 hour mode).
char* RV8803::stringTime()
{
static char time[11]; //Max of hh:mm:ssXM with \0 terminator
if(is12Hour() == true)
{
char half = 'A';
uint8_t twelveHourCorrection = 0;
if(isPM())
{
half = 'P';
if (BCDtoDEC(_time[TIME_HOURS]) > 12)
{
twelveHourCorrection = 12;
}
}
sprintf(time, "%02d:%02d:%02d%cM", BCDtoDEC(_time[TIME_HOURS]) - twelveHourCorrection, BCDtoDEC(_time[TIME_MINUTES]), BCDtoDEC(_time[TIME_SECONDS]), half);
}
else
sprintf(time, "%02d:%02d:%02d", BCDtoDEC(_time[TIME_HOURS]), BCDtoDEC(_time[TIME_MINUTES]), BCDtoDEC(_time[TIME_SECONDS]));
return(time);
}
//Returns the most recent timestamp captured on the EVI pin (if the EVI pin has been configured to capture events)
char* RV8803::stringTimestamp()
{
static char time[14]; //Max of hh:mm:ss:HHXM with \0 terminator
if(is12Hour() == true)
{
char half = 'A';
uint8_t twelveHourCorrection = 0;
if(isPM())
{
half = 'P';
if (BCDtoDEC(_time[TIME_HOURS]) > 12)
{
twelveHourCorrection = 12;
}
}
sprintf(time, "%02d:%02d:%02d:%02d%cM", BCDtoDEC(_time[TIME_HOURS]) - twelveHourCorrection, BCDtoDEC(_time[TIME_MINUTES]), BCDtoDEC(readRegister(RV8803_SECONDS_CAPTURE)), BCDtoDEC(readRegister(RV8803_HUNDREDTHS_CAPTURE)), half);
}
else
sprintf(time, "%02d:%02d:%02d:%02d", BCDtoDEC(_time[TIME_HOURS]), BCDtoDEC(_time[TIME_MINUTES]), BCDtoDEC(readRegister(RV8803_SECONDS_CAPTURE)), BCDtoDEC(readRegister(RV8803_HUNDREDTHS_CAPTURE)));
return(time);
}
//Returns timestamp in ISO 8601 format (yyyy-mm-ddThh:mm:ss).
char* RV8803::stringTime8601()
{
static char timeStamp[21]; //Max of yyyy-mm-ddThh:mm:ss with \0 terminator
sprintf(timeStamp, "20%02d-%02d-%02dT%02d:%02d:%02d", BCDtoDEC(_time[TIME_YEAR]), BCDtoDEC(_time[TIME_MONTH]), BCDtoDEC(_time[TIME_DATE]), BCDtoDEC(_time[TIME_HOURS]), BCDtoDEC(_time[TIME_MINUTES]), BCDtoDEC(_time[TIME_SECONDS]));
return(timeStamp);
}
//Returns time in UNIX Epoch time format
uint32_t RV8803::getEpoch()
{
struct tm tm;
tm.tm_isdst = -1;
tm.tm_yday = 0;
tm.tm_wday = 0;
tm.tm_year = BCDtoDEC(_time[TIME_YEAR]) + 100;
tm.tm_mon = BCDtoDEC(_time[TIME_MONTH]) - 1;
tm.tm_mday = BCDtoDEC(_time[TIME_DATE]);
tm.tm_hour = BCDtoDEC(_time[TIME_HOURS]);
tm.tm_min = BCDtoDEC(_time[TIME_MINUTES]);
tm.tm_sec = BCDtoDEC(_time[TIME_SECONDS]);
return mktime(&tm);
}
//Sets time using UNIX Epoch time
bool RV8803::setEpoch(uint32_t value)
{
if (value < 946684800) {
value = 946684800; // 2000-01-01 00:00:00
}
struct tm tm;
time_t t = value;
struct tm* tmp = gmtime(&t);
_time[TIME_SECONDS] = DECtoBCD(tmp->tm_sec);
_time[TIME_MINUTES] = DECtoBCD(tmp->tm_min);
_time[TIME_HOURS] = DECtoBCD(tmp->tm_hour);
_time[TIME_DATE] = DECtoBCD(tmp->tm_mday);
_time[TIME_WEEKDAY] = 1 << tmp->tm_wday;
_time[TIME_MONTH] = DECtoBCD(tmp->tm_mon + 1);
_time[TIME_YEAR] = DECtoBCD(tmp->tm_year - 100);
return setTime(_time, TIME_ARRAY_LENGTH); //Subtract one as we don't write to the hundredths register
}
//Set time and date/day registers of RV8803
bool RV8803::setTime(uint8_t sec, uint8_t min, uint8_t hour, uint8_t weekday, uint8_t date, uint8_t month, uint16_t year)
{
_time[TIME_SECONDS] = DECtoBCD(sec);
_time[TIME_MINUTES] = DECtoBCD(min);
_time[TIME_HOURS] = DECtoBCD(hour);
_time[TIME_DATE] = DECtoBCD(date);
_time[TIME_WEEKDAY] = 1 << weekday;
_time[TIME_MONTH] = DECtoBCD(month);
_time[TIME_YEAR] = DECtoBCD(year - 2000);
return setTime(_time, TIME_ARRAY_LENGTH); //Subtract one as we don't write to the hundredths register
}
//Set time and date/day registers of RV8803 (using data array)
bool RV8803::setTime(uint8_t * time, uint8_t len = 8)
{
if (len != TIME_ARRAY_LENGTH)
return false;
return writeMultipleRegisters(RV8803_SECONDS, time + 1, len - 1); //We use length - 1 as that is the length without the read-only hundredths register We also point to the second element in the time array as hundredths is read only
}
bool RV8803::setHundredthsToZero()
{
bool temp = writeBit(RV8803_CONTROL, CONTROL_RESET, ENABLE);
temp &= writeBit(RV8803_CONTROL, CONTROL_RESET, DISABLE);
return temp;
}
bool RV8803::setSeconds(uint8_t value)
{
_time[TIME_SECONDS] = DECtoBCD(value);
return setTime(_time, TIME_ARRAY_LENGTH);
}
bool RV8803::setMinutes(uint8_t value)
{
_time[TIME_MINUTES] = DECtoBCD(value);
return setTime(_time, TIME_ARRAY_LENGTH);
}
bool RV8803::setHours(uint8_t value)
{
_time[TIME_HOURS] = DECtoBCD(value);
return setTime(_time, TIME_ARRAY_LENGTH);
}
bool RV8803::setDate(uint8_t value)
{
_time[TIME_DATE] = DECtoBCD(value);
return setTime(_time, TIME_ARRAY_LENGTH);
}
bool RV8803::setMonth(uint8_t value)
{
_time[TIME_MONTH] = DECtoBCD(value);
return setTime(_time, TIME_ARRAY_LENGTH);
}
bool RV8803::setYear(uint16_t value)
{
_time[TIME_YEAR] = DECtoBCD(value - 2000);
return setTime(_time, TIME_ARRAY_LENGTH);
}
bool RV8803::setWeekday(uint8_t value) //value is anywhere between 0=sunday and 6=saturday
{
if (value > 6)
{
value = 6;
}
_time[TIME_WEEKDAY] = 1 << value;
return setTime(_time, TIME_ARRAY_LENGTH);
}
//Move the hours, mins, sec, etc registers from RV-8803 into the _time array
//Needs to be called before printing time or date
//We do not protect the GPx registers. They will be overwritten. The user has plenty of RAM if they need it.
bool RV8803::updateTime()
{
if (readMultipleRegisters(RV8803_HUNDREDTHS, _time, TIME_ARRAY_LENGTH) == false)
return(false); //Something went wrong
if (BCDtoDEC(_time[TIME_SECONDS]) == 59) //If seconds are at 59, read again to make sure we didn't accidentally skip a minute
{
uint8_t tempTime[TIME_ARRAY_LENGTH];
if (readMultipleRegisters(RV8803_HUNDREDTHS, tempTime, TIME_ARRAY_LENGTH) == false)
{
return(false); //Something went wrong
}
if (BCDtoDEC(tempTime[TIME_SECONDS]) == 0) //If the reading for seconds changed, then our new data is correct, otherwise, we can leave the old data.
{
memcpy(_time, tempTime, TIME_ARRAY_LENGTH);
}
}
return true;
}
uint8_t RV8803::getHundredths()
{
return BCDtoDEC(_time[TIME_HUNDREDTHS]);
}
uint8_t RV8803::getSeconds()
{
return BCDtoDEC(_time[TIME_SECONDS]);
}
uint8_t RV8803::getMinutes()
{
return BCDtoDEC(_time[TIME_MINUTES]);
}
uint8_t RV8803::getHours()
{
uint8_t tempHours = BCDtoDEC(_time[TIME_HOURS]);
if (is12Hour())
{
if (tempHours > 12)
{
tempHours -= 12;
}
}
return tempHours;
}
uint8_t RV8803::getDate()
{
return BCDtoDEC(_time[TIME_DATE]);
}
uint8_t RV8803::getWeekday()
{
uint8_t tempWeekday = _time[TIME_WEEKDAY];
return tempWeekday;
}
uint8_t RV8803::getMonth()
{
return BCDtoDEC(_time[TIME_MONTH]);
}
uint16_t RV8803::getYear()
{
return BCDtoDEC(_time[TIME_YEAR]) + 2000;
}
uint8_t RV8803::getHundredthsCapture()
{
return BCDtoDEC(readRegister(RV8803_HUNDREDTHS_CAPTURE));
}
uint8_t RV8803::getSecondsCapture()
{
return BCDtoDEC(readRegister(RV8803_SECONDS_CAPTURE));
}
//Takes the time from the last build and uses it as the current time
//Works very well as an arduino sketch
bool RV8803::setToCompilerTime()
{
_time[TIME_SECONDS] = DECtoBCD(BUILD_SECOND);
_time[TIME_MINUTES] = DECtoBCD(BUILD_MINUTE);
_time[TIME_HOURS] = DECtoBCD(BUILD_HOUR);
_time[TIME_MONTH] = DECtoBCD(BUILD_MONTH);
_time[TIME_DATE] = DECtoBCD(BUILD_DATE);
_time[TIME_YEAR] = DECtoBCD(BUILD_YEAR - 2000); //! Not Y2K (or Y2.1K)-proof :(
// Calculate weekday (from here: http://stackoverflow.com/a/21235587)
// 0 = Sunday, 6 = Saturday
uint16_t d = BUILD_DATE;
uint16_t m = BUILD_MONTH;
uint16_t y = BUILD_YEAR;
uint16_t weekday = (d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7 + 1;
_time[TIME_WEEKDAY] = 1 << weekday;
return setTime(_time, TIME_ARRAY_LENGTH);
}
bool RV8803::setCalibrationOffset(float ppm)
{
int8_t integerOffset = ppm / 0.2384; //.2384 is ppm/LSB
if (integerOffset < 0)
{
integerOffset += 64;
}
return writeRegister(RV8803_OFFSET, integerOffset);
}
float RV8803:: getCalibrationOffset()
{
int8_t value = readRegister(RV8803_OFFSET);
if (value > 32)
{
value -= 64;
}
return value * .2384;
}
bool RV8803::setEVIDebounceTime(uint8_t debounceTime)
{
return writeBit(RV8803_EVENT_CONTROL, EVENT_ET, debounceTime);
}
bool RV8803::setEVICalibration(bool eviCalibration)
{
return writeBit(RV8803_EVENT_CONTROL, EVENT_ERST, eviCalibration);
}
bool RV8803::setEVIEdgeDetection(bool edge)
{
return writeBit(RV8803_EVENT_CONTROL, EVENT_EHL, edge);
}
bool RV8803::setEVIEventCapture(bool capture)
{
return writeBit(RV8803_EVENT_CONTROL, EVENT_ECP, capture);
}
uint8_t RV8803::getEVIDebounceTime()
{
return readTwoBits(RV8803_EVENT_CONTROL, EVENT_ET);
}
bool RV8803::getEVICalibration()
{
return readBit(RV8803_EVENT_CONTROL, EVENT_ERST);
}
bool RV8803::getEVIEdgeDetection()
{
return readBit(RV8803_EVENT_CONTROL, EVENT_EHL);
}
bool RV8803::getEVIEventCapture()
{
return readBit(RV8803_EVENT_CONTROL, EVENT_ECP);
}
bool RV8803::setCountdownTimerEnable(bool timerState)
{
return writeBit(RV8803_EXTENSION, EXTENSION_TE, timerState);
}
bool RV8803::setCountdownTimerFrequency(uint8_t countdownTimerFrequency)
{
return writeBit(RV8803_EXTENSION, EXTENSION_TD, countdownTimerFrequency);
}
bool RV8803::setCountdownTimerClockTicks(uint16_t clockTicks)
{
//First handle the upper bit, as we need to preserve the GPX bits
uint8_t value = readRegister(RV8803_TIMER_1);
value &= ~(0b00001111); //Clear the least significant nibble
value |= (clockTicks >> 8);
bool returnValue = writeRegister(RV8803_TIMER_1, value);
value = clockTicks & 0x00FF;
returnValue &= writeRegister(RV8803_TIMER_0, value);
return returnValue;
}
bool RV8803::setClockOutTimerFrequency(uint8_t clockOutTimerFrequency)
{
return writeBit(RV8803_EXTENSION, EXTENSION_FD, clockOutTimerFrequency);
}
bool RV8803::getCountdownTimerEnable()
{
return readBit(RV8803_EXTENSION, EXTENSION_TE);
}
uint8_t RV8803::getCountdownTimerFrequency()
{
return readTwoBits(RV8803_EXTENSION, EXTENSION_TD);
}
uint16_t RV8803::getCountdownTimerClockTicks()
{
uint16_t value = readRegister(RV8803_TIMER_1) << 8;
value |= readRegister(RV8803_TIMER_0);
return value;
}
uint8_t RV8803::getClockOutTimerFrequency()
{
return readTwoBits(RV8803_EXTENSION, EXTENSION_FD);
}
bool RV8803::setPeriodicTimeUpdateFrequency(bool timeUpdateFrequency)
{
return writeBit(RV8803_EXTENSION, EXTENSION_USEL, timeUpdateFrequency);
}
bool RV8803::getPeriodicTimeUpdateFrequency()
{
return readBit(RV8803_EXTENSION, EXTENSION_USEL);
}
/********************************
Set Alarm Mode controls which parts of the time have to match for the alarm to trigger.
When the RTC matches a given time, make an interrupt fire.
Setting a bit to 1 means that the RTC does not check if that value matches to trigger the alarm
********************************/
void RV8803::setItemsToMatchForAlarm(bool minuteAlarm, bool hourAlarm, bool weekdayAlarm, bool dateAlarm)
{
writeBit(RV8803_MINUTES_ALARM, ALARM_ENABLE, !minuteAlarm); //For some reason these bits are active low
writeBit(RV8803_HOURS_ALARM, ALARM_ENABLE, !hourAlarm);
writeBit(RV8803_WEEKDAYS_DATE_ALARM, ALARM_ENABLE, !weekdayAlarm);
writeBit(RV8803_EXTENSION, EXTENSION_WADA, dateAlarm);
if (dateAlarm == true)//enabling both weekday and date alarm will default to a date alarm
{
writeBit(RV8803_WEEKDAYS_DATE_ALARM, ALARM_ENABLE, !dateAlarm);
}
}
bool RV8803::setAlarmMinute(uint8_t minute)
{
uint8_t value = readRegister(RV8803_MINUTES_ALARM);
value &= (1 << ALARM_ENABLE); //clear everything but enable bit
value |= DECtoBCD(minute);
return writeRegister(RV8803_MINUTES_ALARM, value);
}
bool RV8803::setAlarmHour(uint8_t hour)
{
uint8_t value = readRegister(RV8803_HOURS_ALARM);
value &= (1 << ALARM_ENABLE); //clear everything but enable bit
value |= DECtoBCD(hour);
return writeRegister(RV8803_HOURS_ALARM, value);
}
bool RV8803::setAlarmWeekday(uint8_t weekday)
{
uint8_t value = readRegister(RV8803_WEEKDAYS_DATE_ALARM);
value &= (1 << ALARM_ENABLE); //clear everything but enable bit
value |= 0x7F & weekday;
return writeRegister(RV8803_WEEKDAYS_DATE_ALARM, value);
}
bool RV8803::setAlarmDate(uint8_t date)
{
uint8_t value = readRegister(RV8803_WEEKDAYS_DATE_ALARM);
value &= (1 << ALARM_ENABLE); //clear everything but enable bit
value |= DECtoBCD(date);
return writeRegister(RV8803_WEEKDAYS_DATE_ALARM, value);
}
/*********************************
Given a bit location, enable the interrupt
INTERRUPT_BLIE 4
INTERRUPT_TIE 3
INTERRUPT_AIE 2
INTERRUPT_EIE 1
*********************************/
bool RV8803::enableHardwareInterrupt(uint8_t source)
{
uint8_t value = readRegister(RV8803_CONTROL);
value |= (1<<source); //Set the interrupt enable bit
return writeRegister(RV8803_CONTROL, value);
}
bool RV8803::disableHardwareInterrupt(uint8_t source)
{
uint8_t value = readRegister(RV8803_CONTROL);
value &= ~(1 << source); //Clear the interrupt enable bit
return writeRegister(RV8803_CONTROL, value);
}
bool RV8803::disableAllInterrupts()
{
uint8_t value = readRegister(RV8803_CONTROL);
value &= 1; //Clear all bits except for Reset
return writeRegister(RV8803_CONTROL, value);
}
bool RV8803::getInterruptFlag(uint8_t flagToGet)
{
uint8_t flag = readRegister(RV8803_FLAG);
flag &= (1 << flagToGet);
flag = flag >> flagToGet;
return flag;
}
bool RV8803::clearAllInterruptFlags() //Read the status register to clear the current interrupt flags
{
return writeRegister(RV8803_FLAG, 0b00000000);//Write all 0's to clear all flags
}
bool RV8803::clearInterruptFlag(uint8_t flagToClear)
{
uint8_t value = readRegister(RV8803_FLAG);
value &= ~(1 << flagToClear); //clear flag
return writeRegister(RV8803_FLAG, value);
}
uint8_t RV8803::BCDtoDEC(uint8_t val)
{
return ( ( val / 0x10) * 10 ) + ( val % 0x10 );
}
// BCDtoDEC -- convert decimal to binary-coded decimal (BCD)
uint8_t RV8803::DECtoBCD(uint8_t val)
{
return ( ( val / 10 ) * 0x10 ) + ( val % 10 );
}
bool RV8803::readBit(uint8_t regAddr, uint8_t bitAddr)
{
return ((readRegister(regAddr) & (1 << bitAddr)) >> bitAddr);
}
uint8_t RV8803::readTwoBits(uint8_t regAddr, uint8_t bitAddr)
{
return ((readRegister(regAddr) & (3 << bitAddr)) >> bitAddr);
}
bool RV8803::writeBit(uint8_t regAddr, uint8_t bitAddr, bool bitToWrite)
{
uint8_t value = readRegister(regAddr);
value &= ~(1 << bitAddr);
value |= bitToWrite << bitAddr;
return writeRegister(regAddr, value);
}
bool RV8803::writeBit(uint8_t regAddr, uint8_t bitAddr, uint8_t bitToWrite) //If we seean unsigned eight bit, we know we have to write two bits.
{
uint8_t value = readRegister(regAddr);
value &= ~(3 << bitAddr);
value |= bitToWrite << bitAddr;
return writeRegister(regAddr, value);
}
uint8_t RV8803::readRegister(uint8_t addr)
{
_i2cPort->beginTransmission(RV8803_ADDR);
_i2cPort->write(addr);
_i2cPort->endTransmission();
//typecasting the 1 parameter in requestFrom so that the compiler
//doesn't give us a warning about multiple candidates
if (_i2cPort->requestFrom(static_cast<uint8_t>(RV8803_ADDR), static_cast<uint8_t>(1)) != 0)
{
return _i2cPort->read();
}
return false;
}
bool RV8803::writeRegister(uint8_t addr, uint8_t val)
{
_i2cPort->beginTransmission(RV8803_ADDR);
_i2cPort->write(addr);
_i2cPort->write(val);
if (_i2cPort->endTransmission() != 0)
return (false); //Error: Sensor did not ack
return(true);
}
bool RV8803::writeMultipleRegisters(uint8_t addr, uint8_t * values, uint8_t len)
{
_i2cPort->beginTransmission(RV8803_ADDR);
_i2cPort->write(addr);
for (uint8_t i = 0; i < len; i++)
{
_i2cPort->write(values[i]);
}
if (_i2cPort->endTransmission() != 0)
return (false); //Error: Sensor did not ack
return(true);
}
bool RV8803::readMultipleRegisters(uint8_t addr, uint8_t * dest, uint8_t len)
{
_i2cPort->beginTransmission(RV8803_ADDR);
_i2cPort->write(addr);
if (_i2cPort->endTransmission() != 0)
return (false); //Error: Sensor did not ack
_i2cPort->requestFrom(static_cast<uint8_t>(RV8803_ADDR), len);
for (uint8_t i = 0; i < len; i++)
{
dest[i] = _i2cPort->read();
}
return(true);
}