TODOPIC

Microcontroladores PIC => Todo en microcontroladores PIC => Mensaje iniciado por: JonGoten en 29 de Diciembre de 2004, 19:08:00

Título: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: JonGoten en 29 de Diciembre de 2004, 19:08:00
El PIC es un 16f88, tengo puesto reloj interno de 4MHz, y aunque la frecuencia anda muy muy cerca de 1Hz, no lo clava (Más o menos cada 10 segundos, se retrasa 0.1 o asíGiño

Le he dado mil vueltas al código, que no tiene casi nada y no he visto nada.
A ver si alguien me hecha una mano.

Gracias.

// PROGRAMA PRINCIPAL
While (1)
{
   if (pasado1s)
   {
      pasado1s=0;
      salida=!salida;
    }
}

// LA INICIALIZACIÓN
void inicializar (void)
{
   set_tris_a(0x00);  
   set_tris_b(0xfe);  
   setup_oscillator(OSC_4MHZ);
   setup_ccp1(CCP_PWM);
   setup_timer_2(T2_DIV_BY_16,30,1); // PWM de 1Khz
   setup_counters(RTCC_INTERNAL,RTCC_DIV_4);
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RTCC);
   set_rtcc(5);
   set_pwm1_duty(200);
}

// LA INTERRUPCIÓN
#INT_RTCC
void int_reloj_1ms (void)        // Entra cada 1ms
{
   set_rtcc(5);
   InterrupcionTMR0=1;
   cont1ms++;              
   if(cont1ms == 5)
   {
      cont1ms=0;                          // Entra cada 5ms
      pasado5ms=1;              
      cont5ms++;                
      if(cont5ms==2)
      {
         pasado10ms=1;
         cont5ms=0;
         cont10ms++;
         if(cont10ms==100)
         {
            pasado1s=1;
            cont10ms=0;
         }
      }
   }
}
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: peddrorolo en 30 de Diciembre de 2004, 01:55:00
Hola Jon Gothen,
Saber que el reloj interno del pic no es muy exacto, pues varía con la temperatura, etc. Mira en el DS que te vendrá cual es la resolución máxima del reloj interno. Yo no uso el 16F88, pero uso el 16F648 con reloj interno y la precisión que da el fabricante es del 1% más o menos. Si a ti cada 10s se mueve 0,1; pues eso es el 1% de precisión.

Un saludo Pedro.
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: Falconhunter en 30 de Diciembre de 2004, 14:32:00
Prueba a poner un reloj externo de esos que son insensibles a la temperatura (Dallas tiene varios) de los que se utilizan para los circuitos RTC.

Feliz año nuevo
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: wqtrp en 30 de Diciembre de 2004, 17:55:00
hola, bueno no es para tanto señores, si bien tiene deriva con la temperatura y seguramente un reloj externo es mas preciso (y caro) no podemos tirar abajo asi a microchip con estos despues de todo tan solidarios chips.....

tu problema es mucho mas gordito y esta en el programa y por supuesto en el compilador ........

una pregunta: para q es la instruccion set_rtcc(5);  ?????

como para q no sea tan facil comenza a revisar por ahi y conta si ves algo ....

suerte y sigo leyendo
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: Arlequin en 30 de Diciembre de 2004, 18:39:00
Dado tu caso, yo pienso que lo mejor sería que realices el código en ASM.

Saludos, y Feliz Año.
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: JonGoten en 30 de Diciembre de 2004, 19:45:00
Suele hacer esas cosas raras el compilador? No pensaba que las jugaba tan mal...

Por otra parte, lo del 1% de precisión del reloj interno no suena tan descabellado...

Por otra parte, el set_rtcc(VALOR); lo que hace es poner en el registro el VALOR para que se cumpla esta fórmula

Tiempo_de_interrupción=4*RTCC_DIV*(255-VALOR)/Freloj
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: Nocturno en 31 de Diciembre de 2004, 01:27:00
¿Esa fórmula es correcta?, es que hay dos cosas que me resultan chocantes.

Por un lado, tal y como está expresada, el tiempo de interrupción será inversamente proporcional al Valor y tengo entendido que dicho tiempo debería aumentar conforme el Valor establecido en RTCC fuera más alto.

Por otro lado, si la dejamos como está, para un Valor de 255 el tiempo de interrupción sería 0, lo cual es imposible.

¿Lo puedes aclarar?
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: peddrorolo en 31 de Diciembre de 2004, 02:59:00
Hola a todos,
Vamos a intentar aclarar una cuestiones. Quiero dejar claro que a mi me encantan los micros de microchip, y los utilizo normalmente y en varias aplicaciones incluidas aplicaciones de radiofrecuencia yo uso el reloj interno del micro, concretamente del 16f648. Por otra parte quiero reiterar que para determinadas aplicaciones el reloj interno del micro es inexacto y no vale, por mucho que queramos defender a microchip, hay ocasiones en las que hay que poner un cristal y en otras de gran precisión. Para mi respuesta anterior solo me he basado en lo que dice microchip en su DS del 16F648,  donde indica la precisión del reloj interno del 1%, si lo que alguien necesita es mayor precisión, pues a joderse y poner un cristal.
Por otro lado, en cuanto a la formula del tiempo para producir una interrupción, pues a mi me parece que está correcto. Cuanto mayor es el valor de carga  del timer0, más corto es el tiempo entre una interrupción y otra, pues la interrupción por timer0 se produce cuando la cuenta del contador del timer0 pasa de FF a 00. Con lo cual si nosotros precargamos el valor de inicio de la cuenta cerca de FF, menos tiempo le queda de contar hasta desbordarse y producir la interrupción.
Si revisamos la fórmula escrita en un post anterior, tenemos que el "4" es por el fosc/4, osea que la entrada de reloj es la frecuencia del reloj que usemos dividida entre 4; luego le aplicamos el predividor del timer0, aparece multiplicando pues así aumentamos el tiempo de la oscilación o cuenta del timer0, por último la carga del timer0 o valor desde el cual va ha empezar a contar hasta que cuando llegue a FF se desborde.

Espero no haber sido muy pesado y haber aclarado algo.

Un saludo Pedro
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: Nocturno en 31 de Diciembre de 2004, 03:20:00
Si es así entonces está bien, pero yo pensaba que la cuenta del Timer0 era decreciente y desbordaba al llegar a 0.

¿Qué pasa entonces si ponemos Valor=255?
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: pocher en 31 de Diciembre de 2004, 03:22:00
Voy a dar una respuesta totalmente diferente a las anteriores.

Si quieres que un reloj no te atrase y escribes en C, no uses la interrupción. Solo por el hecho de entrar en ella ya se pierde tiempo y si encima metes varias instrucciones en la interrupción pués más todavía.

Mi consejo si quieres que un reloj no te atrase, ya sea con oscilador interno o externo es que no uses la interrupción y que detectes el desbordamiento del TMR0 en el programa principal usando la bandera T0IF.

Un saludo
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: pocher en 31 de Diciembre de 2004, 03:32:00
A otra cosa con un cristal de 4MHz no vas a conseguir una base de tiempos exacta. Debes cambiar a otro cristal con el que el cálculo de los números en la fórmula te salga clavado (sin un solo decimal).

Y por último otra cosa no hagas recargas del TMR0, deja que cuente el solito de 0 a 255, con el set_timer también se pierde tiempo.

Un saludo

PD. Manolo si cargas con 255, al sobrepasarlo se desborda, se activa T0IF y vuelve a empezar desde 0.
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: wqtrp en 31 de Diciembre de 2004, 08:32:00
hola, puedo yo de nuevo, ahora q veo q se anoto un monton de gente....
resulta q este es un tema del q ya se escribio bastante, por eso no quise ser tan directo en los puntos q a mi entender causan problemas....
empecemos de a uno...
1. cuando interrumpe el micro y llegas a la instruccion set_rtcc(5); ?????  cuanto te piensas q es el valor del tmr0 justo antes q le ponga el famoso 5(cinco) ??? te diria q lo ejecutes paso a paso o q lo emules y te sorprenderas, el compilador pone todo un overhead q uno si no lo mira bien, ni se entera, pero seguramente tendra un valor entre 20 y 50, siendo mas cerca de 50, dependiendo cuantas otras interrupciones utilices, asi q esto es un lindo chiste, ya tienes una valor de 50 y le pones un 5, zassss, un desastre...
2. por eso lo aconsejable si usas algo asi no es resetear el TMR0 , sino corregirlo, teniendo en cuenta q cuando lo esribas, perderas 2 ciclos de maquina, asi q lo mejor es SUMARLE un 5 a lo q ya tiene, porque la realidad es que el TMR0 no tiene un cero , eso ya lo paso hace rato... creo q debes sumarle no 5 sino 3 o 7, fijate bien el las especificaciones....
3. el otro problema q tienes es q usas un divisor por cuatro, entonces en el momento q sumas aun puedes tener un error de 4 en 1000

prueba con esto y cuentanos, veras q el error disminuye, ya no sera tan salvaje y para realmente verlo deberas esmerarte bastante...

Suerte y cuentanos un cacho mas....

perdon releyendo, acabo  de racapacitar q si divides por 4 , el trm0 tendra una valor dividido 4 tambien asi q sera entre 5 y 12 aprox..

Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: _Canito_ en 31 de Diciembre de 2004, 16:11:00
Hola a todos,

A mi me pasó lo mismo con el 16F627 (error en las temporizaciones con reloj interno a 4 Mhz).

Al incorporar el XT el problema se solucionó.


Un saludo
Jorge.
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: pocher en 01 de Enero de 2005, 01:19:00
Otra cosilla más. En la fórmula no es 255 si no 256. Entonces al aplicarla ya no te sale 1ms exacto. Si quieres buscar una base de tiempos exacta de 1s tendrás que abandonar los 4MHz
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: Nocturno en 01 de Enero de 2005, 12:26:00
Ahora sí que me encaja, con 255 no veía la manera. Gracias Pocher
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: Lager. en 01 de Enero de 2005, 17:45:00
Solo aclarando lo ya aclarado,: Esta formula es muy sencilla y te dice exactamente lo que necesitas,:
T. de DESBORDE= (4/Fosc)*(-TMR0)* N
Donde, N es el divisor de frecuencia, Fosc es el Xtal que usas y –TMR0 es  desde donde empiezas.
Ejemplo:
a)Xtal 20 mhz sin D.F.(divisor de frecuencia) con 175 pasos de conteo
(4/20,000000)*(175)*(1) =35 Us, OJO!!!!! Que no cargas ese valor a timer, sino su complemento =  Valor maximo CUANTITATIVO DE TMRX – (-TMRX)
=256-175= 81
por tanto:
set_timer0(81);        ß- esto es lo correcto, no al reves!!!!!!!!!!!!

b)Otro ejemplo
Xtal 4 mhz con 4 de D.F. con 5 pasos de conteo
(4/4,000000)* (5)*(4) =0.02 ms ~~~(256-5) : set_timer0(251)

c)Otro ejemplo
Xtal 4 mhz con 4 de D.F. con 251 pasos de conteo
(4/4,000000)* (251)*(4) =1.004 ms ~~~(256-251) : set_timer0(5)

d)Un  ejemplo mas para deshabilitar TODA interrupcion inesperada ene este post, jejeje.
Xtal 4 mhz con 4 de D.F. con 250 pasos de conteo
(4/4,000000)* (250)*(4) =1 ms ~~~(256-250) : set_timer0(6) <<--


Un abraso panas
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: pocher en 02 de Enero de 2005, 05:46:00
Si se usa la instrucción de recarga del TMR0, set_rtcc(6), al descomponerse esta instrucción en instrucciones en ensamblador se pierde tiempo, durante el cual no cuenta el TMR0.

Aunque parezca mentira fijaros lo importante que es que no se pierdan microsegundos:

Para un retraso de 10us en 4ms ----> 2,5ms en 1s ----> 150ms en 1minuto ----> 9s en 1h ----> 3,6minutos en 1día ..... sin comentarios.

Un saludo

PD. Usar por ejemplo un cristal de 3,2768MHz, no usar interrupción y no hacer recarga del TMR0 sería la solución
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: Lager. en 02 de Enero de 2005, 11:35:00
Asi es pocher, de hecho para ser precisos, son 2 ciclos de instruccion por cada cargado del Registro, mas lo que añada CADA compilador( epa! loco  ) .

Salu2 panas
Título: RE: Este sencillo código no cuenta cada segundo exacto, pq?
Publicado por: JonGoten en 04 de Enero de 2005, 20:19:00
Como bien dice pocher he hecho mal los cálculos. En la fórmula es 256 (de 0 a 255) y no 255 como yo ponia.
Eso sumado a la pérdida de instrucciones y al error del oscilador interno, pues es lo que me provocaba ese pequeño error.

De todas formas, no puedo comprobarlo porque ya no dispongo del hardware con el que hacia las pruebas.