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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

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