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
main.cpp
- Committer:
- loopsva
- Date:
- 2016-03-11
- Revision:
- 4:df12939cba66
- Parent:
- 3:f0eb506d4add
File content as of revision 4:df12939cba66:
#include "mbed.h" #include "rtos.h" //mbed rtos - uncomment to make RTOS available #include "ds3232m.h" //Maxim RTC #ifdef RTOS_H Mutex MutexI2cWait_1; //lock/unlock I2C requests RawSerial pc(USBTX, USBRX); //console interface for RTOS #else Serial pc(USBTX, USBRX); //console interface #endif //RTOS_H #define SDA0 D14 //assuming arduino pins #define SCL0 D15 ds3232m rtc(SDA0, SCL0, 400000); //Maxim real time clock //--------------------------------------------------------------------------------------------------------------------------------------// // Time variables time_t ctTime; //time structure int DST = 1; //Daylight Saving Time (or as defined in .ini file) int TZone = -8; //Time Zone from UTC (or as defined in .ini file) char timebuf_hms[10]; //local time format buffer - 21:16:43 char timebuf_dMyy[14]; //local time format buffer - 01-Apr-2014 char timebuf_dow[1]; //local time format buffer - 5 int StartTime = 0; //time we powered up bool allowDisplayTime = false; //used to stop displaying date/time when entering data from the console //--------------------------------------------------------------------------------------------------------------------------------------// //Variables for USB Serial Port RX uint32_t pcRxQty = 0; //RX data counter/pointer char pcRxBuffer[128]; //RX data buffer bool pcRxLine = false; //CR or LF detected (end of line) bool pcRxEOB = false; //RX buffer is full!!! cannot accept any more characters char inchar = 0; //RX input character //--------------------------------------------------------------------------------------------------------------------------------------// // various Mutex lock/unlock definitions void lockI2C() { #ifdef RTOS_H MutexI2cWait_1.lock(); #endif //RTOS_H } void unlockI2C() { #ifdef RTOS_H MutexI2cWait_1.unlock(); #endif //RTOS_H } //--------------------------------------------------------------------------------------------------------------------------------------// // This function is called when a character goes into the RX buffer. #define DOUPONELINE "\033[1A" #define BS 0x08 //ascii backspace #define CR 0x0d //ascii CR #define LF 0x0a //ascii LF #define ticC 0x03 //ascii control C #define DEGC_DEGF_FLOAT 9.0 / 5.0 + 32.0 void PcRxChar(char inchar) { 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 if(inchar == LF) pc.printf(" %c %c", BS, BS); if(inchar == BS) { if(pcRxQty == 0) { pcRxBuffer[pcRxQty] = 0; } else { pc.printf("%c %c", BS, BS); pcRxQty--; pcRxBuffer[pcRxQty] = 0; } } else if((inchar == CR) || (inchar == LF)) { pcRxLine = true; pc.printf("\r\n"); } else if(inchar == ticC) { NVIC_SystemReset(); } else { if(pcRxQty < (sizeof(pcRxBuffer) - 2)) { pcRxBuffer[pcRxQty] = inchar; pcRxQty++; pcRxBuffer[pcRxQty] = 0; pc.printf("%c", pcRxBuffer[pcRxQty - 1]); } else { pc.printf ("\r\n*** pcRxBuffer is full!!\r\n"); pcRxEOB = true; } } } //--------------------------------------------------------------------------------------------------------------------------------------// // Read received chars from USB UART interrupt void PcRxIRQ(void){ /* #if defined(TARGET_KL25Z) NVIC_DisableIRQ(UART0_IRQn); // n=0, 1 or 2 Disable Rx interrupt on kl25z #endif #if defined(TARGET_K64F) NVIC_DisableIRQ(UART0_RX_TX_IRQn); // n=0, 1 or 2 Disable Rx interrupt on k64f #endif #if defined(TARGET_LPC1768) LPC_UART0->IER = 0; //Disable Rx interrupt on mbed1768 #endif */ while (pc.readable()) { inchar = pc.getc(); //read data from USB PcRxChar(inchar); //go process char } /* #if defined(TARGET_KL25Z) NVIC_EnableIRQ(UART0_IRQn); // n=0, 1 or 2 Re-enable Rx interrupt on kl25z #endif #if defined(TARGET_K64F) NVIC_EnableIRQ(UART0_RX_TX_IRQn); // n=0, 1 or 2 Re-enable Rx interrupt on k64f #endif #if defined(TARGET_LPC1768) LPC_UART0->IER = 1; //RE-enable Rx interrupt on mbed1768 #endif */ } //--------------------------------------------------------------------------------------------------------------------------------------// //clear RxData buffer with all 00's and clear flags void pcClrLineBuf() { pcRxQty = 0; // data counter/pointer for(int i = 0; i < (sizeof(pcRxBuffer) - 1); i++) pcRxBuffer[i] = 0; // clear out rx buffer pcRxLine = false; pcRxEOB = false; } //--------------------------------------------------------------------------------------------------------------------------------------// // Update time display values void UpdateTimeRegs() { strftime(timebuf_dMyy, 14, "%d-%b-%Y", localtime(&ctTime)); strftime(timebuf_hms, 10, "%H:%M:%S", localtime(&ctTime)); strftime(timebuf_dow, 1, "%u", localtime(&ctTime)); } void UpdateTime() { ctTime = time(NULL) + ((TZone + DST) * 3600); //timezone and dst offsets UpdateTimeRegs(); } //--------------------------------------------------------------------------------------------------------------------------------------// // display current local date and time void PrintDateTime() { pc.printf("%sDate: %s ", DOUPONELINE, timebuf_dMyy); pc.printf("Time: %s \r\n", timebuf_hms); } //--------------------------------------------------------------------------------------------------------------------------------------// //Manually set the date and time ds3232m::Time_rtc rtc_m = {}; struct tm t; bool SetRTC() { pc.printf("Enter current date and time:\n"); pc.printf("MM DD YY HH MM SS[enter]\n"); pcClrLineBuf(); //wait for string above do{ #ifdef RTOS_H Thread::wait(10); #else wait_ms(10); #endif } while((pcRxLine == false) && (pcRxEOB == false)); //load up the time structure t.tm_year = (2000 + ((pcRxBuffer[6] - '0') * 10) + pcRxBuffer[7] - '0'); t.tm_mon = (((pcRxBuffer[0] - '0') * 10) + pcRxBuffer[1] - '0'); t.tm_mday = (((pcRxBuffer[3] - '0') * 10) + pcRxBuffer[4] - '0'); t.tm_hour = (((pcRxBuffer[9] - '0') * 10) + pcRxBuffer[10] - '0'); t.tm_min = (((pcRxBuffer[12] - '0') * 10) + pcRxBuffer[13] - '0'); t.tm_sec = (((pcRxBuffer[15] - '0') * 10) + pcRxBuffer[16] - '0'); //adjust for tm structure required values t.tm_year = t.tm_year - 1900; t.tm_mon = t.tm_mon - 1; t.tm_wday = t.tm_wday & 7; //if error exists, exit without changing time if(t.tm_year < 113) return(32); if(t.tm_mon > 12) return(16); if(t.tm_mday > 31) return(8); if(t.tm_hour > 23) return(4); if(t.tm_min > 59) return(2); if(t.tm_sec > 59) return(1); //set up the DS3232's RTC rtc_m.sec = t.tm_sec; rtc_m.min = t.tm_min; rtc_m.hour = t.tm_hour; rtc_m.wday = t.tm_wday; rtc_m.date = t.tm_mday; rtc_m.mon = t.tm_mon + 1; rtc_m.year = t.tm_year + 1900; rtc.setTime(rtc_m); //(time structure) //set the mbed's time time_t ctTime = mktime(&t); //reset system up time since it will be out of whack once the time is updated StartTime = ctTime; //have to change sysuptime now ctTime = ctTime - (TZone + DST) * 3600; //take out local time set_time(ctTime); UpdateTime(); return(0); } //--------------------------------------------------------------------------------------------------------------------------------------// // Load the local mbed-RTC from that external DS3232 RTC void loadRTC() { lockI2C(); //get data from DS3232 rtc.getTime(rtc_m); unlockI2C(); t.tm_sec = rtc_m.sec; t.tm_min = rtc_m.min; t.tm_hour = rtc_m.hour; t.tm_mday = rtc_m.date; t.tm_mon = rtc_m.mon - 1; t.tm_year = rtc_m.year - 1900; //set the mbed's time time_t ctTime = mktime(&t); ctTime = ctTime - (TZone + DST) * 3600; //take out local time set_time(ctTime); UpdateTime(); } //--------------------------------------------------------------------------------------------------------------------------------------// // Pull the temperature out of the DS3232 RTC void Get3232Temp() { pc.printf("%c", BS); lockI2C(); if(rtc.startTempCycle(rtc_m) == true) { unlockI2C(); pc.printf(" - DS3232M start converstion ok \r\n"); } else { unlockI2C(); pc.printf(" - DS3232M start converstion BUSY!!! \r\n"); } //wait for DS3232 temperature conversion to finish int i = 80; for(i = 80; i > 0; i--) { #ifdef RTOS_H Thread::wait(20); #else wait_ms(20); #endif lockI2C(); if((rtc.checkTempBusy(rtc_m)) == true) break; unlockI2C(); } //timed out or display temperature if(i > 0) { float ds3232tempC = rtc.getTemperature(rtc_m); unlockI2C(); #if (defined(TARGET_K64F) || defined(TARGET_DISCO_F746NG)) pc.printf(" - DS3232M Temperature: %.2fC %.1fF\r\n", (double)ds3232tempC, (double)ds3232tempC * DEGC_DEGF_FLOAT); #else pc.printf(" - DS3232M Temperature: %.2fC %.1fF\r\n", ds3232tempC, ds3232tempC * DEGC_DEGF_FLOAT); #endif } else { unlockI2C(); pc.printf("*** DS3232M Temperature timeout!!!!\r\n"); } } //--------------------------------------------------------------------------------------------------------------------------------------// // Checking for characters to execute commands from. It's a thread if RTOS is used. #ifdef RTOS_H void cli_thread(void const *argument) { pc.printf(" - Starting CLI RTOS thread\r\n"); while (true) { //while loop only for RTOS Thread::wait(73); #else void cli_thread() { #endif if(pcRxQty != 0) { pc.printf("\r\n"); if(pcRxBuffer[0] == 'A') rtc.set32KhzOutput(rtc_m, true, false); //turn on 32KHz output if(pcRxBuffer[0] == 'a') rtc.set32KhzOutput(rtc_m, false, false); //turn off 32KHz output if(pcRxBuffer[0] == 'B') rtc.set1hzOutput(rtc_m, true, false); //turn on 1Hz output if(pcRxBuffer[0] == 'b') rtc.set1hzOutput(rtc_m,false, false); //turn off 1Hz output if(pcRxBuffer[0] == 'c') { allowDisplayTime = true; SetRTC(); //change DS3232 time allowDisplayTime = false; pcRxBuffer[0] = 'c'; } uint8_t errorValue = 0; if(pcRxBuffer[0] == 'g') { //get and display stored data string errorValue = rtc.getUserRAM(pcRxBuffer, rtc_m, 128, 124); if(errorValue) { pc.printf("'Get' user RAM error: %d\r\n", errorValue); } else if(pcRxBuffer[0] == NULL) { pc.printf("User RAM empty!!\r\n"); } else { //pcRxBuffer[31] = NULL; //guarantee that the string max length is 32 bytes pc.printf("%s\r\n", pcRxBuffer); } pcRxBuffer[0] = 'g'; errorValue = 0; } if(pcRxBuffer[0] == 's') { //save data string allowDisplayTime = true; pc.printf("Enter text string to save: "); pcClrLineBuf(); do { #ifdef RTOS_H Thread::wait(20); #else wait_ms(20); #endif } while((pcRxLine == false) && (pcRxEOB == false)); lockI2C(); errorValue = rtc.putUserRAM(pcRxBuffer, rtc_m, 128, pcRxQty + 2); unlockI2C(); if(errorValue) pc.printf("'Put' user RAM error: %d\r\n", errorValue); allowDisplayTime = false; pcRxBuffer[0] = 's'; errorValue = 0; } if(pcRxBuffer[0] == 't') Get3232Temp(); //display the DS3232's temperature if(pcRxBuffer[0] == 'z') { lockI2C(); rtc.LoadRTCRam(rtc_m); unlockI2C(); pc.printf("CRC16 value: 0x%04X\r\n", rtc.calculateCRC16(pcRxBuffer, rtc_m, 0x14, 0xea)); } if((pcRxBuffer[0] != 'a') && (pcRxBuffer[0] != 'A') && (pcRxBuffer[0] != 'b') && (pcRxBuffer[0] != 'B') && (pcRxBuffer[0] != 'c') && (pcRxBuffer[0] != 'g') && (pcRxBuffer[0] != 's') && (pcRxBuffer[0] != 't') && (pcRxBuffer[0] != 'z')) pc.printf("Entry Error!!\r\n"); pc.printf("\r\n"); pcClrLineBuf(); } #ifdef RTOS_H } //RTOS while loop #endif } //--------------------------------------------------------------------------------------------------------------------------------------// int main() { pc.baud(230400); ctTime = time(NULL); StartTime = ctTime; //get time we started up pc.printf("\r\n\r\nDS3232M demo Christmas-2014 K. Braun\r\n"); //check for RTOS operation #ifdef RTOS_H pc.printf("RTOS installed...\r\n"); #else pc.printf("not using RTOS...\r\n"); #endif //pc RX character callback interrupt pc.printf("Initializing Serial Port Rx Interrupt... \r\n"); pc.attach(&PcRxIRQ, pc.RxIrq); pc.printf("Checking the mbed's RTC...\r\n"); #ifdef RTOS_H Thread::wait(1500); #else wait_ms(1500); #endif ctTime = time(NULL); //first, see if K64F's RTC already running if((StartTime == ctTime) || (ctTime <= 1000000000)) { pc.printf("*** mbed's local RTC is not initialized\r\n"); loadRTC(); StartTime = ctTime; //now see if DS3232's clock needs to be set if(ctTime <= 1000000000) { pc.printf("*** Local RTC stopped, initializing the RTC. !!CHECK BATTERY!!\r\n"); pc.printf("*** Note: Time is incorrect, needs to be updated!!!\r\n"); //set up the DS3232's clock if(SetRTC() != 0) pc.printf("Entry Error!!"); pcClrLineBuf(); } } //sync up the mbed's time with the DS3232's time loadRTC(); StartTime = ctTime; pc.printf(" - RTC Start Time: "); PrintDateTime(); pc.printf(" - Day of Week: %s\r\n", timebuf_dow); //day of the week //get the DS3232's temperature Get3232Temp(); #ifdef RTOS_H //turn on the rest of the os threads pc.printf("Initializing os threads...\r\n"); Thread th3(cli_thread, NULL, osPriorityNormal); Thread::wait(300); #endif int CheckTime = ctTime; pc.printf("Hit 'A' or 'a' - turn on/off the 32KHz output\r\n"); pc.printf("Hit 'B' or 'b' - turn on/off the 1Hz output (1Hz pin needs pull-up)\r\n"); pc.printf("Hit 'c' - change the date & time\r\n"); pc.printf("Hit 'g' - get data string from DS3232 user RAM\r\n"); pc.printf("Hit 's' - store data string in the DS3232 user RAM\r\n"); pc.printf("Hit 't' - get DS3232's temperature\r\n"); pc.printf("Hit 'z' - get user RAM CRC data\r\n"); pc.printf("Hit '^C' - reboot\r\n"); pc.printf("\r\n"); //Ready!! while (true) { #ifdef RTOS_H Thread::wait(50); #else wait_ms(50); #endif UpdateTime(); if(CheckTime != ctTime) { CheckTime = ctTime; if(allowDisplayTime == false) PrintDateTime(); } #ifndef RTOS_H cli_thread(); #endif } }