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?