If this page is translated by Google, the source code below will not be useable : leave the translation to get it correctly.
/* * DCF-77 LED CLOCK * * PIC16F84A * 10 Mhz crystal, HS clock * * PORTA.0->3, out : 7 segment cathod control * PORTA.4, in ; DCF pulse input * * PORTB.0->7, out : 7 segment output * PORTB.7, in : button input * * Author : Bruno Gavand, november 2005 * see more details on www.micro-examples.com * */ /* * constant definitions */ #define MAXCOUNT 9766 // number of TMR0 overflows in 1 second #define ADJUST 96 // extra ticks in 1 second /* * this values are reduced in practice * to give some flexibility to DCF-77 pulse reception */ #define timer_d_min 14000 // number of TMR0 overflows in 2 seconds : 19531 #define timer_h_0 640 // number of TMR0 overflows in 0.1 second : 976 #define timer_h_1 1400 // number of TMR0 overflows in 0.2 second : 1953 /* * RAM variables */ unsigned int tmrh ; // count of TMR0 overflows since pulse is high unsigned int tmrd ; // count of TMR0 overflows since pulse is down unsigned char bitnum = 0 ; // number of last valid bit received char last_bit ; // value of last valid bit received unsigned char parity ; // count of positive bits received unsigned char full = 0 ; // set to 1 when DCF frame is complete unsigned char locked = 0 ; // set to 1 when clock has been adjusted unsigned char mode = 1 ; // 0:positive logic receiver, 1:negative logic receiver unsigned char mn ; // next minutes in DCF frame unsigned char hh ; // next hours in DCF frame unsigned int scaler ; // count of TMR0 overflows for RTC unsigned char rhh = 12, rmn = 34, rss = 56 ; // RTC clock : hours, minutes, seconds unsigned char digiled[4] ; // 7 segment for each 4 displays /* * 7 segment encoding for numbers from 0 to 9 */ unsigned char septSeg[10] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07, 0x7f, 0x67 } ; unsigned char digit ; // current digit in multiplexing sequence unsigned char kp ; // keypad : button to press for displaying mn:ss instead of hh:mn unsigned char dp = 0 ; // decimal points to be reported on display unsigned char i ; // general purpose register /* * interrupt routine called 2500000/256 times by seconds : * the register TMR0 is increased each 4 clock cycles (quartz frequency is 10 Mhz), * and overflows when reseting from 255 to 0, * fetching to the interrupt precedure with bit T0IF set */ void interrupt(void) { // if(INTCON.T0IF) // TMR0 overflow ? { /* * test DCF pulse, inverts the level if negative logic flag 'mode' is set */ if(PORTA.F4 ^ mode) // DCF pulse is high ? { tmrh++ ; // yes, increment my high timer if(tmrd > timer_d_min) // down timer is greater than pulse pause ? { bitnum = 0 ; // yes, reset bit number if(full) // is the DCF frame complete ? { rhh = hh ; // yes, set hours, min and seconds of RTC rmn = mn ; rss = 0 ; scaler = 0 ; // reset my scaler locked = 1 ; // locked flag is set, to enable display } mn = hh = 0 ; // reset min and hours for next frame parity = 0 ; // reset parity counter full = 0 ; // reset full flag dp.F3 = 1 ; // set frame flag } tmrd = 0 ; // reset down timer } else { tmrd++ ; // pulse is low if(tmrh > 0) // test if a high pulse was present { if(tmrh > timer_h_1) // yes, was longer than delay for a 1 ? { last_bit = 1 ; // yes, last bit was a 1 switch(bitnum) // depending on number of frame bit : { case 21: mn++ ; break ; // add minutes weights case 22: mn += 2 ; break ; case 23: mn += 4 ; break ; case 24: mn += 8 ; break ; case 25: mn += 10 ; break ; case 26: mn += 20 ; break ; case 27: mn += 40 ; break ; case 29: hh++ ; break ; // add hours weights case 30: hh += 2 ; break ; case 31: hh += 4 ; break ; case 32: hh += 8 ; break ; case 33: hh += 10 ; break ; case 34: hh += 20 ; break ; } /* * is it a data bit or a parity bit ? */ if((bitnum != 28) && (bitnum != 35) && (bitnum != 58)) { parity++ ; // data bit, increment parity } bitnum++ ; // next frame bit } else if(tmrh > timer_h_0) // was last pulse a 0 ? { if(bitnum == 20) // yes, start bit ? { last_bit = -1 ; // bad karma, should be 1 ! bitnum = 0 ; // reset frame bit counter dp.F3 = 0 ; // clear frame flag indicator } else { last_bit = 0 ; // not a start bit, is ok bitnum++ ; // next frame bit } } else { last_bit = -1 ; // ouch, last bit was garbage bitnum = 0 ; // reset frame bit counter dp.F3 = 0 ; // clear frame flag indicator } if(bitnum == 21) // bit 20 is passed ? { parity = 0 ; // yes, clear parity counter } /* * last bit was a parity bit ? */ if((bitnum == 29) || (bitnum == 36) || (bitnum == 59)) { if((parity & 1) != last_bit) // yes, but parity is incorrect { bitnum = 0 ; // reset frame bit counter dp.F3 = 0 ; // clear frame flag indicator } parity = 0 ; // clear parity counter } if(bitnum == 59) // is the frame complete ? { full++ ; // yes, should have a pulse pause } } tmrh = 0 ; // clear high pulse counter } /* * real time clock */ scaler++ ; // increment the scaler if(scaler == MAXCOUNT) // a second is passed ? { TMR0 += ADJUST ; scaler = 0 ; // yes, clear scaler rss++ ; // next second if(rss == 60) // seconds overflow ? { rss = 0 ; // yes, clear second rmn++ ; // next minute if(rmn == 60) // minutes overflow ? { rmn = 0 ; // yes, clear minute rhh++ ; // next hour if(rhh == 24) // hours overflow ? { rhh = 0 ; // yes, clear hour } } } } dp.F1 = PORTA.F4 ^ mode ; // copy the pulse level to the decimal point for display INTCON.T0IF = 0 ; // clear interrupt flag to enable next call on overflow } } /* * program entry point */ main() { TRISA = 0b00010000 ; // see header TRISB = 0x00 ; // see header INTCON = 0b10100000 ; // T0IF and GIE enabled OPTION_REG = 0b11011000 ; // no prescaler /* * main loop */ for(;;) { if(locked > 0) // is the RTC up to date ? { if(kp) // yes, is the key pressed ? { /* * yes, prepare display for MN:SS */ digiled[0] = septSeg[rmn / 10] ; // minutes tenth digiled[1] = septSeg[rmn % 10] ; // minutes unit digiled[2] = septSeg[rss / 10] ; // seconds tenth digiled[3] = septSeg[rss % 10] ; // seconds unit } else { /* * no key, prepare display for HH:MN */ digiled[0] = (rhh < 10) ? 0 : septSeg[rhh / 10] ; // hours tenth, blank if null digiled[1] = septSeg[rhh % 10] ; // hours unit digiled[2] = septSeg[rmn / 10] ; // minutes tenth digiled[3] = septSeg[rmn % 10] ; // minute unit } } else { /* * the RTC is not up to date, display DCF frame info */ digiled[0] = 0 ; // nothing on first 2 digits digiled[1] = 0 ; digiled[2] = septSeg[bitnum / 10] ; // number of bit tenth digiled[3] = septSeg[bitnum % 10] ; // number of bit unit } /* * set each decimal points, * F1 is pulse repeater, * F3 is frame progress */ digiled[0].F7 = dp.F0 ; digiled[1].F7 = dp.F1 ; digiled[2].F7 = dp.F2 ; digiled[3].F7 = dp.F3 ; PORTA = 0 ; // shut down display PORTB = 0 ; // clear segment outputs TRISB = 0x80 ; // set PORTB.F7 as input kp = PORTB.F7 ; // read key TRISB = 0x00 ; // set PORTB.F7 as output again digit++ ; // next digit to be displayed if(digit > 3) // all done ? { digit = 0 ; // yes, start again with first i = 0x01 ; // assign bit mask for PORTA first display led cathod control } else { i = 0x01 << digit ; // shift bit for next led display cathod activztion } PORTB = digiled[digit] ; // write 7 segment output PORTA = i ; // light on selected 7 segment display } }