Autor Tema: timer1 no desborda cuando espero...  (Leído 3982 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado LoPiTaL

  • PIC12
  • **
  • Mensajes: 73
timer1 no desborda cuando espero...
« en: 06 de Diciembre de 2007, 15:37:54 »
Después de empacharme de datasheet, buscar info por el foro y tal no he conseguido hacer que el timer1 desborde cuando yo quiero... :(

A ver si mi deducción es correcta:

Uso el oscilador interno del pic 18f2550 (8 MHz), uso el prescaler por 2, y por tanto se produce un tick del reloj cada 1 us (8 MHz/4/2=1 MHz-> T= 1 us). Quiero que desborde cada 400 us, generando así una interrupción, por lo que deberá hacer 400 ticks (1 us * 400=400 us) antes de desbordar. Por tanto, deberé cargar el timer1 a 65536-400=61536. De esta forma, cada 400 us desbordará el timer1 ¿verdad? Sin embargo, no lo consigo, desborda cada 60 y pico ms..... Os dejo el código por si lo hiciese mal.

El código es un receptor serie, detecta el bit de start con la interrupción del puerto B y después deshabilita dicha interrupción, activa la del timer y recibe el dato. Una vez recibido todo el dato, se desactiva el timer y se reactiva la interrupción del puerto para volver a recibir otro dato.
El timer0 lo utilizo simplemente para comprobar que el pic funciona, haciendo parpadear un led cada cierto tiempo (no lo he calculado :D, ya que no es importante).
Citar

#include <18F2550.h>               //pic a utilizar   

int orden=0, aux;

void ejecutaOrden();

#fuses INTRC_IO,NOWDT,NOPROTECT,PUT      //ordenes para el programador
#use delay (internal=8M)         //Fosc=8 Mhz interno
#use fast_io(b)
#use fast_io(c)

long int contador_led=0;
int contador_reloj=0;

#INT_RB
void bit_start(){         //Tras simularlo con el ISIS, vemos que con un periodo de reloj de 400 us le da tiempo
                     //al micro a detectar la interrupción. Ésta interrupción salta cuando llega el bit_start
                     //Después se desactiva, tras activar la interrupción del timer1.
   if (input_state(PIN_B7)){      //En el semiciclo positivo del reloj....
      contador_reloj=0;
      disable_interrupts(INT_RB);
      disable_interrupts(GLOBAL);
      setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
      set_timer1(61536);      //f=8MHz -> f/4/2=1 MHz-> T=1 us. Para que cuente 400 us: 65536-400=61536.
                        //Contamos 400 us, para detectar los pulsos correctos.

      enable_interrupts(INT_TIMER1);
      enable_interrupts(INT_TIMER0);
      enable_interrupts(GLOBAL);

   }
}

#INT_TIMER0
void interrupcion(){
   contador_led++;
   if (contador_led==488){            //¿?
      contador_led=0;
      output_toggle(PIN_C0);
   }      
   set_timer0(5);            //Recargamos el timer.
}

#INT_TIMER1
void interrupcion1(){
   contador_reloj++;
   orden=orden<<1;
   aux=input_state(PIN_B7);
   orden=orden+aux;
   
   if (contador_reloj==8){      //Si terminamos de recibir el dato, nos preparamos para un nuevo bit de start y ejecutamos la orden.
      contador_reloj=0;
      disable_interrupts(INT_TIMER1);
      enable_interrupts(INT_RB);
      ejecutaOrden();
   }
   set_timer1(61536);
}


//PROGRAMA
void main(void)
{
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2|RTCC_8_BIT);   //Dado que la frecuencia del timer viene dada por:
                                    //f(8MHz)/4/2(RTCC_DIV_2)=1MHz cada cuenta. Tiene 255 cuentas,
                                    //por lo que creará una interrupción cada 255 us
   set_timer0(5);                        //cargamoss un 5 para que desborde cada 250 us.


   set_tris_c(0x00);
      set_tris_b(0b10000001);   //portb como toca
   output_low(PIN_B1);
   output_low(PIN_B2);
   output_low(PIN_B3);
   output_low(PIN_B4);
   output_low(PIN_B5);
   output_low(PIN_B6);
   output_c(0x00);

   enable_interrupts (INT_RB);
   enable_interrupts(INT_TIMER0);
   enable_interrupts (GLOBAL);

    do{                           //Si es una orden lenta, se va ejecutando en el bucle infinito.
   }while (1);   //Bucle infinito
}

void ejecutaOrden(){
   if ((orden & 0b10000000)==0){      //Si es una orden ejecutable en el acto, se ejecuta aquí y se resetea la orden
      switch (orden){
      case 1:   output_toggle(PIN_B1);
            break;
      case 2: output_toggle(PIN_B2);
            break;
      default: break;
      }
      orden=0;
   }
}

Gracias de antemano por vuestra ayuda, estoy aprendiendo muchísimo con vuestro foro,

LoPiTaL
Hoy soy yo quién pregunta. Mañana seré quien conteste...

Desconectado Rulo

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 168
Re: timer1 no desborda cuando espero...
« Respuesta #1 en: 06 de Diciembre de 2007, 15:47:17 »

    Pues no he hecho los calculos, pero podrias utilizar herramientas como el timer pic calculator de Red Pic para hacer los calculos.


          http://www.todopic.com.ar/foros/index.php?topic=19454.msg140548#msg140548



              saludos

Desconectado jfh900

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3595
Re: timer1 no desborda cuando espero...
« Respuesta #2 en: 06 de Diciembre de 2007, 16:03:13 »
En las subrutinas de interrupción hay que poner el menor código posible.

Por otra parte en una interrupción no tienes que reinicializar los timer de echo yo dejaría el código así:

Código: [Seleccionar]
void bit_start(){         //Tras simularlo con el ISIS, vemos que con un periodo de reloj de 400 us le da tiempo
                     //al micro a detectar la interrupción. Ésta interrupción salta cuando llega el bit_start
                     //Después se desactiva, tras activar la interrupción del timer1.
   if (input_state(PIN_B7)){      //En el semiciclo positivo del reloj....
      contador_reloj=0;
      set_timer1(61536);      //f=8MHz -> f/4/2=1 MHz-> T=1 us. Para que cuente 400 us: 65536-400=61536.
                        //Contamos 400 us, para detectar los pulsos correctos.
   }
}

El resto de código se pone en el comienzo del main para inicializar y no se vuelve a repetir.

Un saludo
* Cuando hables, procura que tus palabras sean mejores que el silencio.
* 'Todos somos ignorantes, lo que ocurre es que no todos ignoramos las mismas cosas.' Albert Einstein.
* No hay nada peor que un experto para evitar el progreso en un campo
* "La vida es como una novela. No importa que sea larga, sino que esté bien narrada" Seneca
* La vida no se vive por las veces que respiras, sino por los momentos que dejan sin aliento.
* Dios dijo: ∇·E=ρ/ε0 ; ∇·B=0 ; ∇xE=-dB/dt ; ∇xB= μ0ε0dE/dt..y la luz se hizo..!!..

Desde España Jesús

Desconectado LoPiTaL

  • PIC12
  • **
  • Mensajes: 73
Re: timer1 no desborda cuando espero...
« Respuesta #3 en: 06 de Diciembre de 2007, 20:20:08 »
Vale, creo que voy a hacer lo que dice jfh, a ver si con eso lo soluciono. Pero ahora me surge un problema: ¿cómo inicializo el timer? ¿Cuando entro en la interrupción pongo a true una variable booleana para que en el main se active el timer? Mañana haré más pruebas a ver qué sale.... En cuanto a lo del cálculo del timer creo que lo hice bien, pero probaré la aplicación esa a ver si sale lo que yo he calculado. También lo haré mañana, ahora me he pasado con el ron y no es plan de jugar a estas horas :D jeje

Mañana pruebo y ya os vuelvo a preguntar si no lo consigo,

LoPiTaL
Hoy soy yo quién pregunta. Mañana seré quien conteste...

Desconectado juanelete

  • PIC12
  • **
  • Mensajes: 74
Re: timer1 no desborda cuando espero...
« Respuesta #4 en: 07 de Diciembre de 2007, 05:55:13 »
Hola LoPiTaL

Hechando un vistazo por encima, el fallo mas importante que veo es que llamas a la funcion ejecutaOrden() desde dentro de la INT, deberias activar un flag y llamarla desde el main(), aparte de eso veo tambien que no es necesario configurar el timer1 cada vez, ni desactivar las INT, ya que la INT timer0 es compatible con la otra y pueden convivir, en cuanto a la INT timer1, una vez que se desborda, tienes 65536 us (una eternidad) antes de que vuelva a desbordarse otra vez, es mas podrias utilizar esto para detectar que no estas recibiendo datos y generar el correspondiente error.


Yo lo dejaria asi:

Citar

#include <18F2550.h>               //pic a utilizar   

int orden=0, aux;

void ejecutaOrden();

#fuses INTRC_IO,NOWDT,NOPROTECT,PUT      //ordenes para el programador
#use delay (internal=8M)         //Fosc=8 Mhz interno
#use fast_io(b)
#use fast_io(c)

long int contador_led=0;
int contador_reloj=0;
int1 flag_ejecutaOrden=0;      //Indica cuando he recibido una orden y tengo que procesarla

#INT_RB
void bit_start(){         //Tras simularlo con el ISIS, vemos que con un periodo de reloj de 400 us le da tiempo
                     //al micro a detectar la interrupción. Ésta interrupción salta cuando llega el bit_start
                     //Después se desactiva, tras activar la interrupción del timer1.
   if (input_state(PIN_B7)){      //En el semiciclo positivo del reloj....
      contador_reloj=0;
     
      set_timer1(61536);      //f=8MHz -> f/4/2=1 MHz-> T=1 us. Para que cuente 400 us: 65536-400=61536.
                                       //Contamos 400 us, para detectar los pulsos correctos.
   }
}

#INT_TIMER0
void interrupcion(){
   contador_led++;
   if (contador_led==488){            //¿?
      contador_led=0;
      output_toggle(PIN_C0);
   }     
   set_timer0(5);            //Recargamos el timer.
}

#INT_TIMER1
void interrupcion1(){
   contador_reloj++;
   orden=orden<<1;
   aux=input_state(PIN_B7);
   orden=orden+aux;
   
   if (contador_reloj==8)      //Si terminamos de recibir el dato, nos preparamos para un nuevo bit de start y ejecutamos la orden.
      flag_ejecutaOrden=1;
   
   set_timer1(61536);
}


//PROGRAMA
void main(void)
{
   delay_ms(300);          //Le damos algo de tiempo al micro para que se estabilice
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);

   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2|RTCC_8_BIT);   //Dado que la frecuencia del timer viene dada por:
                                    //f(8MHz)/4/2(RTCC_DIV_2)=1MHz cada cuenta. Tiene 255 cuentas,
                                    //por lo que creará una interrupción cada 255 us

   set_tris_c(0x00);
      set_tris_b(0b10000001);   //portb como toca

   delay_ms(100);           //Otro poquito mas de tiempo antes de meternos en faena

   output_low(PIN_B1);
   output_low(PIN_B2);
   output_low(PIN_B3);
   output_low(PIN_B4);
   output_low(PIN_B5);
   output_low(PIN_B6);
   output_c(0x00);

   enable_interrupts (INT_RB);
   enable_interrupts(INT_TIMER0);
   enable_interrupts (GLOBAL);

   set_timer0(5);                        //cargamoss un 5 para que desborde cada 250 us.

    do{                           //Si es una orden lenta, se va ejecutando en el bucle infinito.

        if (flag_ejecutaOrden==1) ejecutaOrden();

   }while (1);   //Bucle infinito
}

void ejecutaOrden(){
   if ((orden & 0b10000000)==0){      //Si es una orden ejecutable en el acto, se ejecuta aquí y se resetea la orden
      switch (orden){
      case 1:   output_toggle(PIN_B1);
            break;
      case 2: output_toggle(PIN_B2);
            break;
      default: break;
      }
      orden=0;
      flag_ejecutaOrden=0;             // Orden ejecutada, esperando nueva orden
   }
}

Espero que te sirva de algo...  :mrgreen:

Saludos

Desconectado LoPiTaL

  • PIC12
  • **
  • Mensajes: 73
Re: timer1 no desborda cuando espero...
« Respuesta #5 en: 07 de Diciembre de 2007, 14:33:04 »
Después de un montón de problemas con internet he conseguido entrar al foro, por fin!!!

Gracias por la respuesta juanelete, pero como no he podido entrar hasta ahora, me he rehecho el programa usando en lugar del timer1 el timer0, y ahora me va bien. También creo haber visto el error de por qué en la simulación con el ISIS no desbordaba cuando esperaba: en el ISIS hay un parámetro de los pic con oscilador interno que es "Processor Clock Frecuency" que por defecto está a 4 MHz (y yo trabajaba con el oscilador interno a 8 MHz) y por eso me salía un periodo del timer distinta a la que había calculado yo.

Por si le interesa a alguien un programa de recepción serie a un cable, lo copio aquí. Ya no uso la interrupción del puerto B, sino la interrupción externa por flanco de subida, que viene mejor para lo que quería.

Citar
//La conexión será a un solo cable, que estará conectado en el pin 7 del puerto B. Se transmite primero un bit de start,
//de 200 us a nivel bajo, 200 us a nivel alto y 200 us a nivel bajo (de esta forma nos aseguramos que hay transiciones de bajo a alto).
//Después se transmiten los bits de 400 us en 400 us, es decir, a una tasa binaria de 2500 bps.
//Los LEDs estan en los pines 1 y 2 del puerto B.
//Versión 2: Para una orden ejecutable en el acto, el bit 7 estará a 0 y se ejecutará en ejecutaOrden.
//     Para una orden que tarda en ejecutarse (avanza,gira,etc...) este bit estará a 1, y se ejecutará en el main.


#include <18F2550.h>               //pic a utilizar   

void ejecutaOrden();

#fuses INTRC_IO,NOWDT,NOPROTECT,PUT      //ordenes para el programador
#use delay (internal=8M)         //Fosc=8 Mhz interno
#use fast_io(b)
#use fast_io(c)

int orden=0, orden_aux=0, aux=1;
int contador_reloj=0,contador_datos=0;
boolean activa_timer=false, desactiva_timer=false, bit_stop=false;

#INT_EXT
void bit_start(){         //Tras simularlo con el ISIS, vemos que con un periodo de reloj de 400 us le da tiempo
                     //al micro a detectar la interrupción. Ésta interrupción salta cuando llega el bit_start
                     //Después se desactiva, tras activar la interrupción del timer1.
   if (input_state(PIN_B0)){      //En el semiciclo positivo del bit de start...
      contador_reloj=0;
      activa_timer=true;
   }
   /*if (bit_stop==true)      //Acabamos de recibir el bit de stop, que es 200 us a 1 y 200 us a 0.
      bit_stop=false;*/
}

#INT_TIMER0
void interrupcion(){
   set_timer0(70);
   contador_reloj++;
   if (contador_reloj==2){
      contador_reloj=0;
      contador_datos++;
      if (input_state(PIN_B0))
         orden_aux=orden_aux+aux;
      aux=aux<<1;
      
      if (contador_datos==8){      //Si terminamos de recibir el dato, nos preparamos para un nuevo bit de start y ejecutamos la orden.
         contador_datos=0;
         orden=orden_aux;
         orden_aux=0;
         desactiva_timer=true;
         //bit_stop=true;         //Activamos el flag indicador de que falta aún el bit de stop.
         aux=1;               //Reseteamos aux.
         ejecutaOrden();
      }
   }
}

//PROGRAMA
void main(void)
{
      set_tris_b(0b10000001);   //portb como toca
   output_low(PIN_B1);
   output_low(PIN_B2);

   ext_int_edge(L_TO_H);         //Se producirá interrupción cuando se detecte transición de bajo a alto en el pin RB0.

   enable_interrupts (INT_EXT);
   enable_interrupts (GLOBAL);

    do{                           //Si es una orden lenta, se va ejecutando en el bucle infinito.

      //AQUÍ CONFIGURAMOS LAS INTERRUPCIONES, EN FUNCIÓN DE QUÉ RECIBIMOS, SI EL BIT DE START O UN DATO NORMAL.
      if (activa_timer){
         activa_timer=false;

         disable_interrupts(INT_EXT);
         disable_interrupts(GLOBAL);
         setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2|RTCC_8_BIT);   //Dado que la frecuencia del timer viene dada por:
                                    //f(8MHz)/4/2(RTCC_DIV_2)=1MHz cada cuenta. Tiene 255 cuentas,
                                    //por lo que creará una interrupción cada 255 us
         set_timer0(56);                        //cargamoss un 55 para que desborde cada 200 us.
         clear_interrupt(int_timer0);            //Limpiamos el flag de interrupción, por si mientras hacíamos
                                          //otra cosa ha desbordado el timer.
   
         enable_interrupts(INT_TIMER0);
         enable_interrupts(GLOBAL);
      }

      if (desactiva_timer){
         desactiva_timer=false;

         disable_interrupts(INT_TIMER0);
         disable_interrupts(GLOBAL);

         ext_int_edge(L_TO_H);
         clear_interrupt(int_ext);            //Lo mismo para la otra interrupción.
         enable_interrupts(INT_EXT);
         enable_interrupts(GLOBAL);
      }

      //FINALMENTE, EJECUTAMOS LAS ÓRDENES LENTAS:
   }while (1);   //Bucle infinito
}

void ejecutaOrden(){
   if ((orden & 0b10000000)==0){      //Si es una orden ejecutable en el acto, se ejecuta aquí y se resetea la orden
      switch (orden){
      case 1:   output_toggle(PIN_B1);
            break;
      case 2: output_toggle(PIN_B2);
            break;
      default: break;
      }
      orden=0;
   }
}


Gracias a todos por la ayuda y la rapidez de las respuestas, yo sigo con mi proyecto de cuadrúpedo y casi seguro que vuelva a preguntar... Aún tengo que probar si funciona físicamente la transmisión estación_base - cerebro.... Si os interesa la estación base está conectada via USB con el PC y con este protocolo a un hilo con el cerebro. El código anterior se corresponde con el del cerebro del robot.
 Ya os contaré mis avances....

LoPiTaL
Hoy soy yo quién pregunta. Mañana seré quien conteste...


 

anything