You are on page 1of 7

/* * 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 #define ADJUST 96

// number of TMR0 overflows in 1 second // 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 r eceiver 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, se conds 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 Mh z), * and overflows when reseting from 255 to 0, * fetching to the interrupt precedure with bit T0IF set */ void interrupt(void) { // if(INTCON.T0IF) // TMR0 overfl ow ? { /* * test DCF pulse, inverts the level if negative logic flag 'mod e' is set */ if(PORTA.F4 ^ mode) // DCF pulse is high ? { tmrh++ ; // yes, incremen t my high timer if(tmrd > timer_d_min) // down timer is greater than pulse pause ? { bitnum = 0 ; // yes, reset bi t number if(full) // is the DCF fr ame complete ? { rhh = hh ; // yes, set hour s, min and seconds of RTC rmn = mn ; rss = 0 ; scaler = 0 ; // reset my scal er locked = 1 ; // locked flag i s set, to enable display } mn = hh = 0 ; // reset min and hours for next frame parity = 0 ; // reset parity counter full = 0 ; // reset full fl ag dp.F3 = 1 ; // set frame fla g } tmrd = 0 ; // reset down ti mer } else { tmrd++ ; // pulse is low if(tmrh > 0) // test if a hig h pulse was present { if(tmrh > timer_h_1) // yes, was long er than delay for a 1 ? { last_bit = 1 ; // yes, last bit

was a 1 switch(bitnum) number of frame bit : { case 21: mn++ ; break ; // add minutes weights case case case case case case // add hours weights case case case case case } 30: 31: 32: 33: 34: hh hh hh hh hh += += += += += 2 ; break ; 4 ; break ; 8 ; break ; 10 ; break ; 20 ; break ; 22: 23: 24: 25: 26: 27: mn mn mn mn mn mn += += += += += += 2 ; break ; 4 ; break ; 8 ; break ; 10 ; break ; 20 ; break ; 40 ; break ; // depending on

case 29: hh++ ; break ;

/* * is it a data bit or a parity bit ? */ if((bitnum != 28) && (bitnum != 35) && ( bitnum != 58)) { parity++ ; rement parity } bitnum++ ; t } else if(tmrh > timer_h_0) e a 0 ? { if(bitnum == 20) t ? { last_bit = -1 ; // bad karma, sh ould be 1 ! bitnum = 0 ; it counter dp.F3 = 0 ; lag indicator } else { last_bit = 0 ; // not a start b it, is ok bitnum++ ; t } } else { // next frame bi // clear frame f // reset frame b // yes, start bi // was last puls // next frame bi // data bit, inc

last_bit = -1 ; t was garbage bitnum = 0 ; it counter dp.F3 = 0 ; lag indicator } if(bitnum == 21) sed ? { parity = 0 ; rity counter }

// ouch, last bi // reset frame b // clear frame f

// bit 20 is pas // yes, clear pa

/* * last bit was a parity bit ? */ if((bitnum == 29) (bitnum == 36) = 59)) { if((parity & 1) != last_bit) but parity is incorrect { bitnum = 0 ; frame bit counter dp.F3 = 0 ; frame flag indicator } parity = 0 ; counter } if(bitnum == 59) complete ? { full++ ; ave a pulse pause } } tmrh = 0 ; lse counter } /* * real time clock */ scaler++ ; scaler if(scaler == MAXCOUNT) assed ? { TMR0 += ADJUST ; scaler = 0 ; aler rss++ ; if(rss == 60)

(bitnum = // yes, // reset // clear

// clear parity

// is the frame // yes, should h

// clear high pu

// increment the // a second is p

// yes, clear sc // next second // seconds overf

low ? { rss = 0 ; cond rmn++ ; if(rmn == 60) low ? { rmn = 0 ; nute rhh++ ; if(rhh == 24) w ? { rhh = 0 ; ur } } } } dp.F1 = PORTA.F4 ^ mode ; to the decimal point for display INTCON.T0IF = 0 ; to enable next call on overflow } } /* * program entry point */ main() { TRISA = 0b00010000 ; TRISB = 0x00 ; INTCON = 0b10100000 ; OPTION_REG = 0b11011000 ; /* * main loop */ for(;;) { if(locked > 0) { if(kp) // copy the pulse level // clear interrupt flag // yes, clear ho // next hour // hours overflo // yes, clear mi // next minute // minutes overf // yes, clear se

// see header // see header // T0IF and GIE enabled // no prescaler

// is the RTC up to date ? // yes, is the key pressed ? { /* * yes, prepare display for MN:SS */ digiled[0] = septSeg[rmn / 10] ; digiled[1] = septSeg[rmn % 10] ;

// minut // minut // secon // secon

es tenth es unit digiled[2] = septSeg[rss / 10] ; ds tenth digiled[3] = septSeg[rss % 10] ;

ds 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] ; es tenth digiled[3] = septSeg[rmn % 10] ; e unit } } else { /* * the RTC is not up to date, display DCF frame info */ digiled[0] = 0 ; // nothing on first 2 di gits digiled[1] = 0 ; digiled[2] = septSeg[bitnum / 10] ; tenth digiled[3] = septSeg[bitnum % 10] ; 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 ; PORTB = 0 ; TRISB = 0x80 ; kp = PORTB.F7 ; TRISB = 0x00 ; digit++ ; if(digit > 3) { digit = 0 ; i = 0x01 ; st display led cathod control } else { i = 0x01 << digit ; y cathod activztion } // shut down display // clear segment outputs // set PORTB.F7 as input // read key // set PORTB.F7 as output again // next digit to be displayed // all done ? // yes, start again with first // assign bit mask for PORTA fir // number of bit // number of bit // minut // minut

// shift bit for next led displa

PORTB = digiled[digit] ; PORTA = i ; isplay } }

// write 7 segment output // light on selected 7 segment d

You might also like