DCF77 Atomic clock using Nokia 6610 colour LCD display. This will continue to run with no signal and shows a graphic bit map display demonstrating the time build. Does not use the Mbed RTC so will run on the LPC11U24. The main signal timing is achieved by using a Ticker ISR that looks at the DCF signal input every 50mS this also produces the seconds on the local clock incase of signal errors or no signal. Many thanks to Lynton Towler for the idea of this part of the code and Wim who helped me convert it from an Arduino program. The Parity code was fromHans program that works.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "MobileLCD.h"
00003 
00004 MobileLCD lcd(p5, p6, p7, p8, p9);
00005 DigitalIn dcfSignalIn(p21);//conection to NON inverting output of dcf module
00006 DigitalOut dcfLED (LED1);//received DCF signal
00007 
00008 //variable
00009 char paritycheck,paritym,parityu,paritydmy;
00010 char testu,testm,testdmy;
00011 char min,minh,minl;
00012 char hourh,hourl;
00013 char w_day;
00014 char day,dayh,dayl;
00015 char monthh,monthl;
00016 char yearh,yearl;
00017 char summertime;
00018 int dcf_array[61];
00019   
00020 //makro,s
00021 void getbit();
00022 void dcf_check();
00023 void lcd_date_print();
00024 void lcd_time_print();
00025 void bit_map_draw();
00026 void bit_print();
00027 void parity_calc();
00028 void reset_rtc();
00029 void local_time();
00030 void set_rtc();
00031 void s_display();
00032 void drawgraph();
00033 
00034 Timer d;
00035 Ticker Ticker10ms;
00036 
00037 #define ZERO 1e-10
00038 #define isBetween(A, B, C) (((A-B) > -ZERO) && ((A-C) < ZERO))
00039 
00040 struct status {
00041     bool is_leap;           // Leap year flag (NOT actually transmitted but calculated)
00042     bool sample50;          // dcf sample at 50mS into the start of the second
00043     bool sample150;         // dcf sample at 150mS into the start of the second
00044     int  second;            // dcf second (NOT actually transmitted but calculated)
00045 } 
00046 dcf_status;
00047 
00048 struct dcf {
00049     char dut1;               // DUT1 (0.1 - 0.8)
00050     char dut2;               // DUT2 (-0.1 - -0.8)
00051     char year;               // Year (00 - 99)
00052     char month;              // Month (01 - 12)
00053     char dayofmonth;         // Day of month (01 - 31)
00054     char dayofweek;          // Day of week (Sunday=0 Saturday=6)
00055     char hour;               // Hour (00 - 23)
00056     char minute;             // Minute (00 - 59)
00057 } dcf_time;
00058 
00059 // Global variables
00060 int in_sec_counter = 0;
00061 int interrupt_counter = 0;
00062 int hour = 12;
00063 int minute = 0;
00064 int second = 0;
00065 int dayofweek = 6;
00066 int dayofmonth = 1;
00067 int month = 1;
00068 int year = 0;
00069 int nosignal;
00070 int start;
00071 int zero_bit;
00072 int dcf_sec;
00073 int s,x,y,r;
00074 int bmd;
00075 int sync;
00076 int p_minute;
00077 int p_hour;
00078 int p_dayofweek;
00079 int p_dayofmonth;
00080 int p_month;
00081 int p_year;
00082 int dcf_error;
00083 int status;
00084 int insecond_counter;
00085 int delay;
00086 int start_delay;
00087 typedef unsigned char byte;
00088 void loop();
00089 void oled_time_print();
00090 void oled_date_print();
00091 void drawgraph();
00092 void bit_map_draw();
00093 void set_time();
00094 void restart();
00095 
00096 // Various text strings used in display
00097 char weekDayName[7][4] = {"Sun","Mon","Tue","Wed","Thu", "Fri","Sat"};
00098 char monthName[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
00099 char statusText[5][17] = {"Waiting Sync    ","Reading dcf data","Checking Parity ","Last Minute Okay","Signal error    "};
00100 char leapText[2][10] = {"    ", "Leap"};
00101 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
00102 
00103 // Return the maximum day in month for a given month & year
00104 
00105 byte maxDay(byte year, byte month)
00106 {
00107     byte lastday, leap;
00108     leap = year%4 == 0 && year%100 !=0 || year%400 == 0;
00109     lastday = MAX_DAY[month - 1];
00110     dcf_status.is_leap = leap > 0 ? 1 : 0;
00111     if ((leap > 0) && (month == 2))
00112         lastday++;
00113     return lastday;
00114 }
00115 
00116 int dayOfWeek(int y, int m, int d)   // 0 = Sunday
00117 {
00118     static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
00119     y -= m < 3;
00120     return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
00121 }
00122 
00123 void myISR()  //This is the interrupt service routine (ISR) that is called every 50ms 
00124 {   
00125     interrupt_counter++;
00126      
00127     dcfLED = dcfSignalIn;  // Show dcfSignal state on LED
00128      
00129     if (interrupt_counter == 20) { // 50mS x 20 = 1000mS = 1 Second
00130         interrupt_counter = 0;
00131         second++;insecond_counter++;
00132         if (d.read()> 2) {d.reset();d.start();delay=1;}
00133         else {delay=0;}
00134         if (second > 2) {start_delay=0;}
00135         if (dcf_error==1) {status = 4;} 
00136        }
00137         if (dcf_sec==58) {status = 2;}
00138         if (dcf_sec==59) {dcf_check();}
00139         if (status == 3 && dcf_sec == 1) {set_time();}
00140            
00141     if (second >= 60) {
00142         ++minute;
00143         second -=60;
00144     }
00145     if (minute >= 60) {
00146         ++hour;
00147         minute-=60;
00148     }
00149     if (hour >= 24) {
00150         hour -=24;
00151         ++dayofweek;
00152         ++dayofmonth;
00153     }
00154     if (dayofweek > 6)
00155         dayofweek = 0;
00156 
00157     if (dayofmonth > maxDay(year, month)) {
00158         dayofmonth = 1;
00159         month++;
00160     }
00161     if (month > 12) {
00162         month = 1;
00163         year++;
00164     }
00165     if (year > 99)
00166         year = 1;
00167            
00168         switch (interrupt_counter) {          
00169             case 1:{  // 50mS after start of second pulse
00170                 dcf_status.sample50 = (dcfSignalIn);
00171                break;}
00172             case 3: { // 150mS after start of second pulse (bit "1" dcf Data)
00173                 dcf_status.sample150 = (dcfSignalIn);                
00174                  if (!dcf_status.sample150 && !dcf_status.sample50 && start_delay==0) {zero_bit=1;sync=0;insecond_counter=0;start=1;}
00175                  else {zero_bit=0;}
00176                break;}
00177             case 6: { // 300mS after start of second (signal error if true)
00178                  if (dcfSignalIn) {dcf_error = 1;}
00179                break;}                
00180             case 10: { // 500mS after start of second (signal error if true)
00181                 if (dcfSignalIn) {dcf_error = 1;}
00182                break;}
00183             case 12: { // 600mS after start of second (signal error if true)
00184                 if (dcfSignalIn) {dcf_error = 1;}
00185                break;}                                                   
00186           }           
00187         if (interrupt_counter==1)
00188            {
00189             if (dcfSignalIn){nosignal=1;}
00190             else nosignal++;              
00191             if (nosignal>5){nosignal=2; status = 0; restart();} 
00192             if (dcf_error == 1 && delay == 1) {dcf_error = 0; status = 0;restart();}                      
00193            }           
00194         if (interrupt_counter==3)
00195            {
00196              lcd.locate(0,4); lcd.foreground (CYAN);
00197              lcd.printf("Bit %d   ",dcf_status.sample150);           
00198              if (start==0) {lcd.foreground (RED);lcd.printf("No Sync ");}             
00199            if (start==1)
00200             {
00201                 dcf_array[dcf_sec]=dcf_status.sample150;
00202                 lcd.foreground (GREEN);
00203                 lcd.printf("In Sync ");  
00204                     if (insecond_counter==1)
00205                     {
00206                         dcf_sec=0;x=0;y=5;dcf_array[58] = 0; bmd=0;        
00207                          if (r == 1){r=0;}
00208                             else {r=1;}
00209                         }        
00210             if (dcf_sec > 2) {status = 1;}                 
00211             if (dcf_sec > 20 && dcf_sec < 59 ) {bit_print();}
00212             if (dcf_sec > 60) {dcf_error = 1;bit_map_draw();status = 4;dcf_sec=0;dcf_error = 0;}  
00213             if (sync==1) {dcf_sec++;}                     
00214                 }     
00215              }             
00216       if (sync==0 ) {
00217             if (dcfSignalIn) {interrupt_counter =0 ;sync=1;}                
00218         }                
00219 } // End of ISR
00220 
00221 int main()
00222 {     
00223     lcd.locate (1,2);
00224     lcd.foreground (WHITE);
00225     lcd.printf("DCF77 Clock");
00226     lcd.locate (1,4);
00227     lcd.printf("Nokia 6610 LCD");
00228     lcd.locate (1,6);
00229     lcd.printf("Signal pin 21");
00230     wait (5);lcd.cls();r = 1;             
00231     bit_map_draw();dcf_sec=0;bmd=1;start=0;zero_bit=0;
00232     status = 0; start_delay=1;
00233     d.start();  
00234     if (dcfSignalIn) {interrupt_counter =0 ;sync=1;}                    
00235     Ticker10ms.attach(& myISR, .05 ); //Setup Ticker to call myISR every 50 ms
00236             
00237   while (true) {
00238     loop();                           // Continuously get dcf time and Display data interrupted by the Ticker every 50ms
00239    }    
00240 }
00241 
00242 void dcf_check()
00243 { 
00244         parity_calc();
00245         paritycheck= testu or testm or testdmy;        
00246         if (year>99) paritycheck=1;
00247         if (month>12) paritycheck=1;
00248         if (day>31) paritycheck=1;
00249         if (hour>23) paritycheck=1;
00250         if (min>59) paritycheck=1;       
00251         if (paritycheck) {        
00252         status = 4;       
00253         }
00254      else {
00255             status = 3;
00256         }       
00257 }
00258 void showClock()
00259 {
00260    lcd.locate(0,0);lcd.foreground (WHITE);
00261    lcd.printf("%02d:%02d:%02d", hour, minute, second);
00262    lcd.locate(0,1);
00263    lcd.printf("%s %02d %s'20%02d", weekDayName[dayofweek], dayofmonth, monthName[month-1], year);
00264    lcd.locate(0,2);
00265    if (summertime) {lcd.foreground (RED);lcd.printf("Summer Time ");}
00266    else {lcd.foreground (BLUE);lcd.printf("Winter Time ");}
00267    lcd.foreground (RED);lcd.printf("%s",leapText[dcf_status.is_leap]);
00268    if (status==0) {lcd.foreground (WHITE);}
00269    if (status==1) {lcd.foreground (CYAN);}
00270    if (status==2) {lcd.foreground (BLUE);}
00271    if (status==3) {lcd.foreground (GREEN);}
00272    if (status==4) {lcd.foreground (RED);}
00273    lcd.locate(0,15);
00274    lcd.printf(statusText[status]);
00275 }
00276 
00277 void bit_print()
00278 {
00279     if (r==1) {lcd.foreground (MAGENTA);}    // alternate bit draw colour
00280     else {lcd.foreground (WHITE);}
00281     lcd.locate(x+3,(y+1));
00282     lcd.printf("%d",dcf_status.sample150);
00283     (y)++;
00284     if ((dcf_sec)==27){(y)=13;}   
00285     if ((dcf_sec)==28){(y)=5;(x)=(x)+2;lcd.printf("          ");}     
00286     if ((dcf_sec)==34){(y)=13;}       
00287     if ((dcf_sec)==35){(y)=5;(x)=(x)+2;}
00288     if ((dcf_sec)==41){(y)=5;(x)=(x)+2;}
00289     if ((dcf_sec)==44){(y)=5;(x)=(x)+2;}
00290     if ((dcf_sec)==49){(y)=5;(x)=(x)+2;}              
00291 }
00292 
00293 void bit_map_draw()
00294 {
00295     lcd.foreground (YELLOW);(x)=0,(y)=5;
00296     lcd.locate(x,y);lcd.printf("   M H D d M Y"); 
00297     lcd.locate(x,y+1);lcd.printf(" 1 i o a a o e");
00298     lcd.locate(x,y+2);lcd.printf(" 2 n u t y n a"); 
00299     lcd.locate(x,y+3);lcd.printf(" 4 u r e   t r");
00300     lcd.locate(x,y+4);lcd.printf(" 8 t       h  "); 
00301     lcd.locate(x,y+5);lcd.printf("10 e          ");
00302     lcd.locate(x,y+6);lcd.printf("20            ");
00303     lcd.locate(x,y+7);lcd.printf("40            ");
00304     lcd.locate(x,y+8);lcd.printf("80            "); 
00305     lcd.locate(x,y+9);lcd.printf(" P arity      "); 
00306 }
00307 
00308 void loop()
00309 {   
00310     if (interrupt_counter == 0) {
00311     showClock();   
00312     lcd.locate(10,12);lcd.foreground (WHITE);lcd.printf("%02d",dcf_sec);
00313     } 
00314   }
00315   
00316 void set_time()
00317 {
00318             second = dcf_sec;
00319             minute=p_minute;
00320             hour=p_hour;
00321             dayofweek=p_dayofweek;
00322             dayofmonth=p_dayofmonth;
00323             month=p_month;
00324             year=p_year;
00325 }
00326 
00327 void restart()
00328 {
00329 start=0;s=0;x=0;y=5;dcf_sec=0;dcf_error=0;
00330 insecond_counter=0;zero_bit=0;start_delay=1;
00331 }
00332 
00333 void parity_calc()
00334 {
00335 //calculate summer/winter time----------------------------------------------------------------------
00336     summertime = dcf_array[17] & 1;
00337 //calculate hour--------------------------------------------------------------------------------------
00338     hourh = dcf_array[34] * 20 + dcf_array[33] * 10;
00339     hourl = dcf_array[32] * 8 + dcf_array[31] * 4 + dcf_array[30] * 2 + dcf_array[29] * 1;
00340     p_hour = hourh + hourl;
00341 //calculate minutes------------------------------------------------------------------------------------
00342     minl = dcf_array[24] * 8 + dcf_array[23] * 4 + dcf_array[22] * 2 + dcf_array[21] * 1;
00343     minh = dcf_array[27] * 40 + dcf_array[26] * 20 +dcf_array[25] * 10;
00344     p_minute = minh + minl;
00345 //calculate day of week--------------------------------------------------------------------------------
00346     p_dayofweek = dcf_array[44] * 4 +dcf_array[43] * 2 + dcf_array[42] * 1;
00347 //calculate day----------------------------------------------------------------------------------------
00348     dayl = dcf_array[39] * 8 + dcf_array[38] * 4 + dcf_array[37] * 2 + dcf_array[36] * 1;
00349     dayh = dcf_array[41] * 20 + dcf_array[40] * 10;
00350     p_dayofmonth=dayh+dayl;
00351 //calculate month--------------------------------------------------------------------------------------
00352     monthh = dcf_array[49] * 10;
00353     monthl = dcf_array[48] * 8 + dcf_array[47] * 4 + dcf_array[46] * 2 + dcf_array[45] * 1;
00354     p_month = monthh +monthl;
00355 //calculate year---------------------------------------------------------------------------------------
00356     yearh = dcf_array[57] * 80 + dcf_array[56] * 40 + dcf_array[55] * 20 + dcf_array[54] * 10;
00357     yearl = dcf_array[53] * 8 +dcf_array[52] * 4 + dcf_array[51] * 2 + dcf_array[50] * 1;
00358     p_year = yearh+yearl;
00359 //calculate parity
00360     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];
00361     parityu =dcf_array[29] + dcf_array[30] + dcf_array[31] + dcf_array[32] + dcf_array[33] + dcf_array[34] + dcf_array[35];
00362     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];
00363 //test parity------------------------------
00364     testu=parityu & 1;
00365     testm=paritym & 1;
00366     testdmy=paritydmy & 1;
00367   }
00368