|
|
View previous topic :: View next topic |
Author |
Message |
pattousai
Joined: 23 Aug 2006 Posts: 37
|
Help in a Real Time Clock application |
Posted: Fri Jul 18, 2008 4:19 pm |
|
|
Hi everybody.
I'm using the code posted by ckielstra to implement a Real Time Clock, and every minute i set a flag that make a led to blink. the problem is that after a couple of hours the led just don't blink anymore.
i'm using the pic16f628a, xtal of 17287200 Hz and (i believe that is the source of the problem) a battery charger as the power source (5,6V).
So... my hardware isn't right? or there could be another problem?
Here is the code that i'm actually using.
thanks everybody.
Code: |
///////////////////////////////////////////////////////////
// Zero Drift Real Time Clock
// Original code supplied by Neutone.
// Some small optimizations by C.Kielstra.
///////////////////////////////////////////////////////////
#include <16F628a.h>
#use delay(clock=17287200)
#fuses HS, NOWDT, NOLVP, NOMCLR
#use rs232(baud=9600, xmit=PIN_B3, rcv=PIN_B0, stream=PC)
//RTC variables
#define XTAL_FREQUENCY 17287200
#define TIMER1_FREQUENCY (XTAL_FREQUENCY / 4 ) // 1 clock tick = 1 instr. cycle = crystal frequency / 4
int32 Ticker;
int8 Seconds=0;
//optional:
int16 Year = 2008;
int8 Month = 7, Days = 17, Hours = 8, Minutes = 19;
int1 flag1 = false;
////////////////////////////////////////////////////////////////////////////////
// Test whether a given year is a leap year.
// This optimized version only works for the period 2001 - 2099
////////////////////////////////////////////////////////////////////////////////
#define IS_LEAP(year) (year%4 == 0)
////////////////////////////////////////////////////////////////////////////////
// Initialize RTC
////////////////////////////////////////////////////////////////////////////////
void Initialize_RTC(void)
{
Ticker = TIMER1_FREQUENCY; // initialize clock counter to number of clocks per second
setup_timer_1( T1_INTERNAL | T1_DIV_BY_1 ); // initialize 16-bit Timer1 to interrupt
// exactly every 65536 clock cycles
// (about 76 times per second)
enable_interrupts( INT_TIMER1 ); // Start RTC
}
////////////////////////////////////////////////////////////////////////////////
// -=Process Zero Drift Real Time Clock Information=-
//
// Most algorithms configure the timer to generate an interrupt every 100ms, and
// then count the number of interrupts. The problem in that approach is that most
// clock frequencies can't be divided by 256 and you don't get an exact 100ms.
// The small errors will add up to an error of several seconds a day.
//
// The algorithm presented here is exact in the long run because it doesn't
// count the number of interrupts but counts the number of clock cycles.
////////////////////////////////////////////////////////////////////////////////
#int_TIMER1
void TIMER1_isr()
{
Ticker -= 65536; // Decrement ticker by clocks per interrupt
if ( Ticker < 65536 ){ // If second has expired
Ticker += TIMER1_FREQUENCY; // Increment ticker by clocks per second
Seconds++; // Increment number of seconds
}
// --- Optional part start ---
if( Seconds == 60 ){
flag1 = true;
Minutes++;
Seconds=0;
if( Minutes == 60 ){
Hours++;
Minutes=0;
if( Hours == 24 ){
Days++;
Hours=0;
if( ( Days == 29 && Month==2 && !IS_LEAP(Year))
|| (Days == 30 && Month==2)
|| (Days == 31 && (Month==4 || Month==6 || Month==9 || Month==11 ))
|| (Days == 32) ){
Month++;
Days=1;
}
if( Month == 13 ){
Year++;
Month=1;
}
}
}
}
// --- Optional part end ---
}
////////////////////////////////////////////////////////////////////////////////
// Example program for using the RTC
////////////////////////////////////////////////////////////////////////////////
void main()
{
int8 prev_second = -1;
Initialize_RTC();
enable_interrupts( GLOBAL );
// loop forever
while(1)
{
// Toggle output every second
if( flag1 == true )
{
output_toggle(PIN_A2);
flag1 = false;
}
}
}
|
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Jul 18, 2008 7:15 pm |
|
|
Using a battery charger as a power supply is not a very reliable solution. The 5.6V is within the absolute maximum ratings but outside the guaranteed specifications of 5.5V.
If the battery charger is one of the 'smarter' types the voltage could easily change...
I strongly recommend another power supply. Or at least try reducing the voltage by adding a low drop voltage regulator, or 1 or 2 diodes in series (0.6V drop for each diode).
To rule out software problems try testing with a simple as possible program. Code: | #include <16F628a.h>
#use delay(clock=17287200)
#fuses HS, NOWDT, NOLVP, NOMCLR
void main()
{
while(1)
{
// Toggle output every second
output_toggle(PIN_A2);
delay_ms(1000);
}
} |
What is your compiler version number? |
|
|
pattousai
Joined: 23 Aug 2006 Posts: 37
|
|
Posted: Mon Jul 21, 2008 8:49 am |
|
|
my compiler version is 4.057 and this simple program works fine.
i will try add a diode in series, really haven't think about that.
thanks |
|
|
pattousai
Joined: 23 Aug 2006 Posts: 37
|
|
Posted: Wed Jul 23, 2008 4:55 pm |
|
|
ok, i bought 2 diodes and put them in series with the power source and the program stop to behave strangely.
But now I'm printing the time, and after 12 hours the program delay a couple of seconds and that is critical to me (maybe the code will run for years). So... I'm wondering is there any precise crystal? To be honest i know nothing about crystals, the only thing i know is that i bought a "crystal of 24MHz" :S
Thanks for the help |
|
|
pattousai
Joined: 23 Aug 2006 Posts: 37
|
|
Posted: Wed Jul 23, 2008 5:31 pm |
|
|
i was doing some research, and found the ds1307 hardware. this already implements a RTC.
ok, but i think this not fit for me... because i want to send a configuration to the pic and depending on this configuration, the pic will send a data with the time specified.
example... the pic receive a configuration string, and are set to send a data every hour... 15 minutes later, the pic receive another configuration string, and are set to send a data every minute...
so... using this hardware i will have to read the time every minute anyway... and the pic will continue to delay some seconds in long hours, isn't right?
so... anyone have a suggestion to how should make my hardware?
thanks again |
|
|
cmdrdan
Joined: 08 Apr 2005 Posts: 25 Location: Washington
|
|
Posted: Wed Jul 23, 2008 9:22 pm |
|
|
I would think that the DS1307 would work well from what you describe.
Set the SQW output of the 1307 to interrupt your PIC once per second via the external interrupt pin. In the interrupt service routine, decrement a sample_delay variable, and when it is zero, set a flag to be read in main(). In main(), check for the flag, and when set, read the time from the DS1307, process your data, and output the results.
The sample delay could be sent in as part of your configuration word, and there is no reason to read the time from the DS1307 until you want to. If timing accuracy is critical, check out the DS32KHZ TCXO to augment the accuracy of the DS1307.
Hope this helps....
Dan |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|