DS3232M RTC demo program. Tested on the K64F (this example) and the KL25Z, but should work on any platform by changing the SDA and SCL pins. USB serial baud rate is 230400, tested on TeraTerm. Demo includes setting the DS3232's time, turning on and off the 32KHz and 1Hz outputs and accessing the DS3232's temperature. Also included are DS3232 user RAM access tests and user RAM CRC data calculations. Since user RAM is battery backed up, CRC routines are included to insure that the data stored in user RAM is intact.

Dependencies:   ds3232m mbed mbed-rtos

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "rtos.h"                           //mbed rtos - uncomment to make RTOS available
00003 #include "ds3232m.h"                        //Maxim RTC
00004 
00005 #ifdef RTOS_H
00006 Mutex MutexI2cWait_1;                       //lock/unlock I2C requests
00007 RawSerial pc(USBTX, USBRX);                 //console interface for RTOS
00008 #else
00009 Serial pc(USBTX, USBRX);                    //console interface
00010 #endif  //RTOS_H
00011 
00012 #define SDA0        D14                     //assuming arduino pins
00013 #define SCL0        D15
00014 ds3232m rtc(SDA0, SCL0, 400000);            //Maxim real time clock
00015 
00016 //--------------------------------------------------------------------------------------------------------------------------------------//
00017 // Time variables
00018 
00019 time_t ctTime;                              //time structure
00020 int DST = 1;                                //Daylight Saving Time (or as defined in .ini file)
00021 int TZone = -8;                             //Time Zone from UTC (or as defined in .ini file)
00022 char timebuf_hms[10];                       //local time format buffer - 21:16:43
00023 char timebuf_dMyy[14];                      //local time format buffer - 01-Apr-2014
00024 char timebuf_dow[1];                        //local time format buffer - 5
00025 int StartTime = 0;                          //time we powered up
00026 bool allowDisplayTime = false;              //used to stop displaying date/time when entering data from the console
00027 
00028 //--------------------------------------------------------------------------------------------------------------------------------------//
00029 //Variables for USB Serial Port RX
00030 
00031 uint32_t pcRxQty = 0;                       //RX data counter/pointer
00032 char pcRxBuffer[128];                       //RX data buffer
00033 bool pcRxLine = false;                      //CR or LF detected (end of line)
00034 bool pcRxEOB = false;                       //RX buffer is full!!! cannot accept any more characters
00035 char inchar = 0;                            //RX input character
00036 
00037 //--------------------------------------------------------------------------------------------------------------------------------------//
00038 // various Mutex lock/unlock definitions
00039 
00040 void lockI2C() {
00041 #ifdef RTOS_H
00042     MutexI2cWait_1.lock();
00043 #endif  //RTOS_H
00044 }
00045 
00046 void unlockI2C() {
00047 #ifdef RTOS_H
00048     MutexI2cWait_1.unlock();
00049 #endif  //RTOS_H
00050 }
00051 
00052 //--------------------------------------------------------------------------------------------------------------------------------------//
00053 // This function is called when a character goes into the RX buffer.
00054 
00055 #define DOUPONELINE         "\033[1A"
00056 #define BS                  0x08                    //ascii backspace
00057 #define CR                  0x0d                    //ascii CR
00058 #define LF                  0x0a                    //ascii LF
00059 #define ticC                0x03                    //ascii control C
00060 #define DEGC_DEGF_FLOAT     9.0 / 5.0 + 32.0
00061 
00062 void PcRxChar(char inchar) {
00063     if(inchar == CR) pc.printf(" %c %c", BS, BS);   //NOTE: Bug in K64F has issue with CR and/or LF, these 2 lines are needed
00064     if(inchar == LF) pc.printf(" %c %c", BS, BS);
00065     if(inchar == BS) { 
00066         if(pcRxQty == 0) {
00067             pcRxBuffer[pcRxQty] = 0;
00068         } else {
00069             pc.printf("%c %c", BS, BS);
00070             pcRxQty--;
00071             pcRxBuffer[pcRxQty] = 0;
00072         }
00073     } else if((inchar == CR) || (inchar == LF)) { 
00074         pcRxLine = true;
00075         pc.printf("\r\n");
00076     } else if(inchar == ticC) {
00077         NVIC_SystemReset();
00078     } else {
00079         if(pcRxQty < (sizeof(pcRxBuffer) - 2)) {
00080             pcRxBuffer[pcRxQty] = inchar;
00081             pcRxQty++;
00082             pcRxBuffer[pcRxQty] = 0;
00083             pc.printf("%c", pcRxBuffer[pcRxQty - 1]);
00084         } else {
00085             pc.printf ("\r\n*** pcRxBuffer is full!!\r\n");
00086             pcRxEOB = true;
00087         }
00088     }
00089 }
00090 
00091 //--------------------------------------------------------------------------------------------------------------------------------------//
00092 // Read received chars from USB UART interrupt
00093 
00094 void PcRxIRQ(void){
00095 /*
00096 #if defined(TARGET_KL25Z)
00097     NVIC_DisableIRQ(UART0_IRQn);        // n=0, 1 or 2  Disable Rx interrupt on kl25z
00098 #endif
00099 #if defined(TARGET_K64F)
00100     NVIC_DisableIRQ(UART0_RX_TX_IRQn);  // n=0, 1 or 2  Disable Rx interrupt on k64f
00101 #endif
00102 #if defined(TARGET_LPC1768)
00103     LPC_UART0->IER = 0;                 //Disable Rx interrupt on mbed1768
00104 #endif
00105 */
00106     while (pc.readable()) {
00107         inchar = pc.getc();             //read data from USB
00108         PcRxChar(inchar);               //go process char
00109     }
00110 /*
00111 #if defined(TARGET_KL25Z)
00112     NVIC_EnableIRQ(UART0_IRQn);         // n=0, 1 or 2  Re-enable Rx interrupt on kl25z
00113 #endif
00114 #if defined(TARGET_K64F)
00115     NVIC_EnableIRQ(UART0_RX_TX_IRQn);   // n=0, 1 or 2  Re-enable Rx interrupt on k64f
00116 #endif
00117 #if defined(TARGET_LPC1768)
00118     LPC_UART0->IER = 1;                 //RE-enable Rx interrupt on mbed1768
00119 #endif
00120 */
00121 }
00122 
00123 //--------------------------------------------------------------------------------------------------------------------------------------//
00124 //clear RxData buffer with all 00's and clear flags
00125 
00126 void pcClrLineBuf() {
00127     pcRxQty = 0;                                                            // data counter/pointer
00128     for(int i = 0; i < (sizeof(pcRxBuffer) - 1); i++) pcRxBuffer[i] = 0;    // clear out rx buffer
00129     pcRxLine = false;
00130     pcRxEOB = false;
00131 }
00132 
00133 //--------------------------------------------------------------------------------------------------------------------------------------//
00134 // Update time display values
00135 
00136 void UpdateTimeRegs() {
00137     strftime(timebuf_dMyy, 14, "%d-%b-%Y", localtime(&ctTime));
00138     strftime(timebuf_hms, 10, "%H:%M:%S", localtime(&ctTime));
00139     strftime(timebuf_dow, 1, "%u", localtime(&ctTime));
00140 }
00141 
00142 void UpdateTime() {
00143     ctTime = time(NULL) + ((TZone + DST) * 3600);   //timezone and dst offsets
00144     UpdateTimeRegs();
00145 }
00146 
00147 //--------------------------------------------------------------------------------------------------------------------------------------//
00148 // display current local date and time
00149 
00150 void PrintDateTime() {
00151     pc.printf("%sDate: %s   ",  DOUPONELINE, timebuf_dMyy);
00152     pc.printf("Time: %s \r\n", timebuf_hms);
00153 }
00154 
00155 //--------------------------------------------------------------------------------------------------------------------------------------//
00156 //Manually set the date and time
00157 
00158 ds3232m::Time_rtc rtc_m = {};
00159 struct tm t;
00160 
00161 bool SetRTC() {
00162     pc.printf("Enter current date and time:\n");
00163     pc.printf("MM DD YY HH MM SS[enter]\n");  
00164     pcClrLineBuf(); 
00165      
00166     //wait for string above
00167     do{
00168 #ifdef RTOS_H
00169         Thread::wait(10);
00170 #else
00171         wait_ms(10);
00172 #endif
00173     } while((pcRxLine == false) && (pcRxEOB == false));
00174     
00175     //load up the time structure
00176     t.tm_year = (2000 + ((pcRxBuffer[6] - '0') * 10) + pcRxBuffer[7] - '0');
00177     t.tm_mon =  (((pcRxBuffer[0] - '0') * 10) + pcRxBuffer[1] - '0');
00178     t.tm_mday = (((pcRxBuffer[3] - '0') * 10) + pcRxBuffer[4] - '0');
00179     t.tm_hour = (((pcRxBuffer[9] - '0') * 10) + pcRxBuffer[10] - '0');
00180     t.tm_min = (((pcRxBuffer[12] - '0') * 10) + pcRxBuffer[13] - '0');
00181     t.tm_sec = (((pcRxBuffer[15] - '0') * 10) + pcRxBuffer[16] - '0');
00182     
00183     //adjust for tm structure required values
00184     t.tm_year = t.tm_year - 1900;
00185     t.tm_mon = t.tm_mon - 1;  
00186     t.tm_wday = t.tm_wday & 7;
00187     
00188     //if error exists, exit without changing time
00189     if(t.tm_year < 113) return(32);
00190     if(t.tm_mon > 12) return(16); 
00191     if(t.tm_mday > 31) return(8);  
00192     if(t.tm_hour > 23) return(4); 
00193     if(t.tm_min > 59) return(2); 
00194     if(t.tm_sec > 59) return(1); 
00195     
00196     //set up the DS3232's RTC
00197     rtc_m.sec = t.tm_sec;
00198     rtc_m.min = t.tm_min;
00199     rtc_m.hour = t.tm_hour;
00200     rtc_m.wday = t.tm_wday;
00201     rtc_m.date = t.tm_mday;
00202     rtc_m.mon = t.tm_mon + 1;
00203     rtc_m.year = t.tm_year + 1900;
00204     rtc.setTime(rtc_m);    //(time structure)
00205 
00206     //set the mbed's time
00207     time_t ctTime = mktime(&t);
00208     //reset system up time since it will be out of whack once the time is updated
00209     StartTime = ctTime;                         //have to change sysuptime now
00210     ctTime = ctTime - (TZone + DST) * 3600;     //take out local time
00211     set_time(ctTime);
00212     UpdateTime();
00213     return(0);
00214 }
00215 
00216 //--------------------------------------------------------------------------------------------------------------------------------------//
00217 // Load the local mbed-RTC from that external DS3232 RTC
00218 
00219 void loadRTC() {
00220     lockI2C();
00221     //get data from DS3232
00222     rtc.getTime(rtc_m);
00223     unlockI2C();
00224     t.tm_sec = rtc_m.sec;
00225     t.tm_min = rtc_m.min;
00226     t.tm_hour = rtc_m.hour;
00227     t.tm_mday = rtc_m.date;
00228     t.tm_mon = rtc_m.mon - 1;
00229     t.tm_year = rtc_m.year - 1900;
00230             
00231     //set the mbed's time
00232     time_t ctTime = mktime(&t);
00233     ctTime = ctTime - (TZone + DST) * 3600;     //take out local time
00234     set_time(ctTime);
00235     UpdateTime(); 
00236 }
00237 
00238 //--------------------------------------------------------------------------------------------------------------------------------------//
00239 // Pull the temperature out of the DS3232 RTC
00240 
00241 void Get3232Temp() {
00242     pc.printf("%c", BS);
00243     lockI2C();
00244     if(rtc.startTempCycle(rtc_m) == true) {
00245         unlockI2C();
00246         pc.printf(" - DS3232M start converstion ok \r\n");
00247     } else {
00248         unlockI2C();
00249         pc.printf(" - DS3232M start converstion BUSY!!! \r\n");
00250     }  
00251     //wait for DS3232 temperature conversion to finish
00252     int i = 80;
00253     for(i = 80; i > 0; i--) {
00254 #ifdef RTOS_H
00255         Thread::wait(20);
00256 #else
00257         wait_ms(20);
00258 #endif
00259         lockI2C();
00260         if((rtc.checkTempBusy(rtc_m)) == true) break;
00261         unlockI2C();
00262     }
00263         
00264     //timed out or display temperature
00265     if(i > 0) {
00266         float ds3232tempC = rtc.getTemperature(rtc_m);
00267         unlockI2C();
00268 #if (defined(TARGET_K64F) ||  defined(TARGET_DISCO_F746NG))
00269         pc.printf(" - DS3232M Temperature: %.2fC  %.1fF\r\n", (double)ds3232tempC, (double)ds3232tempC * DEGC_DEGF_FLOAT);
00270 #else
00271         pc.printf(" - DS3232M Temperature: %.2fC  %.1fF\r\n", ds3232tempC, ds3232tempC * DEGC_DEGF_FLOAT);
00272 #endif
00273     } else {
00274         unlockI2C();
00275         pc.printf("*** DS3232M Temperature timeout!!!!\r\n");
00276     }
00277 }
00278 
00279 //--------------------------------------------------------------------------------------------------------------------------------------//
00280 // Checking for characters to execute commands from.  It's a thread if RTOS is used.
00281 
00282 #ifdef RTOS_H
00283 void cli_thread(void const *argument) {
00284     pc.printf(" - Starting CLI RTOS thread\r\n");
00285     while (true) {      //while loop only for RTOS
00286         Thread::wait(73);
00287 #else
00288 void cli_thread() {
00289 #endif
00290         if(pcRxQty != 0) {
00291             pc.printf("\r\n");
00292             if(pcRxBuffer[0] == 'A') rtc.set32KhzOutput(rtc_m, true, false);   //turn on 32KHz output
00293             if(pcRxBuffer[0] == 'a') rtc.set32KhzOutput(rtc_m, false, false);  //turn off 32KHz output
00294             if(pcRxBuffer[0] == 'B') rtc.set1hzOutput(rtc_m, true, false);   //turn on 1Hz output
00295             if(pcRxBuffer[0] == 'b') rtc.set1hzOutput(rtc_m,false, false);  //turn off 1Hz output
00296             if(pcRxBuffer[0] == 'c') {
00297                 allowDisplayTime = true;
00298                 SetRTC();  //change DS3232 time
00299                 allowDisplayTime = false;
00300                 pcRxBuffer[0] = 'c';
00301             }
00302             uint8_t errorValue = 0;
00303             if(pcRxBuffer[0] == 'g') {  //get and display stored data string
00304                 errorValue = rtc.getUserRAM(pcRxBuffer, rtc_m, 128, 124);
00305                 if(errorValue) {
00306                     pc.printf("'Get' user RAM error: %d\r\n", errorValue);
00307                 } else if(pcRxBuffer[0] == NULL) {
00308                     pc.printf("User RAM empty!!\r\n");
00309                 } else {
00310                     //pcRxBuffer[31] = NULL;    //guarantee that the string max length is 32 bytes
00311                     pc.printf("%s\r\n", pcRxBuffer);
00312                 }
00313                 pcRxBuffer[0] = 'g';
00314                 errorValue = 0;
00315             }
00316             if(pcRxBuffer[0] == 's') {  //save data string
00317                 allowDisplayTime = true;
00318                 pc.printf("Enter text string to save: ");
00319                 pcClrLineBuf();
00320                 do {
00321 #ifdef RTOS_H
00322                     Thread::wait(20);
00323 #else
00324                     wait_ms(20);
00325 #endif
00326                 } while((pcRxLine == false) && (pcRxEOB == false));
00327                 lockI2C();
00328                 errorValue = rtc.putUserRAM(pcRxBuffer, rtc_m, 128, pcRxQty + 2);
00329                 unlockI2C();
00330                 if(errorValue) pc.printf("'Put' user RAM error: %d\r\n", errorValue);
00331                 allowDisplayTime = false;
00332                 pcRxBuffer[0] = 's';
00333                 errorValue = 0;
00334             }
00335             if(pcRxBuffer[0] == 't') Get3232Temp();  //display the DS3232's temperature
00336             if(pcRxBuffer[0] == 'z') {  
00337                 lockI2C();
00338                 rtc.LoadRTCRam(rtc_m);
00339                 unlockI2C();
00340                 pc.printf("CRC16 value: 0x%04X\r\n", rtc.calculateCRC16(pcRxBuffer, rtc_m, 0x14, 0xea));
00341             }
00342             if((pcRxBuffer[0] != 'a') && (pcRxBuffer[0] != 'A') && (pcRxBuffer[0] != 'b') 
00343                 && (pcRxBuffer[0] != 'B') && (pcRxBuffer[0] != 'c') && (pcRxBuffer[0] != 'g') 
00344                 && (pcRxBuffer[0] != 's') && (pcRxBuffer[0] != 't') && (pcRxBuffer[0] != 'z')) pc.printf("Entry Error!!\r\n");
00345             pc.printf("\r\n");
00346             pcClrLineBuf();
00347         }
00348 #ifdef RTOS_H
00349     }   //RTOS while loop
00350 #endif
00351 }
00352 
00353 //--------------------------------------------------------------------------------------------------------------------------------------//
00354 
00355 int main() {
00356     pc.baud(230400);
00357     ctTime = time(NULL);
00358     StartTime = ctTime;                     //get time we started up
00359     pc.printf("\r\n\r\nDS3232M demo  Christmas-2014  K. Braun\r\n");
00360     
00361     //check for RTOS operation
00362 #ifdef RTOS_H
00363     pc.printf("RTOS installed...\r\n");
00364 #else
00365     pc.printf("not using RTOS...\r\n");
00366 #endif
00367 
00368     //pc RX character callback interrupt
00369     pc.printf("Initializing Serial Port Rx Interrupt...   \r\n");
00370     pc.attach(&PcRxIRQ, pc.RxIrq);
00371     
00372     pc.printf("Checking the mbed's RTC...\r\n");
00373 #ifdef RTOS_H
00374     Thread::wait(1500);
00375 #else
00376     wait_ms(1500);
00377 #endif
00378 
00379     ctTime = time(NULL);
00380     
00381     //first, see if K64F's RTC already running
00382     if((StartTime == ctTime) || (ctTime <= 1000000000)) {
00383         pc.printf("*** mbed's local RTC is not initialized\r\n");
00384         loadRTC();
00385         StartTime = ctTime;
00386         
00387         //now see if DS3232's clock needs to be set
00388         if(ctTime <= 1000000000) {
00389             pc.printf("*** Local RTC stopped, initializing the RTC.  !!CHECK BATTERY!!\r\n");
00390             pc.printf("*** Note: Time is incorrect, needs to be updated!!!\r\n");
00391             
00392             //set up the DS3232's clock
00393             if(SetRTC() != 0) pc.printf("Entry Error!!");
00394             pcClrLineBuf();
00395         }
00396     } 
00397     
00398     //sync up the mbed's time with the DS3232's time    
00399     loadRTC();
00400     StartTime = ctTime;
00401     pc.printf(" - RTC Start Time:   ");
00402     PrintDateTime();
00403     pc.printf(" - Day of Week: %s\r\n", timebuf_dow);  //day of the week
00404         
00405     //get the DS3232's temperature
00406     Get3232Temp();
00407     
00408 #ifdef RTOS_H
00409     //turn on the rest of the os threads
00410     pc.printf("Initializing os threads...\r\n");
00411     Thread th3(cli_thread, NULL, osPriorityNormal);
00412     Thread::wait(300);
00413 #endif
00414     
00415     int CheckTime = ctTime;
00416     pc.printf("Hit 'A' or 'a' - turn on/off the 32KHz output\r\n");
00417     pc.printf("Hit 'B' or 'b' - turn on/off the 1Hz output (1Hz pin needs pull-up)\r\n");
00418     pc.printf("Hit 'c' - change the date & time\r\n");
00419     pc.printf("Hit 'g' - get data string from DS3232 user RAM\r\n");
00420     pc.printf("Hit 's' - store data string in the DS3232 user RAM\r\n");
00421     pc.printf("Hit 't' - get DS3232's temperature\r\n");
00422     pc.printf("Hit 'z' - get user RAM CRC data\r\n");
00423     pc.printf("Hit '^C' - reboot\r\n");
00424     pc.printf("\r\n");
00425     
00426     //Ready!!
00427     while (true) {
00428 #ifdef RTOS_H
00429         Thread::wait(50);
00430 #else
00431         wait_ms(50);
00432 #endif
00433         UpdateTime();
00434         if(CheckTime != ctTime) {
00435             CheckTime = ctTime;
00436             if(allowDisplayTime == false) PrintDateTime();
00437         }
00438 #ifndef RTOS_H
00439         cli_thread();
00440 #endif      
00441     }
00442 }