Yup, It appears that the capacitor value is crucial to long term timing.

In my test above (8 sec. fast). I was using a PROTO-40 board from the now defunct projectx.com It came with 15pf capacitors on the crystal. After making a program to be able to read the crystal frequency, I found that it was very close to my estimate above. (4,000,358 instead of 4,000,370). It's amazing that a 7pf difference can throw the crystal that far out of tolerance.

After changing the capacitors to 22pf, the frequency changed to 3,999,978

And, after two days of running your Romanesque code, it's showing a loss of 0.5 seconds per day. So it's at least gratifying to know that the frequency measurement was correct, and the overall timing is predictable.

However, now you've thrown me for another loop by saying that your crystal was oscillating fast with 33pf caps. Which doesn't fit in with my theory of more pF = lower Freq. So, yet another thing to figure out. Oy vey.

I guess it won't really matter too much though, since there are only 3 standard capacitor values in the range we need, 15, 22 and 33 pf, there's no way to compensate for inaccuracies by changing the values. So, it seems to boil down to a few possibilities.
  • Measure the actual frequency and use a variable capacitor on the crystal to adjust to the correct frequency.
  • Use normal fixed capacitors. Measure the actual frequency, and calculate a "Fudge Factor" for the Timer counts.
  • Spend several days watching a clock count and compare it to Real time, then calculate the Fudge Factor from the time difference. (I got really tired of this one, takes too long)

So it looks like the only way to go is actually measuring the frequency and adjusting from there, either hardware or software. But how to measure it? Simply putting a frequency counter probe on the crystal will change the frequency significantly due to the extra capacitance. So it needs to be done some other way.

<hr>My first attempt:

I'm using a DS1307 as the time base, and for the moment am using a +/-20ppm 32,768 crystal on it. I've been trying to find a DS32KHZ +/-2ppm oscillator, but can't seem to find anywhere that has one in stock. But I'm not too worried about it now because, after 3 days, the DS1307 is still "Exactly" in sync with real time, so I think it's pretty close to 32,768

Timer1 is set up as a Free-running counter, that never gets stopped or reloaded, so it's just sitting there counting instruction cycles forever. The overflow interrupt simply adds 1 to a 32-bit variable each time, extending timer1's count to 48 bits, which let's it count instruction cycles for a very long time.

The 1hz square wave output from the 1307 is fed to CCP1 input. CCP1 is in Capture mode, triggering on every rising edge. The Capture catches the TMR1 value, and the interrupt handler copies the upper 32 bits to temp vars so they don't change while sending out RS.232

The Timer is started on the first rising edge of the Square Wave input, and the number of cycles received from the 1307 are counted in another 32-bit variable. But since PBP doesn't work with 48 and 32-bit variables, I have to send the data out as hex numbers. Looks like this...<pre>Count 001D 1855 A0E0<br>Seconds 0001 E823</pre>
From there I can cut&paste the numbers into the windows calculator and figure out that after 124,963 seconds (0001 E823) about 34 hours, the pic had executed 124,962,316,512 instructions (001D 1855 A0E0)

Dividing the total by the seconds passed says that 999,994.53 instructions are being executed each second from a crystal frequency of 3,999,978.12 hz.

However, after only 10 minutes, it had it nailed down to 999,994.42 inst/sec. and as time goes on, it just works out the decimal places.

So now, I'm running the Roman code with a constant of 999,994 (0F 42 3A), instead of 1,000,000 (0F 42 40). So far so good.

While this procedure seems to work, it still takes external hardware (DS1307). &nbsp; And frankly, it's a pain in the butt converting all those hex numbers. So I think the next step is to create a program that runs on a PC to do all those conversions, and to handle the timing. instead of the 1307. Hopefully that will make it so you don't need any external hardware on the pic, except for a serial port. Then once the frequency is known it can save the Fudge Factor in EEPROM.

I also thought about using Steve's nice little timer as the time base, but I needed Timer1 for the CCP capture. May want to use that one later though.
<hr>
After the frequency is determined and the constant calculated, It's still not going to keep perfect time. With a +/- 100 ppm variance over the temperature range, it just messes everything up. As seen earlier, 93ppm made a difference of 8 seconds per day.

Granted, I never plan on seeing -10 deg C in my home, or outside for that matter (California). But even 10 or 15 degrees away from 25 deg C could have a big impact.

So I'm thinking that monitoring the temperature and adjusting the constant dynamically as the temperature changes, will yield the best results.

Geez, this is turning into one of those never ending projects. And I just have to find the answers.

BTW shahidali, if you "tweaked" the constant for 4,000,176 hz, if my math is correct should have been (0F 42 6C)? Anywhere close?
<br>