
DCF77 atomic clock using 1602 type LCD, sets MCU RTC and goes into Deep Sleep, waking every second to update LCD time. Re acquires DCF time every 24 hours, tests for available signal and indicates DCF pulse width in millisecond's. Time zone can be changed at the beginning of the code. If no signal detected, the program sleeps updating the display with the current RTC time then try's again in 1 hour. The RTC will remain accurate until power is cycled where it will reset the RTC registers. Hard reset will not effect RTC registers. Tested using a project MCU board, MCU Deep Sleep power is 3uA, 1602 LCD is 900uA. Wake up takes around 12mS to update display time every second. The current FRDM board has a PCB track issue that does not allow the power to be monitored.
Dependencies: TextLCD WakeUp mbed
main.cpp
00001 #include "mbed.h" 00002 #include "TextLCD.h" 00003 #include "WakeUp.h" 00004 00005 TextLCD lcd(PTB6, PTA12, PTB5, PTA11, PTB1, PTB2, TextLCD::LCD20x4); // rs, e, d4, d5, d6, d7 00006 InterruptIn dcfSignalIn(PTB0); //DCF signal input,conection of output non-inverting module 00007 00008 // Include the definition for required Time Zone 00009 #define TimeZone 1 //GMT 00010 //#define TimeZine 2 //CET 00011 //#define TimeZone 3 //EET 00012 00013 DigitalOut dcfLED(LED1); 00014 DigitalOut WakeLED(LED3); 00015 00016 //variable 00017 char paritycheck,paritym,parityu,paritydmy; 00018 char testu,testm,testdmy; 00019 char minh,minl; 00020 char hourh,hourl; 00021 char day,dayh,dayl; 00022 char monthh,monthl; 00023 char yearh,yearl; 00024 char summertime; 00025 char buffer[32]; 00026 int interrupt_counter = 0; 00027 int hour = 0; 00028 int minute = 0; 00029 int second = 0; 00030 int dayofweek = 6; 00031 int dayofmonth = 1; 00032 int month = 1; 00033 int year = 0; 00034 int nosignal,signal_error,start,dcf_sec,sync,RTCset,getDCF; 00035 int p_minute,p_hour,p_dayofweek,p_dayofmonth,p_month,p_year; 00036 int dcf_error,error_count,dcf_good,signal_good,ISRlock; 00037 int n,loop; 00038 int dcf_array[61]; 00039 00040 typedef unsigned char byte; 00041 00042 //makro,s 00043 void dcfISR(),dcf_check(),checkSIGNAL(),signal(); 00044 void parity_calc(); 00045 void RTC_reset(),RTC_set(); 00046 void Displayloop(); 00047 void setTIME(); 00048 void restart(); 00049 void dcfIRQ(); 00050 00051 Ticker Ticker50ms; 00052 Timer check; 00053 #define ZERO 1e-10 00054 #define isBetween(A, B, C) (((A-B) > -ZERO) && ((A-C) < ZERO)) 00055 00056 struct status { 00057 bool is_leap; // Leap year flag (NOT actually transmitted but calculated) 00058 bool sample50; // dcf sample at 50mS into the start of the second 00059 bool sample150; // dcf sample at 150mS into the start of the second 00060 int second; // dcf second (NOT actually transmitted but calculated) 00061 } 00062 dcf_status; 00063 00064 struct dcf { 00065 char dut1; // DUT1 (0.1 - 0.8) 00066 char dut2; // DUT2 (-0.1 - -0.8) 00067 char year; // Year (00 - 99) 00068 char month; // Month (01 - 12) 00069 char dayofmonth; // Day of month (01 - 31) 00070 char dayofweek; // Day of week (Sunday=0 Saturday=6) 00071 char hour; // Hour (00 - 23) 00072 char minute; // Minute (00 - 59) 00073 } dcf_time; 00074 00075 struct tm t; 00076 00077 // Various text strings used in display 00078 char weekDayName[7][4] = {"Sun","Mon","Tue","Wed","Thu", "Fri","Sat"}; 00079 char monthName[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 00080 char MAX_DAY[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // Max days in a month for a non-leap year 00081 char leapText[2][4] = {" ", "L"}; 00082 char dstSymbol[2][3] = {"WT", "ST"}; 00083 00084 byte maxDay(byte year, byte month) // Return the maximum day in month for a given month & year 00085 { 00086 byte lastday, leap; 00087 leap = year%4 == 0 && year%100 !=0 || year%400 == 0; 00088 lastday = MAX_DAY[month - 1]; 00089 dcf_status.is_leap = leap > 0 ? 1 : 0; 00090 if ((leap > 0) && (month == 2)) 00091 lastday++; 00092 return lastday; 00093 } 00094 00095 int dayOfWeek(int y, int m, int d) // 0 = Sunday 00096 { 00097 static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; 00098 y -= m < 3; 00099 return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7; 00100 } 00101 00102 int main() 00103 { 00104 lcd.printf("DCF77 clock\n"); 00105 lcd.printf("Checking Signal"); 00106 WakeLED=1;dcfLED=1; 00107 WakeUp::calibrate(); 00108 wait(1); 00109 checkSIGNAL();dcfSignalIn.rise(NULL);lcd.cls(); 00110 if (signal_good==0) { 00111 lcd.printf("No Signal!!\n"); 00112 lcd.printf("Retry in 1 hour"); 00113 wait(2);lcd.cls();n=3600; 00114 getDCF=0; 00115 } 00116 else{ 00117 lcd.printf("DCF detected\n"); 00118 lcd.printf("Setting RTC"); 00119 wait(2);lcd.cls(); 00120 restart();lcd.cls(); 00121 } 00122 00123 while (true){ 00124 00125 while (getDCF==1) { // Get dcf time and set cpu RTC 00126 if (loop==0) { 00127 Displayloop(); // update display every 50mS 00128 loop=1; 00129 } 00130 } 00131 00132 while (getDCF==0) { // Deep Sleep mode, Wake and update display time every second 00133 WakeLED=0; 00134 time_t seconds = time(NULL); 00135 strftime(buffer, 32, "%I:%M:%S %p", localtime(&seconds)); 00136 lcd.locate(0,0);lcd.printf("RTC %s", buffer); 00137 strftime(buffer, 32, "%a %d %b %Y ", localtime(&seconds)); 00138 lcd.locate(0,1);lcd.printf("%s", buffer); 00139 WakeLED=1; 00140 n--;if (n==0) {getDCF=1;} // Restart and Synchronise DCF every 1 or 24 hours 00141 WakeUp::set(1); 00142 deepsleep(); 00143 } 00144 checkSIGNAL();dcfSignalIn.rise(NULL);lcd.cls(); 00145 if (signal_good==1) {restart();} 00146 else {n=3600;getDCF=0;} 00147 } 00148 } 00149 00150 void Displayloop() 00151 { 00152 if (interrupt_counter == 0) { 00153 if (dcf_good == 1 && dcf_sec == 2) { 00154 RTC_set(); // set cpu RTC if good data 00155 } 00156 time_t seconds = time(NULL); 00157 strftime(buffer, 32, "%a %d %H:%M:%S", localtime(&seconds)); 00158 lcd.locate(0,1);lcd.printf("%s", buffer); 00159 } 00160 00161 if (interrupt_counter==3){ 00162 if (start==1){ 00163 dcf_array[dcf_sec]=dcf_status.sample150; 00164 if (dcf_sec==0){ 00165 dcf_array[58] = 0; 00166 } 00167 } 00168 } 00169 00170 if (interrupt_counter==5) { 00171 if (signal_error==1){ 00172 Ticker50ms.detach();dcfSignalIn.rise(NULL);getDCF=0;lcd.cls(); 00173 lcd.printf("10 Signal errors\n"); 00174 lcd.printf("detected,restart"); 00175 wait(2); 00176 lcd.cls();restart();} // Restart DCF ISR if signal 10 errors detected 00177 } 00178 } 00179 00180 void setTIME() // Set time variables with Partity data 00181 { 00182 second = dcf_sec; 00183 minute=p_minute; 00184 hour=p_hour; 00185 dayofweek=p_dayofweek; 00186 dayofmonth=p_dayofmonth; 00187 month=p_month; 00188 year=p_year; 00189 } 00190 00191 void checkSIGNAL() 00192 { 00193 n=10;dcfSignalIn.rise(signal); 00194 while(n>0){ 00195 if (ISRlock==0){ 00196 lcd.locate(0,0); 00197 if (signal_good==1) {lcd.printf ("Signal Good %d ",n);} 00198 else {lcd.printf("No Signal %d ",n);} 00199 signal_good=0; 00200 } 00201 wait(1); 00202 n--; 00203 } 00204 } 00205 void signal() 00206 { 00207 check.start();ISRlock=1,signal_good=1; 00208 while (dcfSignalIn==1){}; 00209 check.stop(); 00210 lcd.locate(0,1);lcd.printf ("DCF pulse %3.f mS",(check.read()*1000)); 00211 check.reset();ISRlock=0; 00212 } 00213 00214 void restart() 00215 { 00216 hour = 0;minute = 0,second = 0,dayofweek = 6;dayofmonth = 1;month = 1;year = 0; 00217 signal_error=0;sync=0;getDCF=1;RTCset=0;error_count=0; 00218 start=0;dcf_sec=0;dcf_good=0; 00219 dcfSignalIn.rise(dcfIRQ); //Trigger dcfISR on rising edge of DCF pulse 00220 while(dcfSignalIn == 1){} 00221 while(dcfSignalIn == 0){} 00222 interrupt_counter = 0;sync=1;dcf_sec=0; 00223 } 00224 00225 void dcfIRQ(void) // DCF Signal Interrupt to synchronise Ticker ISR 00226 { 00227 if (sync==0){ 00228 Ticker50ms.attach(& dcfISR, .05); 00229 interrupt_counter = 0;sync=1;dcf_sec=0; 00230 } 00231 } 00232 00233 void dcfISR() //Interrupt service routine (ISR) that is called every 50ms 00234 { 00235 interrupt_counter++;loop=0; 00236 00237 dcfLED = !dcfSignalIn; // Show dcf Signal state on LED 00238 00239 if (interrupt_counter == 20) { // 50mS x 20 = 1000mS = 1 Second 00240 interrupt_counter = 0; second++; 00241 if (start==1) {dcf_sec++;} 00242 } 00243 lcd.locate(0,0); lcd.printf("%2d:%02d:%02d.%d Dcf%02d",hour,minute,second,interrupt_counter*5/10,dcf_sec); 00244 00245 if (dcf_sec==59) {dcf_check();} 00246 if (dcf_good==1 && dcf_sec==1) {setTIME();} 00247 if (second >= 60) {++minute;second -=60;} 00248 if (minute >= 60) {++hour;minute-=60;} 00249 if (hour >= 24) {hour -=24;++dayofweek;++dayofmonth;} 00250 if (dayofweek > 6) dayofweek = 0; 00251 if (dayofmonth > maxDay(year, month)) {dayofmonth = 1;month++;} 00252 if (month > 12) {month = 1;year++;} 00253 if (year > 99) year = 1; 00254 switch (interrupt_counter) { 00255 case 1:{ // 50mS after start of second pulse 00256 dcf_status.sample50 = (dcfSignalIn); 00257 break;} 00258 case 3: { // 150mS after start of second pulse (bit "1" dcf Data) 00259 dcf_status.sample150 = (dcfSignalIn); 00260 if (!dcf_status.sample150 && !dcf_status.sample50) {sync=0;start=1;} // Reset Ticker ISR to line up with 59th second pulse 00261 break;} 00262 case 6: { // 300mS after start of second (signal error if true) 00263 if (dcfSignalIn) {dcf_error = 1;} 00264 break;} 00265 case 10: { // 500mS after start of second (signal error if true) 00266 if (dcfSignalIn) {dcf_error = 1;} 00267 break;} 00268 case 15: { // 750mS after start of second (signal error if true) 00269 if (dcfSignalIn) {dcf_error = 1;} 00270 break;} 00271 } 00272 if (dcf_error==1) {error_count++;dcf_error=0;} 00273 if (error_count > 9 && sync==1) {error_count = 0;signal_error=1;} 00274 } // End of ISR 00275 00276 void dcf_check() 00277 { 00278 parity_calc(); // Get Parity data and test if correct 00279 paritycheck= testu or testm or testdmy; 00280 if (year>99) paritycheck=1; 00281 if (month>12) paritycheck=1; 00282 if (day>31) paritycheck=1; 00283 if (hour>23) paritycheck=1; 00284 if (minute>59) paritycheck=1; 00285 if (paritycheck) { 00286 dcf_good = 0; 00287 } 00288 else { 00289 dcf_good = 1; 00290 } 00291 } 00292 00293 void RTC_set() // Set cpu RTC to required Time Zone 00294 { 00295 t.tm_sec = (second); // 0-59 00296 t.tm_min = (minute); // 0-59 00297 t.tm_hour = (hour); // 0-23 00298 t.tm_mday = (dayofmonth); // 1-31 00299 t.tm_mon = (month-1); // 0-11 DCF "0" = Jan, -1 added for Mbed RCT clock format 00300 t.tm_year = ((year)+100); // year since 1900, current DCF year + 100 + 1900 = correct year 00301 #if (TimeZone == 1) 00302 set_time (mktime(&t)-3600); // set CPU RTC clock to DCF time zone -3600 for GMT 00303 #elif (TimeZone==2) 00304 set_time (mktime(&t)); // set CPU RTC clock to DCF time zone 00305 #elif (TimeZone==3) 00306 set_time (mktime(&t)+3600); // set CPU RTC clock to DCF time zone +3600 for EET 00307 #endif 00308 RTCset=1;getDCF=0;Ticker50ms.detach();dcfSignalIn.rise(NULL);dcfLED=1;lcd.cls(); 00309 lcd.printf("RTC set, run\n"); 00310 lcd.printf("Deep Sleep Mode"); 00311 n=3600*24; 00312 wait(3); 00313 } 00314 00315 void parity_calc() 00316 { 00317 //calculate summer/winter time---------------------------------------------------------------------- 00318 summertime = dcf_array[17] & 1; 00319 //calculate hour-------------------------------------------------------------------------------------- 00320 hourh = dcf_array[34] * 20 + dcf_array[33] * 10; 00321 hourl = dcf_array[32] * 8 + dcf_array[31] * 4 + dcf_array[30] * 2 + dcf_array[29] * 1; 00322 p_hour = hourh + hourl; 00323 //calculate minutes------------------------------------------------------------------------------------ 00324 minl = dcf_array[24] * 8 + dcf_array[23] * 4 + dcf_array[22] * 2 + dcf_array[21] * 1; 00325 minh = dcf_array[27] * 40 + dcf_array[26] * 20 +dcf_array[25] * 10; 00326 p_minute = minh + minl; 00327 //calculate day of week-------------------------------------------------------------------------------- 00328 p_dayofweek = dcf_array[44] * 4 +dcf_array[43] * 2 + dcf_array[42] * 1; 00329 //calculate day---------------------------------------------------------------------------------------- 00330 dayl = dcf_array[39] * 8 + dcf_array[38] * 4 + dcf_array[37] * 2 + dcf_array[36] * 1; 00331 dayh = dcf_array[41] * 20 + dcf_array[40] * 10; 00332 p_dayofmonth=dayh+dayl; 00333 //calculate month-------------------------------------------------------------------------------------- 00334 monthh = dcf_array[49] * 10; 00335 monthl = dcf_array[48] * 8 + dcf_array[47] * 4 + dcf_array[46] * 2 + dcf_array[45] * 1; 00336 p_month = monthh +monthl; 00337 //calculate year--------------------------------------------------------------------------------------- 00338 yearh = dcf_array[57] * 80 + dcf_array[56] * 40 + dcf_array[55] * 20 + dcf_array[54] * 10; 00339 yearl = dcf_array[53] * 8 +dcf_array[52] * 4 + dcf_array[51] * 2 + dcf_array[50] * 1; 00340 p_year = yearh+yearl; 00341 //calculate parity 00342 paritym = dcf_array[21] + dcf_array[22] + dcf_array[23] + dcf_array[24] + dcf_array[25] + dcf_array[26] +dcf_array[27] +dcf_array [28]; 00343 parityu =dcf_array[29] + dcf_array[30] + dcf_array[31] + dcf_array[32] + dcf_array[33] + dcf_array[34] + dcf_array[35]; 00344 paritydmy =dcf_array[36] + dcf_array [37] + dcf_array [38] + dcf_array [39] + dcf_array[40] + dcf_array[41] + dcf_array [42] + dcf_array [43] + dcf_array[44] + dcf_array [45] + dcf_array[46] + dcf_array [47] + dcf_array[48] + dcf_array[49] + dcf_array[50] + dcf_array[51] + dcf_array [52] + dcf_array[53] + dcf_array[54] + dcf_array[55] + dcf_array[56] + dcf_array[57] + dcf_array[58]; 00345 //test parity------------------------------ 00346 testu=parityu & 1; 00347 testm=paritym & 1; 00348 testdmy=paritydmy & 1; 00349 } 00350
Generated on Fri Jul 22 2022 16:47:22 by
