/* * ds1302.cpp: part of the "VoluMaster(tm)" system * * An open-source arduino controller-based digital volume control and input/output selector * * * LICENSE * ------- * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "ds1302.h" #include // not needed yet #include // needed for strlen() #include #include "WConstants.h" // all things wiring / arduino #include "config.h" const char DOWStr[8][4] = {" ", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; const char MonthStr[13][4] = {" ", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; // Max days for each month const unsigned char MaxDays[13] = {99,31,29,31,30,31,30,31,31,30,31,30,31}; static void send1302cmd( unsigned char cmd1, unsigned char cmd2 ); static unsigned char get1302data( unsigned char cmd ); static void ds1302_init( void ); static unsigned char shiftin( void ); static unsigned char DayMap; static unsigned char Hrs; // Hrs has 12/24 and AM/PM bits stripped static unsigned char Mins; static unsigned char Secs; // DS1302's BCD values // ctor DS1302::DS1302( void ) { // init(); } unsigned char DS1302::GetHrs( void ) { return Hrs; } unsigned char DS1302::GetMins( void ) { return Mins; } unsigned char DS1302::GetSecs( void ) { return Secs; } void DS1302::SetHrs( unsigned char val ) { Hrs = val; } void DS1302::SetMins( unsigned char val ) { Mins = val; } void DS1302::SetSecs( unsigned char val ) { Secs = val; } void DS1302::init( void ) { /* * setup RTC (realtime hardware chip-based clock) */ pinMode(CE1302_PIN, OUTPUT); pinMode(DAT1302_PIN, OUTPUT); pinMode(CLK1302_PIN, OUTPUT); // This routine is, most likely, called with the DS1302 running on the // supercap or battery backup, so it is important to preserve its // time values. send1302cmd(WriteCtrl, 0); // Clear write protect Secs = get1302data(ReadSecs); // Clear CH bit, preserving secs reg Secs &= B01111111; send1302cmd(WriteSecs, Secs); #ifdef USE_12_HR_TIME_FORMAT Hrs = get1302data(ReadHrs); // Set 12 hour format, // preserving hrs reg value (Hrs & B00100000) ? PMFlag = 1 : PMFlag = 0; Hrs |= B10000000; // bit 7 in 1302's hours reg // sets 12 hour format send1302cmd(WriteHrs, Hrs); Hrs &= B00011111; // Store Hrs locally // without flag bits #endif send1302cmd(WriteTrickle, TrickleSet); // begin charging the supercap #ifdef USE_12_HR_TIME_FORMAT PMFlag = 0; #endif } //======================= Service Routines ================================// void DS1302::GetTime(void) { Secs = get1302data(ReadSecs); Mins = get1302data(ReadMins); Hrs = get1302data(ReadHrs); #ifdef USE_12_HR_TIME_FORMAT // set PM flag ( (Hrs & B00100000) > 0) ? PMFlag = 1 : PMFlag = 0; Hrs &= B00011111; #endif } // Write time to DS1302 void DS1302::SetTime(void) { #ifdef USE_12_HR_TIME_FORMAT (PMFlag) ? temp = Hrs | B10100000 : temp = Hrs | B10000000; DS1302::send1302cmd(WriteHrs, temp); #endif send1302cmd(WriteHrs, Hrs); send1302cmd(WriteMins, Mins); send1302cmd(WriteSecs, Secs); } static uint8_t ds_bcd2bin( const uint8_t val ) { return (((val >> 4) * 10) + (val & 0x0f)); } unsigned long DS1302::get_abs_time( void ) { unsigned long total_time; // in minutes, ignoring seconds GetTime(); // read all regs of the RTC chip total_time = 60 * ds_bcd2bin(GetHrs()) + ds_bcd2bin(GetMins()); return total_time; } // =================== DS1302 Driver Routines ==============================// static void send1302cmd( unsigned char cmd1, unsigned char cmd2 ) { digitalWrite(CE1302_PIN, 1); // Set CE1302 high delayMicroseconds(2); shiftOut(DAT1302_PIN, CLK1302_PIN, LSBFIRST, cmd1); delayMicroseconds(2); // This delay might not be needed shiftOut(DAT1302_PIN, CLK1302_PIN, LSBFIRST, cmd2); digitalWrite(CE1302_PIN, 0); // Set CE1302 low } static unsigned char get1302data( unsigned char cmd ) { unsigned char dat; digitalWrite(CE1302_PIN, 1); // CE1302 high shiftOut(DAT1302_PIN, CLK1302_PIN, LSBFIRST, cmd); dat = shiftin(); digitalWrite(CE1302_PIN, 0); // CE1302 low return (dat); } // Shifts in a byte from the DS1302. // This routine is called immediately after a shiftout. The first bit is // present on DAT1302 at call, so only 7 additional clock pulses are // required. // Restores DAT1302 to OUTPUT prior to return. static unsigned char shiftin( void ) { unsigned char dat = 0; int i = 0; pinMode(DAT1302_PIN, INPUT); // Set DAT1302 as input for (i=0; i < 7; i++) { if (digitalRead(DAT1302_PIN) == 1) { dat |= B10000000; // we found a 1-bit, so add it to our collection ;) } dat >>= 1; // shift over so that we can logical-OR the next 1-bit (if any) digitalWrite(CLK1302_PIN, 1); // Strobe in next data bit using CLK1302 delay(1); digitalWrite(CLK1302_PIN, 0); delay(1); } pinMode(DAT1302_PIN, OUTPUT); // Restore DAT1302 as output return (dat); }