forked from luon/wordclock
273 lines
4.3 KiB
C++
273 lines
4.3 KiB
C++
#include "WProgram.h"
|
|
#include "DS1302.h"
|
|
|
|
|
|
/*** Time definitions ***/
|
|
|
|
Time::Time(uint16_t yr, uint8_t mon, uint8_t date,
|
|
uint8_t hr, uint8_t min, uint8_t sec,
|
|
uint8_t day)
|
|
{
|
|
this->yr = yr;
|
|
this->mon = mon;
|
|
this->date = date;
|
|
this->hr = hr;
|
|
this->min = min;
|
|
this->sec = sec;
|
|
this->day = day;
|
|
}
|
|
|
|
|
|
Time::Time()
|
|
{
|
|
Time(2000, 1, 1, 0, 0, 0, 7);
|
|
}
|
|
|
|
|
|
/*** DS1302 definitions ***/
|
|
|
|
DS1302::DS1302(uint8_t ce_pin, uint8_t io_pin, uint8_t sclk_pin)
|
|
{
|
|
_ce_pin = ce_pin;
|
|
_io_pin = io_pin;
|
|
_sclk_pin = sclk_pin;
|
|
|
|
pinMode(ce_pin, OUTPUT);
|
|
pinMode(sclk_pin, OUTPUT);
|
|
}
|
|
|
|
|
|
void DS1302::_write_out(uint8_t value)
|
|
{
|
|
pinMode(_io_pin, OUTPUT);
|
|
shiftOut(_io_pin, _sclk_pin, LSBFIRST, value);
|
|
}
|
|
|
|
|
|
uint8_t DS1302::_read_in()
|
|
{
|
|
uint8_t input_value = 0;
|
|
uint8_t bit = 0;
|
|
pinMode(_io_pin, INPUT);
|
|
|
|
for (int i = 0; i < 8; ++i) {
|
|
bit = digitalRead(_io_pin);
|
|
input_value |= (bit << i);
|
|
|
|
digitalWrite(_sclk_pin, HIGH);
|
|
delayMicroseconds(1);
|
|
digitalWrite(_sclk_pin, LOW);
|
|
}
|
|
|
|
return input_value;
|
|
}
|
|
|
|
|
|
uint8_t DS1302::_register_bcd_to_dec(reg_t reg, uint8_t high_bit)
|
|
{
|
|
uint8_t val = read_register(reg);
|
|
uint8_t mask = (1 << (high_bit + 1)) - 1;
|
|
val &= mask;
|
|
val = (val & 15) + 10 * ((val & (15 << 4)) >> 4);
|
|
return val;
|
|
}
|
|
|
|
|
|
uint8_t DS1302::_register_bcd_to_dec(reg_t reg)
|
|
{
|
|
return _register_bcd_to_dec(reg, 7);
|
|
}
|
|
|
|
|
|
void DS1302::_register_dec_to_bcd(reg_t reg, uint8_t value, uint8_t high_bit)
|
|
{
|
|
uint8_t regv = read_register(reg);
|
|
uint8_t mask = (1 << (high_bit + 1)) - 1;
|
|
|
|
/* convert value to bcd in place */
|
|
uint8_t tvalue = value / 10;
|
|
value = value % 10;
|
|
value |= (tvalue << 4);
|
|
|
|
/* replace high bits of value if needed */
|
|
value &= mask;
|
|
value |= (regv &= ~mask);
|
|
|
|
write_register(reg, value);
|
|
}
|
|
|
|
|
|
void DS1302::_register_dec_to_bcd(reg_t reg, uint8_t value)
|
|
{
|
|
_register_dec_to_bcd(reg, value, 7);
|
|
}
|
|
|
|
|
|
uint8_t DS1302::read_register(reg_t reg)
|
|
{
|
|
uint8_t cmd_byte = 129; /* 1000 0001 */
|
|
uint8_t reg_value;
|
|
cmd_byte |= (reg << 1);
|
|
|
|
digitalWrite(_sclk_pin, LOW);
|
|
digitalWrite(_ce_pin, HIGH);
|
|
|
|
_write_out(cmd_byte);
|
|
reg_value = _read_in();
|
|
|
|
digitalWrite(_ce_pin, LOW);
|
|
|
|
return reg_value;
|
|
}
|
|
|
|
|
|
void DS1302::write_register(reg_t reg, uint8_t value)
|
|
{
|
|
uint8_t cmd_byte = (128 | (reg << 1));
|
|
|
|
digitalWrite(_sclk_pin, LOW);
|
|
digitalWrite(_ce_pin, HIGH);
|
|
|
|
_write_out(cmd_byte);
|
|
_write_out(value);
|
|
|
|
digitalWrite(_ce_pin, LOW);
|
|
}
|
|
|
|
|
|
void DS1302::write_protect(bool enable)
|
|
{
|
|
write_register(WP_REG, (enable << 7));
|
|
}
|
|
|
|
|
|
void DS1302::halt(bool enable)
|
|
{
|
|
uint8_t sec = read_register(SEC_REG);
|
|
sec &= ~(1 << 7);
|
|
sec |= (enable << 7);
|
|
write_register(SEC_REG, sec);
|
|
}
|
|
|
|
|
|
/*** Get time ***/
|
|
|
|
uint8_t DS1302::seconds()
|
|
{
|
|
return _register_bcd_to_dec(SEC_REG, 6);
|
|
}
|
|
|
|
|
|
uint8_t DS1302::minutes()
|
|
{
|
|
return _register_bcd_to_dec(MIN_REG);
|
|
}
|
|
|
|
|
|
uint8_t DS1302::hour()
|
|
{
|
|
uint8_t hr = read_register(HR_REG);
|
|
uint8_t adj;
|
|
if (hr & 128) /* 12-hour mode */
|
|
adj = 12 * ((hr & 32) >> 5);
|
|
else /* 24-hour mode */
|
|
adj = 10 * ((hr & (32 + 16)) >> 4);
|
|
hr = (hr & 15) + adj;
|
|
return hr;
|
|
}
|
|
|
|
|
|
uint8_t DS1302::date()
|
|
{
|
|
return _register_bcd_to_dec(DATE_REG, 5);
|
|
}
|
|
|
|
|
|
uint8_t DS1302::month()
|
|
{
|
|
return _register_bcd_to_dec(MON_REG, 4);
|
|
}
|
|
|
|
|
|
uint8_t DS1302::day()
|
|
{
|
|
return _register_bcd_to_dec(DAY_REG, 2);
|
|
}
|
|
|
|
|
|
uint16_t DS1302::year()
|
|
{
|
|
return 2000 + _register_bcd_to_dec(YR_REG);
|
|
}
|
|
|
|
|
|
Time DS1302::time()
|
|
{
|
|
Time t;
|
|
t.sec = seconds();
|
|
t.min = minutes();
|
|
t.hr = hour();
|
|
t.date = date();
|
|
t.mon = month();
|
|
t.day = day();
|
|
t.yr = year();
|
|
return t;
|
|
}
|
|
|
|
|
|
/*** Set time ***/
|
|
|
|
void DS1302::seconds(uint8_t sec)
|
|
{
|
|
_register_dec_to_bcd(SEC_REG, sec, 6);
|
|
}
|
|
|
|
|
|
void DS1302::minutes(uint8_t min)
|
|
{
|
|
_register_dec_to_bcd(MIN_REG, min, 6);
|
|
}
|
|
|
|
|
|
void DS1302::hour(uint8_t hr)
|
|
{
|
|
write_register(HR_REG, 0); /* set 24-hour mode */
|
|
_register_dec_to_bcd(HR_REG, hr, 5);
|
|
}
|
|
|
|
|
|
void DS1302::date(uint8_t date)
|
|
{
|
|
_register_dec_to_bcd(DATE_REG, date, 5);
|
|
}
|
|
|
|
|
|
void DS1302::month(uint8_t mon)
|
|
{
|
|
_register_dec_to_bcd(MON_REG, mon, 4);
|
|
}
|
|
|
|
|
|
void DS1302::day(uint8_t day)
|
|
{
|
|
_register_dec_to_bcd(DAY_REG, day, 2);
|
|
}
|
|
|
|
|
|
void DS1302::year(uint16_t yr)
|
|
{
|
|
yr -= 2000;
|
|
_register_dec_to_bcd(YR_REG, yr);
|
|
}
|
|
|
|
|
|
void DS1302::time(Time t)
|
|
{
|
|
seconds(t.sec);
|
|
minutes(t.min);
|
|
hour(t.hr);
|
|
date(t.date);
|
|
month(t.mon);
|
|
day(t.day);
|
|
year(t.yr);
|
|
}
|