firmware/main.c

Go to the documentation of this file.
00001 
00010 #include <avr/io.h>
00011 #include <avr/interrupt.h>
00012 #include <avr/pgmspace.h>
00013 #include <util/delay.h>
00014 
00015 #include "saa1064.h"
00016 #include "dcftime.h"
00017 
00018 uint8_t byte[4] = { 2, 3, 1, 0 }; 
00019 uint8_t output[4]; 
00020 uint8_t outputOld[4]; 
00023 enum modes {
00024     timeasbinary, 
00025     dateasbinary, 
00026     timeasbcdhorizontal, 
00027     dateasbcdhorizontal, 
00028     timeasbcdvertical, 
00029     dateasbcdvertical, 
00030     timestamp 
00031 };
00033 enum modes mode;
00034 
00036 uint8_t demomode = 0;
00037 
00038 
00042 void setLeds(void) {
00043     uint8_t i;
00044     for (i = 0; i < 4; i++) {
00045         if (output[i] != outputOld[i]) {
00046             set_led_digit(byte[i], output[i]);
00047             outputOld[i] = output[i];
00048         }
00049     }
00050 } // function setLeds
00051 
00056 void setOutput(dcf_datetime datetime) {
00057     uint8_t bcdlow, bcdhigh; /* takes the low and high parts when converting to BCD */
00058     const uint32_t TS01012000 = 946681200UL; /* The UNIX-Timestamp of 1.1.2000 */
00059     const uint16_t monthstarts[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; /* On which day does a new month start in non-leap-years */
00060     const uint32_t SECONDSINADAY = (60UL * 60 * 24); /* Number of seconds in a day */
00061     uint32_t ts; /* takes the UNIX-Timestamp */
00062 
00063     switch (mode) {
00064         case timeasbinary:
00065             /* hour, minute and second are displayed in rows */
00066             output[0] = datetime.time.hour;
00067             output[1] = datetime.time.minute;
00068             output[2] = datetime.time.second;
00069             output[3] = 0;
00070             break;
00071         case dateasbinary:
00072             /* day of month, month, year and day of week (starting with monday
00073              * = 1) are displayed in rows */
00074             output[0] = datetime.date.dayofmonth;
00075             output[1] = datetime.date.month;
00076             output[2] = datetime.date.year;
00077             output[3] = datetime.date.dayofweek;
00078             break;
00079         case timeasbcdhorizontal:
00080             /* the time is converted to BCD, the digits are displayed by two in
00081              * a row */
00082             bcdlow  = datetime.time.hour % 10;
00083             bcdhigh = datetime.time.hour / 10;
00084             output[0] = (bcdhigh << 4) | bcdlow;
00085             bcdlow  = datetime.time.minute % 10;
00086             bcdhigh = datetime.time.minute / 10;
00087             output[1] = (bcdhigh << 4) | bcdlow;
00088             bcdlow  = datetime.time.second % 10;
00089             bcdhigh = datetime.time.second / 10;
00090             output[2] = (bcdhigh << 4) | bcdlow;
00091             output[3] = 0;
00092             break;
00093         case dateasbcdhorizontal:
00094             /* the date is converted to BCD, the digits are displayed by two in
00095              * a row */
00096             bcdlow  = datetime.date.dayofmonth % 10;
00097             bcdhigh = datetime.date.dayofmonth / 10;
00098             output[0] = (bcdhigh << 4) | bcdlow;
00099             bcdlow  = datetime.date.month % 10;
00100             bcdhigh = datetime.date.month / 10;
00101             output[1] = (bcdhigh << 4) | bcdlow;
00102             bcdlow  = datetime.date.year % 10;
00103             bcdhigh = datetime.date.year / 10;
00104             output[2] = (bcdhigh << 4) | bcdlow;
00105             bcdlow  = datetime.date.dayofweek;
00106             bcdhigh = 0;
00107             output[3] = (bcdhigh << 4) | bcdlow;
00108             break;
00109         case timeasbcdvertical:
00110             /* the time is converted to BCD, the digits are displayed in
00111              * columns */
00112             output[0] = 0;
00113             output[1] = 0;
00114             output[2] = 0;
00115             output[3] = 0;
00116             bcdlow  = datetime.time.hour % 10;
00117             bcdhigh = datetime.time.hour / 10;
00118             output[0] |= ((bcdhigh & 8) << 4) | ((bcdlow & 8) << 3);
00119             output[1] |= ((bcdhigh & 4) << 5) | ((bcdlow & 4) << 4);
00120             output[2] |= ((bcdhigh & 2) << 6) | ((bcdlow & 2) << 5);
00121             output[3] |= ((bcdhigh & 1) << 7) | ((bcdlow & 1) << 6);
00122             bcdlow  = datetime.time.minute % 10;
00123             bcdhigh = datetime.time.minute / 10;
00124             output[0] |= ((bcdhigh & 8) << 1) | ((bcdlow & 8) << 0);
00125             output[1] |= ((bcdhigh & 4) << 2) | ((bcdlow & 4) << 1);
00126             output[2] |= ((bcdhigh & 2) << 3) | ((bcdlow & 2) << 2);
00127             output[3] |= ((bcdhigh & 1) << 4) | ((bcdlow & 1) << 3);
00128             bcdlow  = datetime.time.second % 10;
00129             bcdhigh = datetime.time.second / 10;
00130             output[0] |= ((bcdhigh & 8) >> 2) | ((bcdlow & 8) >> 3);
00131             output[1] |= ((bcdhigh & 4) >> 1) | ((bcdlow & 4) >> 2);
00132             output[2] |= ((bcdhigh & 2) << 0) | ((bcdlow & 2) >> 1);
00133             output[3] |= ((bcdhigh & 1) << 1) | ((bcdlow & 1) << 0);
00134             break;
00135         case dateasbcdvertical:
00136             /* the date is converted to BCD, the digits are displayed in
00137              * columns */
00138             output[0] = 0;
00139             output[1] = 0;
00140             output[2] = 0;
00141             output[3] = 0;
00142             bcdlow  = datetime.date.dayofmonth % 10;
00143             bcdhigh = datetime.date.dayofmonth / 10;
00144             output[0] |= ((bcdhigh & 8) << 4) | ((bcdlow & 8) << 3);
00145             output[1] |= ((bcdhigh & 4) << 5) | ((bcdlow & 4) << 4);
00146             output[2] |= ((bcdhigh & 2) << 6) | ((bcdlow & 2) << 5);
00147             output[3] |= ((bcdhigh & 1) << 7) | ((bcdlow & 1) << 6);
00148             bcdlow  = datetime.date.month % 10;
00149             bcdhigh = datetime.date.month / 10;
00150             output[0] |= ((bcdhigh & 8) << 1) | ((bcdlow & 8) << 0);
00151             output[1] |= ((bcdhigh & 4) << 2) | ((bcdlow & 4) << 1);
00152             output[2] |= ((bcdhigh & 2) << 3) | ((bcdlow & 2) << 2);
00153             output[3] |= ((bcdhigh & 1) << 4) | ((bcdlow & 1) << 3);
00154             bcdlow  = datetime.date.year % 10;
00155             bcdhigh = datetime.date.year / 10;
00156             output[0] |= ((bcdhigh & 8) >> 2) | ((bcdlow & 8) >> 3);
00157             output[1] |= ((bcdhigh & 4) >> 1) | ((bcdlow & 4) >> 2);
00158             output[2] |= ((bcdhigh & 2) << 0) | ((bcdlow & 2) >> 1);
00159             output[3] |= ((bcdhigh & 1) << 1) | ((bcdlow & 1) << 0);
00160             break;
00161         case timestamp:
00162             /* compute the UNIX-Timestamp. This function is based on http://www.mulder.franken.de/ntpdcfledclock/ */
00163             ts = TS01012000 + SECONDSINADAY;        /* 2000 was leap year */
00164             ts += SECONDSINADAY * datetime.date.year * 365;
00165             /* Now account for the leap years. Yes, 2000 was a leap year too. */
00166             ts += SECONDSINADAY * ((datetime.date.year - 1) / 4);
00167             ts += SECONDSINADAY * monthstarts[datetime.date.month - 1];
00168             if (((datetime.date.year % 4) == 0) && (datetime.date.month > 2)) {
00169                 /* We are in a leap year and past february */
00170                 ts += SECONDSINADAY;
00171             }
00172             ts += SECONDSINADAY * (datetime.date.dayofmonth - 1);
00173             ts += 3600UL * datetime.time.hour;
00174             ts += 60 * datetime.time.minute;
00175             ts += datetime.time.second;
00176 
00177             output[0] = (ts >> 24);
00178             output[1] = (ts >> 16);
00179             output[2] = (ts >>  8);
00180             output[3] = (ts >>  0);
00181             break;
00182         default:
00183             break;
00184     }
00185 } // function setOutput
00186 
00191 void setWaiting(void) {
00192     static uint8_t position = 0;
00193     output[0] = 0;
00194     output[1] = 0;
00195     output[2] = 0;
00196     output[3] = 0;
00197     if (position < 8) {
00198         output[0] = (1 << position);
00199     } else if (position == 8) {
00200         output[1] = 128;
00201     } else if (position == 9) {
00202         output[2] = 128;
00203     } else if (position == 18) {
00204         output[2] = 1;
00205     } else if (position == 19) {
00206         output[1] = 1;
00207     } else {
00208         output[3] = (128 >> (position - 10));
00209     }
00210     position++;
00211     if (position > 19) {
00212         position = 0;
00213     }
00214 } // function setWaiting
00215 
00220 void timerInterrupt(void) {
00221     dcf_datetime datetime; 
00222     static uint8_t tickcounter; 
00223     static uint8_t keycounter = 0; 
00224     static uint8_t demomodecounter = 0; 
00225     static uint8_t modeswitched = 0; 
00227     tickcounter++;
00228 
00229     /* on every second interrupt, check the state of the DCF-signal */
00230     if (tickcounter % 2) {
00231         if ((PINC & (1 << PINC0))) {
00232             // signal high
00233             dcf_signal(True);
00234             PORTC |= (1 << PINC1);
00235         } else {
00236             // signal low
00237             dcf_signal(False);
00238             PORTC &= ~(1 << PINC1);
00239         }
00240     }
00241 
00242     /* on every 32nd interrupt, check if the key is pressed. After 5 loops with
00243      * a pressed key, switch to the next display-mode. */
00244     if (tickcounter % 32 == 0) {
00245         if (!(PINC & (1 << PINC2))) {
00246             // key pressed
00247             keycounter++;
00248             if (keycounter > 2) {
00249                 // after 4 cycles with pressed key, switch to the next mode
00250                 keycounter = 0;
00251                 mode++;
00252                 if (mode > timestamp) {
00253                     mode = timeasbinary;
00254                 }
00255                 modeswitched = 5;
00256             }
00257             demomodecounter++;
00258             if (demomodecounter > 75) {
00259                 // after 75 cycles with pressed key, switch to or from demo mode
00260                 if (demomode == 0) {
00261                     demomode = 1;
00262                     mode = timeasbinary;
00263                     output[0] = 255;
00264                     output[1] = 255;
00265                     output[2] = 255;
00266                     output[3] = 255;
00267                 } else {
00268                     demomode = 0;
00269                     mode = timeasbinary;
00270                     output[0] = 255;
00271                     output[1] = 129;
00272                     output[2] = 129;
00273                     output[3] = 255;
00274                 }
00275                 setLeds();
00276                 demomodecounter = 0;
00277             }
00278         } else {
00279             // key unpressed
00280             keycounter = 0;
00281             demomodecounter = 0;
00282         }
00283     }
00284 
00285     /* on every 128th interrupt (about 4 times per second), check if anything
00286      * new has to be displayed. */
00287     if (tickcounter % 128 == 0) {
00288         if (demomode == 1) {
00289             // set the current date and time to a fixed value to demonstrate
00290             // how the time is displayed
00291             datetime.is_valid = 1;
00292             datetime.time.hour = 23;
00293             datetime.time.minute = 49;
00294             datetime.time.second = 57;
00295             datetime.date.dayofmonth = 31;
00296             datetime.date.month = 12;
00297             datetime.date.year = 6;
00298             datetime.date.dayofweek = 7;
00299         } else {
00300             datetime = dcf_current_datetime();
00301         }
00302         if (modeswitched > 0) {
00303             output[0] = mode + 1;
00304             output[1] = mode + 1;
00305             output[2] = mode + 1;
00306             output[3] = mode + 1;
00307             modeswitched--;
00308         } else if (datetime.is_valid) {
00309             setOutput(datetime);
00310         } else {
00311             setWaiting();
00312         }
00313         /* finally, set the output */
00314         setLeds();
00315     }
00316 } // function timerInterrupt
00317 
00323 int main(void) {
00324     uint8_t i;
00325 
00326     /* set a default display-mode */
00327     mode = timeasbinary;
00328 
00329     /* intialize ports */
00330     DDRC = (1 << DDC1); // set pin 1 to output
00331     PORTC = (1 << PC1) | (1 << PC2); // activate pullups on pins 1 and 2
00332 
00333     /* initialize SAA1064 on i2c-bus */
00334     led_init();
00335     set_led_brightness(1);
00336     for (i = 0; i <= 3; i++) { /* switch off all connected LEDs */
00337         set_led_digit(i, 0);
00338     }
00339 
00340     /* initialize DCF77 */
00341     dcf_init();
00342 
00343     /* initialize timer */
00344     TCCR0 = (0 << CS02) | (1 << CS01) | (0 << CS00); // set divider to 8.
00345          /* The interrupt is called every 8*256 CPU-cycles, at 1MHz we get 488
00346           * calls per second. DCF_RATE in dcftime.h has to be set according to
00347           * this value. */
00348     sei();
00349 
00350     while (1) {                 /* main event loop */
00351         if (TIFR & (1 << TOV0)) {
00352             TIFR |= 1 << TOV0;  /* clear pending flag */
00353             timerInterrupt();
00354         }
00355     }
00356     return 0;
00357 }

Generated on Wed Jan 3 22:22:35 2007 for Binary DCF-77 Clock by  doxygen 1.5.1