Ayuda con timer0 pic16f84a

Buenas Gente,,, tengo una duda existencial..

estoy haciendo un reloj digital con el pic16f84a con un cristal de 4MHZ

programando en pic c compiler.. porque ASM ni se ni me gusta..

partiendo desde 0 lo que tengo es lo siguiente..

la creacion de la base de tiempo de un segundo con la RTCC

el gran problema parte desde aqui creo yo.. ya que mi reloj ademas de tenerlo ya funcionando.. en forma de prototipo... pasadas 4 hs comienza a retrasarse un par de minutos...

alguien puede decirme porque??? o que esta mal?








#fuses HS,NOWDT,NOPROTECT,PUT
#use delay(clock=4000000)

char contador;

#int_rtcc
void interrupt(void)
{
set_rtcc(6); // interrupciones y recarga el timer
contador++; // Incrementa la variable que cuenta las

if(contador==250) // aqui llego a 1 segundo
{
contador=0;
s++;



}

void main()
{

setup_counters(RTCC_INTERNAL,RTCC_DIV_16);
set_rtcc(6); // Carga el valor del timer0

enable_interrupts(int_rtcc);
enable_interrupts(GLOBAL);

do
{
//lalalal
}while(1);

}
 
Claro, un compilador de alto nivel genera más código en ASM que si lo hicieras todo en asm, así que esos microsegundos de más se hacen notar con el pasar de las horas.
Usar setup_counters(RTCC_.... hace lo mismo que si usas setup_timer_0(... ya que da igual, solo usa el único timer que tiene.

Como lo veo, tienes que seguir:
- Setear el timer0 con un valor de ajuste cada vez que sucede la interrupción y también debes de ajustar la variable contador lo más que puedas hasta que tenga cierta estabilidad al pasar las horas.
- O hacer la interrupción manualmente mezclando instrucciones en ASM ya que si vez el archivo *.lst te darás cuenta que hay como 30 instrucciones más arriba de la interrupción que hacen el trabado de guardar/salvar el contexto cuando sucede una interrupción. Supongo que es por eso que se retrasa el conteo.

saludos.
 
Hola psm

Hay una explicación a lo que esta sucediendo, tu programa esta bien y has hecho bien las consideraciones de parametrizacion; sin embargo debes considerar que el TMR0 requiere sincronizacion interna debido al diseño de los microcontroladores PIC, existe un ciclo dummy que el procesador toma para generar la interrupcion.

La explicacion precisa la puedes encontrar en el documento de microchip (DS33023)
[/SIZE]
http://ww1.microchip.com/downloads/en/DeviceDoc/33023a.pdf

busca en la pagina 173.

Ojala te sirva

Saludos
 
ahora me pongo a leer lo que me sugeriste.. tratante.. no tenia idea de eso..

en fin.. lo que no me queda claro.. es si tengo que recurrir a aprender a programar en asm o si es realmente factible poder hacer un reloj exacto programado desde c..


de todas formas.. les agradezco..


otra cosa que no me queda clara.. es..::


usando el timer 0 para crear la base de tiempos...


si yo.. en la funcion main dentro del while.. pusiera. delay_ms(1000);

afectaria al contador , a la base de tiempo?


es asincrono?


gracias :D

The TMR0 interrupt is generated when the TMR0 register overflows from FFh to 00h. This
overflow sets bit T0IF (INTCON<2>). The interrupt can be masked by clearing bit T0IE
(INTCON<5>). Bit T0IF must be cleared in software by the Timer0 module interrupt service routine
before re-enabling this interrupt. The TMR0 interrupt cannot awaken the processor from
SLEEP since the timer is shut-off during SLEEP. See Figure 11-4 for Timer0 interrupt timing


me dice eso.. tratante.... es como preguntarle la hora a un japones para mi...


como uso TOIF desde c, INTCON... ni ideaaaaaaaaaaa
 
Última edición:
Hola psm

Hice las verificaciones considerando la perdida de 2 ciclos y no justifica mas de 3 segundos en 4 horas de trabajo; asi que me di a la tarea de observar el archivo LST que genera el compilador y sorpresa desagradable !!!

Ejecuta al menos 26 instrucciones antes de recargar el TMR0 despues de haber ocurrido la interrupcion real, ya que el TMR0 se incrementa cada 16 ciclos y estamos consumiendo 26 ciclos esta claro que perdiste un incremento.

Un incremento representa 1000000 / 16 = 62500 y 1 / 62500 = 0.000016
es decir el TMR0 se incrementa cada 16uS

bien, 16uS * 250 = 0.004; es decir, la interrupcion ocurre cada 0.004 segundos
Si cada 0.004 pierdes 16uS entonces 250 * 16uS = 0.004

0.004 es lo que pierdes por cada segundo transcurrido, 0.004 * 3600 = 14.4 segundos por hora y en 4 horas seran 57.6 segundos !!!

Posible solucion

Usa un preescaler mas pesado, digamos 64, y carga 256 - 125 = 0x83 en el TMR0
y cuenta 125 veces la interrupcion para hacer un segundo.

En teoria la rutina de servicio podra ocurrir y terminar antes de que ocurra el nuevo
incremento al TMR0.

Otra solucion seria que cuentes 249 en lugar de 250 y asi compensar el incremento que debio haber ocurrido antes de recargar el TMR0.

Saludos !!!
 
wow tu te diste más trabajo que yo (y) al ver el archivo .lst que nos hace llorar de vez en cuando que se busca precisión. En fin espero que no esté buscando hacer un reloj suizo... todo lo que se conseguirá es una aproximación.

PD: Para otros PIC, usa el Timer1 + cristal externo de 32.768Khz

Saludos
 
muchisimas gracias de verdad.. soy nuevo en esto.. y esas cosas no las tengo en la mente..


agradezco por los 2 tips..


voy a ver como lo soluciono.. y sino.. habra q poner otro cristalcito..
 
Como decia ByAxel, si yo uso un pic 16f628a ,,, que posee timer1 podrias pasarme un esquema de como se conectaria el cristal externo que me decis con los capacitores a masa?...


el cristal tiene 2 patas.. una iria a positivo y la otra a la pata del pic? :S o como seria???
 
Te fijas en el datasheet del 16F628A, verás que para el Timer1 usa los pines RB6/T1OSO y RB7/T1OSI para poner el cristal externo de baja frecuencia. Incluso recomiendan usar el cristal de 32.768Khz + 2 capacitores de 15pF. Es decir que las dos patas del cristal van a esos dos pines del PIC, cada capacitor conectado a cada pin y conectados a masa (el cuerpo del cristal también a masa). EL resto ya es configurar los registros para que el Timer1 trabaje con el cristal y activar interrpución para que el Timer1 se desborde cada 1s.

saludos
 
Atrás
Arriba