|
|
View previous topic :: View next topic |
Author |
Message |
Guest Guest
|
General clock, timing, and interval question |
Posted: Tue Feb 24, 2004 11:27 am |
|
|
Advice from the experts, please:
If I need a basic PIC to do something at periodic intervals (like take an ADC measurement, or send data out the RS232 port), what is the best way to do this when the time between these events is very, very long wrt the clock cycle?
For example, I want to do something every hour for 1000 hours - this is a made-up but maybe practical example. Is it best to use the internal timers and interrupts, or would one use a real-time clock? Are the internal timers (assuming the code is written correctly, temperature is stable, etc.) precise enough for such long-term measurements? Or does the cumulative error get too big (I don't mean the error from rounding of integers - I assume the code is written to minimize this if possible)? Does one then use an off-board clock and use this to time the events? What do people do in this case?
General comments appreciated. Thanks.
Bill |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Tue Feb 24, 2004 11:44 am |
|
|
This is for a 4Mhz crystle
Code: | int1 Clock_Been_Initialized=0;
Int16 Miliseconds;
#locate Miliseconds = Registry_Map+6
Int16 Seconds;
#locate Seconds = Registry_Map+8
int1 Second_Tick=0;
// Global Real Time Clock Information
#int_TIMER2 // Clock interrupt adjusted to occurs ~ 1ms
void TIMER2_isr()
{ Miliseconds++;
if(Miliseconds>999)
{ Miliseconds=0;
Seconds++;
Second_Tick=1;
}
}
/***********************************************************
* Service Hardware Modules *
***********************************************************/
#inline
void Clock_Service(void)
{ if(!Clock_Been_Initialized)
{ setup_timer_2(T2_DIV_BY_4,249,1); // Set 1mS period
enable_interrupts(INT_TIMER2);
Seconds=0;
Clock_Been_Initialized=1;
}
if(Second_Tick)
{ Second_Tick=0;
if(++seconds>59) seconds=0;
if(++Minutes>59)
{ bla bla hour event.....
}
}
}
|
|
|
|
plehman
Joined: 18 Feb 2004 Posts: 12
|
|
Posted: Tue Feb 24, 2004 11:54 am |
|
|
It might help to know what type of timing error you can tolerate. If you are reading every hour for 1000 hours, then a couple of seconds either way may not make a difference. If that's the key, you could probably use the RTC or the timers on the PIC.
If you were to right the clock service as an interrupt service routine, and you timed out how long it was going to take, you could probably "calibrate" out the error on a gross scale, though this would be easier in Assembly language.
Consider the following:
PIC clocked from 4MHz crystal => 1MHz instruction rate
Timer1 used (its 16-bits long on most if not all PICs)
Timer1 set up with a 1:8 prescaler
To get an interrupt every 1/2 second, set Timer1's initial count to 0x0BDB so that an interrupt from overflow will be generated in 62500 clocks (0.5seconds). From the data sheet and looking at the .LST file, you can determine the number of clock cycles it takes to execute your isr for Timer1 (remember to account for CALLs and RETurns into and outof the isr and sub-routines).
you could set up the isr using the code as follows for a good idea
Code: |
static long HoursWorthOfHalfSecs = 0;
static boolean A2DConvertFlag = 0;
#int_TIMER1
void TIMER1_isr()
{
HoursWorthOfHalfSecs++;
if (HoursWorthOfHalfSecs == 7200)
{
HoursWorthOfHalfSecs = 0;
ConvertA2DFlag = 1;
}
set_timer1(XXXX); // XXXX is new count to set it to to account for timing of routine
}
void main()
{
........ // Setup, etc.
while(1)
{
if (ConvertA2DFlag == 1)
{
convert_adc();
ConvertA2DFlag = 0;
}
}
}
|
Now check the assembly created for the TIMER1_isr() in the .LST file, count the clock cycles used, and add them to 0x0BDB to get the new value to set the Timer1 count to before returning from the isr. Now you can minimize the while(1) loop to determine how many clocks from the end if the isr that the code will execute, and the implication is that the A/D conversion would be taken within a few cycles of each other at pretty close to exactly an hour interval. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Tue Feb 24, 2004 2:22 pm |
|
|
This will get an exact 1mS interupt period when using a 4Mhz crystle
setup_timer_2(T2_DIV_BY_4,249,1); // Set 1mS period
This says count exactly 1000 instruction periods and then sets the interupt flag. There is no drift unless interupts are disabled. |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Tue Feb 24, 2004 2:44 pm |
|
|
Consider that a generic micrprocessor crystal has a tollerance of about +/-30ppm, that gives +/-100ms/hour. What sort of accuracy do you require? _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
|
|
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
|