Acabo de ver que fue un error mio. Las 1800 vueltas las tenes casi si haces 30 * 60 = 1800
Volvamos a calcular de nuevo
Fosc = 64Mhz
Fosc/4 = 16Mhz
Pasando el Preescaler que es de 1:8 =
2Mhz Entrando al TMR1Es decir cada cuenta es de
0.5us o
500nsHasta acá estamos igual que antes. Ahora a calcular tu problema.
Tu problema:
Las instrucciones antes del set_timer, como te dije el poner el set_timer antes implica que se cargue rapidamente el valor del TMR1 y no deba pasar por tdas las instrucciones, suponete que apenas entra a la interrupcion el timer1 queda en 0x00 ya que se produjo el overflow, luego de varias instrucciones al final queda en 0x02 y vos lo pones a 0 de vuelta, esos 2 conteos implican un error que va a ocurrir cada ves que entre a la interrupcion. Si decis que entra 30 veces por cada segundo, y son 60 segundos, quiere decir que estaria contando 30*60*2 = 3600 , esos 2 son lo que conto y que sobreescribimos de mas. Se entiende que es un error acumulativo?
Podriamos agarrar y omitir el "set_timer1", total al momento de dispararse la interrupcion es por que paso de 0xFFFF a 0x0000 el TMR1, por lo tanto ya esta en 0 y no deberiamos hacerlo. Aca solucionamos el problema anterior pero tenemos otro problema. Como ves en tus calculos tenes que:
0.032768*30=0.98304 segundos
Son 0.98 segundos y no 1 segundo exacto. Esto que ocurra en los 60 segundos te da que 60 * 0.98304 = 58.9824s , es decir todavia le falta aproximadamente 1 segundo mas. Y si por ejemplo le pones 61 vueltas en ves de 60 tendrias 59.96544s y pensarias que tendrias todo perfecto, pero ocurriria por ejemplo que a la media hora de corriendo tu codigo retrasa un segundo la toma de datos... es decir verias algo asi:
21/02/2017 06:21:20 p.m. ****
21/02/2017 06:22:20 p.m. ****
21/02/2017 06:23:10 p.m. ****
.....
.....
21/02/2017 06:51:19 p.m. *****
21/02/2017 06:52:19 p.m. *****
21/02/2017 06:53:19 p.m. *****
Una solucion seria hacer 62 vueltas en ves de 61 como dijimos antes. Solo que la de 62 cubra esa diferencia y no comienza el timer desde 0. Suponete:
#int_TIMER1 // Interrupción
void TIMER1_isr(void){ // Función de la interrupción
cont++; // Contador
if(cont == 30){ // 0.032768*30=0.98304 segundos
seg++; cont=0; // Bandera para un segundo
if(seg = 62) {
set_timer1(63231);
seg = 0;
min++;
}
} //
}
El calculo es .. Tenemos que suplir 60s - 59.96544s = 0.03456 es decir debe contar , pero antes de entrar al if de esos 62, ocurre que tenes que pasar por 30 antes, entonces 0.03456s / 30 = 1.152ms
A 0.5us cada cuenta -> 2304 a contar, es decir cargar el timer con 63232, ese ultimo valor, podrias hacerlo con 1 mas por las instrucciones anteriores.
Ahora porque complicarse con 2 variables si podemos usar una sola?
int16 cont = 0;
#int_TIMER1 // Interrupción
void TIMER1_isr(void){ // Función de la interrupción
set_timer1(25536);
cont++; // Contador
if(cont == 3000){ // 0.032768*30=0.98304 segundos
cont = 0;
min++;
}
}
Esta ves cuento 40.000 en cada interrupcion del timer es decir 20ms, a los 3000 interrupciones son 20ms*3000 = 60s
Como ves esto me permite con una sola variable tener todo y ser mas simple. Ademas como la interrupcion va a ser un poco mas exacta no tengo que hacer esa ultima vuelta con un timer diferente.
Problemas con esto? Si tendrias el mismo problema que con el anterior, hasta que entre a la interrupcion se perderian algunos ciclos, Y se tornaria en un error acumulable que haria que adelante 1 segundo cada 1 hora o mas tal ves,
Si queres ser mas exacto deberias usar el CCP. Lo configurarias en modo COMPARE; que se auto reinicie el TIMER1, y que ocurra la interrupcion a los 40.000, Asi al menos tendrias solo un error, ya que no se acumularia. Tendrias el error desde que se produce la interrupcion hasta que haces tus cosas en la interrupcion y fue.