I need to increment a stopwatch at 10hz using timer1 on a PIC16F628. The external clock is 1Mhz, supplied by a packaged oscillator (EPSON sg8002db). With no prescaler, the value to set the timer to (I think) should be:
clock ticks in 1 second: 1000000
timer ticks in 1 second: 250000 (clock/4)
timer ticks in 1/10th of a second: 25000 (timer ticks/10)
So: 65536 - 25000 = 40536
but I need to consider the latency from timer overflow to when the clock value is reset - this is the number of cycles it takes from the overflow occurring to when I set the timer value.
The IRQ code is:
irq movwf w_temp ; save state
swapf STATUS, w
clrf STATUS
movwf status_temp
movf PCLATH, w
movwf pclath_temp
clrf PCLATH
btfss PIR1,TMR1IF ; timer1 IRQ?
goto notimer1
bcf PIR1,TMR1IF ; yes, clear it
movLw T1SPEED >> 8 ; reset timer1
movwf TMR1H
movLw T1SPEED & 0xff
movwf TMR1L ; timer1 is off and running again
call timer ; increment clock
notimer1 btfss INTCON, T0IF ; timer0 IRQ?
goto notimer0
bcf INTCON, T0IF ; yes, clear it
call led_set ; update display
btfss PORTA,6 ; button pressed?
goto nobut
clrf digit0 ; yes, reset clock
clrf digit1
clrf digit2
clrf digit3
nobut
notimer0 movf pclath_temp, w ; restore state
movwf PCLATH
swapf status_temp, w
movwf STATUS
swapf w_temp, f
swapf w_temp, w
retfie
Which looks to me like somewhere in the region of about 14 cycles, so LATENCY = 14
65536 - (25000 - LATENCY) = 40550
but this gives a clock which is far too slow, losing multiple seconds per minute. If I change the LATENCY value to ~200 (eg set timer1 to 40736), it's close - within 1 second per minute, but still not accurate. In fact, with LATENCY = 199, it's too fast, and with LATENCY = 200, it's slow.
I can't see where these extra cycles are being spent - it sets the clock value first thing in the IRQ routine. I can't find anything in the datasheet about timer1 being stopped during an interrupt routine, but is it? If so, that would be a bummer, because the routine takes a variable number of cycles depending on which digits overflow.
Is it necessary to pick 2 different reload values and alternate between them in order to hit exactly 10hz?