DCF77 LED Clock C Source Code | Microcontroller Project



/*
* 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 more..........



/*
* 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
}
}

1 comments:

Anonymous said...

Have you ever considered about including a little bit more than just your articles?
I mean, what you say is valuable and everything. Nevertheless just imagine if you added some great photos or video clips to give your posts
more, "pop"! Your content is excellent but with images and clips, this site could certainly be one of the best in its niche.
Great blog!

Check out my weblog - national corporate housing los angeles

Post a Comment

 

Free Download Engineering Books - IEEE Books | Copyright 2009-2013 All right reserved | Design by BMW Automobiles | Created by Umair Sheikh