Autor Tema: Manejo del TIMER0 desde el CCS  (Leído 15324 veces)

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

Desconectado NoSepComo

  • PIC18
  • ****
  • Mensajes: 305
Manejo del TIMER0 desde el CCS
« en: 25 de Febrero de 2011, 07:01:48 »
Hola a todos,
sigo en mi aventura de aprender a usar bien esto de los PICs, ahora necesito hacer un programita que utilice los timer, estoy haciendo una prueba que arranca el timer 0 y en el programa principal, lo que quiero es que cuando active una patita, se encienda un LED y a los 5 segundos (si la entrada está desactivada ya), se apague el sólo.
Entonces, lo estoy haciendo con una subrutina del TIMER0_isr, que realiza cuentas, pero tengo un problema que me dice que se desborda la pila del PIC, y eso no sé porqué pasa, entiendo que lo que le pasa es que hace muchas llamadas y se desborda la pila, pero, aún dejando sólo el timer, sin hacer nada en el programa principal, me pasa.

Gracias de antemano por vuestra ayuda

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Manejo del TIMER0 desde el CCS
« Respuesta #1 en: 25 de Febrero de 2011, 09:30:00 »
  Lo ideal sería que muestres el programa, porque así "en el aire" es imposible saber cual puede ser el problema.
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado NoSepComo

  • PIC18
  • ****
  • Mensajes: 305
Re: Manejo del TIMER0 desde el CCS
« Respuesta #2 en: 25 de Febrero de 2011, 09:52:14 »
Hola Angel, te lo muestro encantado:

#include <18f45k20.h>
#fuses XT,NOWDT
#use delay(clock=4000000)
#byte TRISA=0xF92
#byte PORTA=0xF80

#int_TIMER0

int cuentas = 0;
void TIMER0_isr(void) {
   cuentas ++;
   if(cuentas == 200)
   {
   bit_clear(PORTA,0);
   cuentas = 0;
   }
   set_timer0 (0x3C);  }               //Se recarga el timer0
   
void main() {
  setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);   //Configuración timer0

  set_timer0 (0x3C);                    //Carga del timer0
  enable_interrupts(INT_TIMER0);       //Habilita interrupción timer0
  enable_interrupts(global);           //Habilita interrupción general
 
  TRISA=0x10;
  PORTA=0x00;
 

  while (1)
  {
      if(bit_test(PORTA,4)==1)
      {
         set_timer0(0x3C);
         bit_set(TRISA,4);
      }
  };
}

Ese es el código completo de un ejemplillo tonto que trato de hacer, yo creo quue mi problema viene de que meto código muy pesado en la isr y no le da tiempo a resolverlo antes de la siguiente interrupción y se me colapsa, pero no se, como te digo soy nuevo y ni idea.
¿Alguna idea?
Gracias por vuestras respuestas.

Desconectado NoSepComo

  • PIC18
  • ****
  • Mensajes: 305
Re: Manejo del TIMER0 desde el CCS
« Respuesta #3 en: 25 de Febrero de 2011, 09:57:15 »
Hola otra vez,
Es sólo para hacer una aclaración tonta, donde pone bit_set(TRISA,4) en realidad es con (PORTA,4), que lo copie mal, pero ahí no está mi problema.
Gracias

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Manejo del TIMER0 desde el CCS
« Respuesta #4 en: 25 de Febrero de 2011, 10:07:43 »
  No sé como implemente CCS las llamadas a la interrupción.
  Un desbordamiento de pila podría llegar a ser algo así.... (muestro un código en asm para que se entienda mejor)

Código: ASM
  1. rutina
  2.  .........
  3. .........
  4. .......
  5. call rutina
  6. return
  7.  
  8. main
  9. ........
  10. ..........
  11. call rutina

  ...entonces lo que ocurre es que se llama a la propia rutina dentro de sí misma y el stack del pic supera los niveles que tiene disponible.

  No sé si ése sera tu caso.

  Pasando a tu programa, veo que estás definiendo una variable inmediatamente después de la sentencia

Código: C
  1. #int_TIMER0

  Probá definir la variable antes, tal vez así como tenés el código este generando alguna falla en el compilador.
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado NoSepComo

  • PIC18
  • ****
  • Mensajes: 305
Re: Manejo del TIMER0 desde el CCS
« Respuesta #5 en: 25 de Febrero de 2011, 10:32:16 »
Hola,
Probando he logrado ver, que si quito la variable int cuentas y sus referencias, no se desborda.
No se porque será, epro esque si quiero que la vea la rutina la tengo que escribir fuera, porque para legar al número de cuentas que hacen un segundo la necesito.
Agradecería algún ejemplo si tenéis en CCS para manejar el TIMER0.
Gracias y un saludo.

Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: Manejo del TIMER0 desde el CCS
« Respuesta #6 en: 25 de Febrero de 2011, 10:56:32 »
Hola NoSepComo, con el oscilador a 4Mhz y la configuración que tienes de Timer0, se te estaría desbordando más o menos cada 20 Segundos, porque asi como lo tienes, está configurado como un timer de 16 bits.  Uno de los problemas que veo que tienes es que dentro del while(), estás reiniciando constantemente el valor de inicio de Timer0, por lo que nunca se va a desbordar.  Otro de los problemas que veo, es que no tienes bien declarada la rutina de interrupción:
Código: C
  1. #int_TIMER0
  2.  
  3. int cuentas = 0;
  4. void TIMER0_isr(void) {
  5.    cuentas ++;
  6.    if(cuentas == 200)
  7.    {
  8.    bit_clear(PORTA,0);
  9.    cuentas = 0;
  10.    }
  11.    set_timer0 (0x3C);  }               //Se recarga el timer0
y debería ser:
Código: C
  1. #int_TIMER0
  2. void TIMER0_isr(void) {
  3.    int cuentas = 0;
  4.    
  5.    cuentas ++;
  6.    if(cuentas == 200)
  7.    {
  8.    bit_clear(PORTA,0);
  9.    cuentas = 0;
  10.    }
  11.    set_timer0 (0x3C);  }               //Se recarga el timer0

Para este caso no veo la necesidad de declarar TRISA y PORTA.  Creo que mejor podrías utilizar output_high(pin) y output_low(pin) en donde pin sería por ejemplo PIN_A0

Reconfigura el temporizador para lograr lo 5 segundos que quieres y simplemente al detectar que se pulsó el botón en la entrada A4, activas una bandera que tendrá efecto dentro de la interrupción, que a su vez activa otra bandera indicando que está contando los 5 segundos.  Cuando el while() vea que la bandera de temporización está está activa, enciende el led y cuando termina el tiempo, desactivas la bandera y apagas el led.

Es lo que veo por el momento, si veo algo más te cuento.

Saludos!

Desconectado NoSepComo

  • PIC18
  • ****
  • Mensajes: 305
Re: Manejo del TIMER0 desde el CCS
« Respuesta #7 en: 25 de Febrero de 2011, 10:59:32 »
Muchas gracias, has dado en en el clavo con todo bmb.
Ahora se acabo lo de currar hasta el Lunes, asi que el Lunes os comento que pasó.
Gracias por vuestros aportes y un saludo a todos.

Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: Manejo del TIMER0 desde el CCS
« Respuesta #8 en: 25 de Febrero de 2011, 11:39:42 »
Hola, acabo de ver otro problema y es que al tener declarado a int cuentas = 0; dentro de la misma rutina de interrupción, cada que entre a esta, cuentas volverá a ser 0.  Sería mejor declararla como variable global.

Saludos!

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Manejo del TIMER0 desde el CCS
« Respuesta #9 en: 25 de Febrero de 2011, 11:53:47 »
Hola, acabo de ver otro problema y es que al tener declarado a int cuentas = 0; dentro de la misma rutina de interrupción, cada que entre a esta, cuentas volverá a ser 0.  Sería mejor declararla como variable global.

Saludos!

  Exacto, por eso yo le sugería que pruebe definir la variable antes de la línea

Código: C
  1. #int_TIMER0

  En ANSI C también se podría definir de la siguiente manera, pero no se si CCS lo permita, dentro de la rutina de interrupción

Código: C
  1. estatic int cuentas;

  de esa manara la definimos localmente, pero su valor no se pierda al salir de la rutina
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado KALLITOS

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1256
Re: Manejo del TIMER0 desde el CCS
« Respuesta #10 en: 25 de Febrero de 2011, 12:12:10 »
Hola NoSepComo.
Hola a todos,
sigo en mi aventura de aprender a usar bien esto de los PICs

Para que leas un poco sigue ESTE HILO

Saludos
A un microcontrolador hay que sacarle hasta el ultimo byte....(YO)

Cómo puede ser que un pic24EP512 me quede corto de memoria, señores de MICROCHIP saquen pics con más memoria flash

Más de 45 mil lineas de codigo y aun no termino el equipo, asu mare!!

S34ML08G1TFI200 no necesito mas memoria externa.

Desconectado NoSepComo

  • PIC18
  • ****
  • Mensajes: 305
Re: Manejo del TIMER0 desde el CCS
« Respuesta #11 en: 28 de Febrero de 2011, 05:19:43 »
Hola a todos, Gracias por vuestras respuestas lo primero.
Bueno ya volvió a empezar la semana y he vuelto a enfrentarme a esto del timer, con lo que me dijo bmb pensé que se solucionaría, pero no,
he conseguido que no se me desborde la pila, ya que yo no situaba la rutina del timer justo debajo de definir #int_TIMER0, sin embargo, ahora no hace lo que debería hacer la rutina nunca.
Os copio el código a ver si a alguien de vosotros se le ocurre algo de porque no funciona bien, que seguro que es por algún error tonto por mi parte, pero no lo veo :P.

#include <18f45k20.h>
#fuses XT,NOWDT,NOPROTECT,PUT,NOLVP
#use delay(clock=4000000)
#byte TRISA=0xF92
#byte PORTA=0xF80
#byte TRISB=0xF93
#byte PORTB=0xF81

int cuentas;
int pulsado = 0;

#int_TIMER0
void TIMER0_isr(void)
{
   if(pulsado == 1)
   {
      cuentas++;
      if(cuentas == 100)
      {
         cuentas = 0;
         bit_clear(PORTA,0);
         //output_low(PIN_A0);
         pulsado = 0;
         bit_set(PORTB,7);
      }
   }
   set_timer0 (0x3C);
}




void main() {


  setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);   //Configuración timer0

  set_timer0 (0x3C);                    //Carga del timer0
  enable_interrupts(global);           //Habilita interrupción general
  enable_interrupts(INT_TIMER0);       //Habilita interrupción timer0

 
  TRISA=0x10;
  PORTA=0x00;
  TRISB=0x00;
  PORTB=0x00;
 

  while (1)
  {
      if(bit_test(PORTA,4)==1)
      {
         if(pulsado == 0)
         {
            cuentas = 0;
            bit_set(PORTA,0);
            set_timer0(0x3C);
            pulsado = 1;
         }
      }
  }
}

Gracias por vuestro tiempo y un saludo.

Desconectado NoSepComo

  • PIC18
  • ****
  • Mensajes: 305
Re: Manejo del TIMER0 desde el CCS
« Respuesta #12 en: 28 de Febrero de 2011, 08:05:39 »
Hola a todos de nuevo,
He conseguido solventar mi problema, os lo cuento por si alguien alguna vez se tiene que enfrentar a él.
Yo estaba utilizando las funciones para manejar timers que vienen en el CCS (setup_timer_0()...). El problema es que esas funciones están definidas para un 16f (o eso creo) por defecto, debe de existir alguna forma de adaptarlo a otro pic pero yo la desconozco.
Lo que he hecho ha sido tocar directamente el T0CON, definiendolo al inicio con la directiva #byte T0CON=0xfd5 y después asignándole el valor en binario para configurarlo.
Gracias a todos por vuestras respuestas, si alguien conociese la forma de programar los timers con el 18 desde CCs se lo agradecería o que me pudiese aconsejar algún manual o algo para programar PIC18 desde CCs.
Un saludo.

Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: Manejo del TIMER0 desde el CCS
« Respuesta #13 en: 28 de Febrero de 2011, 10:13:15 »
... He conseguido solventar mi problema, os lo cuento por si alguien alguna vez se tiene que enfrentar a él.
Yo estaba utilizando las funciones para manejar timers que vienen en el CCS (setup_timer_0()...). El problema es que esas funciones están definidas para un 16f (o eso creo) por defecto, debe de existir alguna forma de adaptarlo a otro pic pero yo la desconozco ...

Hola NoSepComo, me alegra que lo tengas funcionando ahora, aunque si escogiste el CCS para programar, creo que estás desaprovechando sus funciones incorporadas que son las que nos facilitan la programación.  En CCS los temporizadores se programan más o menos de la misma manera para todos los PICs, solo que hay que tener en cuenta si el temporizador es de 8 o 16 bits para su configuración.

...con lo que me dijo bmb pensé que se solucionaría, pero no, he conseguido que no se me desborde la pila, ya que yo no situaba la rutina del timer justo debajo de definir #int_TIMER0, sin embargo, ahora no hace lo que debería hacer la rutina nunca.

Bueno, no fué solo lo del Timer, también te faltó esto:

...Para este caso no veo la necesidad de declarar TRISA y PORTA.  Creo que mejor podrías utilizar output_high(pin) y output_low(pin) en donde pin sería por ejemplo PIN_A0

Reconfigura el temporizador para lograr lo 5 segundos que quieres y simplemente al detectar que se pulsó el botón en la entrada A4, activas una bandera que tendrá efecto dentro de la interrupción, que a su vez activa otra bandera indicando que está contando los 5 segundos.  Cuando el while() vea que la bandera de temporización está está activa, enciende el led y cuando termina el tiempo, desactivas la bandera y apagas el led...

... lo que quiero es que cuando active una patita, se encienda un LED y a los 5 segundos (si la entrada está desactivada ya), se apague el sólo...

Usando el 'PICWizard' que viene con el CCS te hice un programita de muestra para lo que necesitabas, para que te hagas a una idea de lo fácil que es:

Código: C
  1. // En general:
  2. // clock = 4000000 Hz
  3. // Tosc = (1 / clock)
  4. //
  5. // Tiempo = 4 x Tosc x Valor a contar en Timer0 + 1 x Rango del Divisor
  6. // Tiempo = 4 x 0.00000025 x 196 x 256 = 50.17mS        // Timer 8 bits a 4MHz
  7. // Valor de inicio para Timer0 = 256 - 196 = 60
  8.  
  9. #include <18F45K20.h>
  10. #device adc=8
  11.  
  12. #FUSES NOWDT                    //No Watch Dog Timer
  13. #FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
  14. #FUSES XT                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
  15. #FUSES NOPROTECT                //Code not protected from reading
  16. #FUSES NOBROWNOUT               //No brownout reset
  17. #FUSES BORV18
  18. #FUSES NOPUT                    //No Power Up Timer
  19. #FUSES NOCPD                    //No EE protection
  20. #FUSES NOSTVREN                 //Stack full/underflow will not cause reset
  21. #FUSES NODEBUG                  //No Debug mode for ICD
  22. #FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
  23. #FUSES NOWRT                    //Program memory not write protected
  24. #FUSES NOWRTD                   //Data EEPROM not write protected
  25. #FUSES NOIESO                   //Internal External Switch Over mode disabled
  26. #FUSES NOFCMEN                  //Fail-safe clock monitor disabled
  27. #FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
  28. #FUSES NOWRTC                   //configuration not registers write protected
  29. #FUSES NOWRTB                   //Boot block not write protected
  30. #FUSES NOEBTR                   //Memory not protected from table reads
  31. #FUSES NOEBTRB                  //Boot block not protected from table reads
  32. #FUSES NOCPB                    //No Boot Block code protection
  33. #FUSES NOLPT1OSC                //Timer1 configured for higher power operation
  34. #FUSES MCLR                     //Master Clear pin enabled
  35. #FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
  36. #FUSES NODELAYINTOSC        
  37. #use delay(clock=4000000)
  38.  
  39. int1 contando = false, temporizar = false;
  40. int cuentas = 0;
  41.  
  42. #int_TIMER0
  43. void  TIMER0_isr(void)
  44. {
  45.    if(temporizar)
  46.    {
  47.       contando = true;
  48.       cuentas ++;
  49.       if(cuentas == 100)         // 50 mS x 100 = 5 Seg. aprox.
  50.       {
  51.          contando = false;
  52.          temporizar = false;
  53.          cuentas = 0;
  54.       }
  55.    }
  56. set_timer0 (60);               //Se recarga el timer0
  57. }
  58.  
  59.  
  60. void main()
  61. {
  62.    setup_adc_ports(NO_ANALOGS|VSS_VDD);
  63.    setup_adc(ADC_CLOCK_DIV_2|ADC_TAD_MUL_0);
  64.    setup_spi(SPI_SS_DISABLED);
  65.    setup_wdt(WDT_OFF);
  66.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_bit);  // 8bits 65,5 mSeg aprox.
  67.    setup_timer_1(T1_DISABLED);
  68.    setup_timer_2(T2_DISABLED,0,1);
  69.    setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
  70.    setup_ccp1(CCP_OFF);
  71.    setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
  72.    enable_interrupts(INT_TIMER0);
  73.    enable_interrupts(GLOBAL);
  74.  
  75.    while (true)
  76.    {
  77.       if(!input(PIN_A4))      // Asumiendo que el pin A4 tiene una resistencia pullup ...
  78.       {
  79.          temporizar = true;
  80.          set_timer0 (60);                    //Carga del timer0
  81.       }
  82.      
  83.       if(contando)
  84.          output_high(PIN_A0);
  85.       else
  86.          output_low(PIN_A0);
  87.    }
  88. }

Saludos!

Desconectado NoSepComo

  • PIC18
  • ****
  • Mensajes: 305
Re: Manejo del TIMER0 desde el CCS
« Respuesta #14 en: 28 de Febrero de 2011, 12:49:16 »
Muchas gracias por tu respuesta bmb, no sabía lo de la selección del timer (de 8 o 16), soy nuevo y estoy aprendiendo, te agradezco tu ayuda, loo he hecho en la forma que me has indicado y también funciona perfectamente.
Un cordial saludo.