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.
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
Generated on Thu Jul 28 2022 11:07:56 by 1.7.2