Necesito incrementar un cronómetro a 10 hz usando el temporizador 1 en un PIC16F628. El reloj externo es de 1Mhz, suministrado por un oscilador empacado (EPSON sg8002db). Sin prescaler, el valor para configurar el temporizador (creo) debería ser:
tictac del reloj en 1 segundo: 1000000
el temporizador marca en 1 segundo: 250000 (reloj/4)
tictac del temporizador en 1/10 de segundo: 25000 (ticks del temporizador/10)
Entonces: 65536 - 25000 = 40536
pero debo considerar la latencia desde el desbordamiento del temporizador hasta que se restablece el valor del reloj: esta es la cantidad de ciclos que transcurren desde que se produce el desbordamiento hasta que configuro el valor del temporizador.
El código IRQ es:
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
Lo que me parece en algún lugar en la región de unos 14 ciclos, entonces LATENCY = 14
65536 - (25000 - LATENCIA) = 40550
pero esto da un reloj que es demasiado lento, perdiendo varios segundos por minuto. Si cambio el valor de LATENCY a ~200 (por ejemplo, configuro timer1 a 40736), está cerca, dentro de 1 segundo por minuto, pero aún no es preciso. De hecho, con LATENCY = 199 es demasiado rápido y con LATENCY = 200 es lento.
No puedo ver dónde se gastan estos ciclos adicionales: establece el valor del reloj a primera hora de la rutina IRQ. No puedo encontrar nada en la hoja de datos sobre la detención del temporizador 1 durante una rutina de interrupción, pero ¿lo es? Si es así, eso sería un fastidio, porque la rutina toma un número variable de ciclos dependiendo de qué dígitos se desbordan.
¿Es necesario elegir 2 valores de recarga diferentes y alternar entre ellos para llegar exactamente a 10 hz?
En lugar de usar el temporizador 1 de 16 bits, que requiere que vuelva a cargar el valor en el código, use el temporizador 2 de 8 bits, que tiene un registro PR2 preestablecido. Cargue PR2 con 250, con un valor de preescalador de 1:1. Luego interrumpirá cada 1 ms y se recargará automáticamente para que no haya problemas de latencia.
Dentro de su interrupción, simplemente incremente un contador de un solo byte. En su rutina base, use un bucle while y pruebe siempre que el contador sea igual a 100 (es decir, haya transcurrido 1/10 de segundo). Luego reinicie el contador y actualice y reinicie su reloj/led allí en el nivel base, no en su rutina de interrupción.
en lugar de restablecer el temporizador 1, simplemente actualice la alarma para que sea 0.1 s más en el futuro
brahans
charlie skilbeck