Autor Tema: Otra de #Int_ext  (Leído 2982 veces)

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

Desconectado elgarbe

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2178
Otra de #Int_ext
« en: 04 de Junio de 2012, 17:36:25 »
Bueno, estoy complicado y no entiendo porque, tengo este código:

#int_EXT
void ext_isr()
{
   delay_ms(500);
   if(start==0){
      start=1;
      mseg=0;
      seg=0;
   }
   else{
      start=0;
   }
}

está tomada la idea del cronómetro de RedPic, solo que yo lo hice en seg y mseg y con la int ext lo quierro arrancar y parar.
El problema es que si el pulso de la interrupcion externa es muy largo (estimo más largo que el delay_ms) deja de funcionar la interrupcion externa.
Yo necesito activar el cronómetro con una señal y pararlo con otra, ámbas por la int_ext. y al ser un cronómetro no me puedo permitir un delay muy grande, en realidad puedo meter un delay de solo 10ms. Porque deja de funcionar si el pulso es muy largo?
estoy pensando en disparar la int_ext con un 555 así me independizo del disparo mecánico. Alguien tiene algún circuito para compartir? con ese circuito externo elimino el rebote tambien, verdad?

Saludos!
-
Leonardo Garberoglio

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18310
    • MicroPIC
Re: Otra de #Int_ext
« Respuesta #1 en: 05 de Junio de 2012, 01:50:54 »
Un delay no puede estar dentro de una interrupción. Si durante el delay se producen otras interrupciones las deja paradas y el programa se vuelve loco.

Si lo que quieres es eliminar rebotes de un pulsador mecánico que está conectado a la interrupción externa, te recomiendo lo siguiente:

1.- Quita el delay de tu interrupción. Copia el código desde if(start... hasta el final porque lo vamos a poner en otro sitio
2.- En tu interrupción externa, configura un timer para que desborde dentro de unos 20ms y activa la interrupción de ese timer
3.- En la interrupción del timer, comprueba si el pulso sigue como te interesa para arrancar (alto o bajo). En caso afirmativo, utiliza aquí el código que copiaste al principio.
4.- En caso contrario, estás delante de un rebote. Desactiva la interrupción del timer e ignóralo.

Desconectado elgarbe

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Otra de #Int_ext
« Respuesta #2 en: 05 de Junio de 2012, 08:50:30 »
Gracias nocturno, aquí va el código (como hago para ponerlo dentro de esos marcos que colorean las sentencias?)
Lo de poner el delay para el rebote creí haberlo leído por aquí, coincido que no era lo más elegante.
En cuanto al disparo por hardware, alguna idea? como es un cronómetro para carrareas, lo máximo que puedo perder son 10mseg verificando rebotes, preferiría hacer un hardware que me asegure 0 rebotes.

Código: C
  1. #int_RTCC
  2. void RTCC_isr()
  3. {
  4.   if(++nRTCC==RTCCxS){
  5.     nRTCC=0x00;
  6.     output_toggle(PIN_B2);
  7.     if(++mseg>99){
  8.       output_toggle(PIN_B3);
  9.       mseg=0;
  10.       if(++seg>59){
  11.         seg=0;
  12.       }
  13.     }
  14.   }
  15.   set_timer0(i_ADJ_TIME);
  16. }
  17. #int_EXT
  18. void ext_isr()
  19. {
  20.    delay_ms(500);
  21.    if(start==0){
  22.       start=1;
  23.       mseg=0;
  24.       seg=0;
  25.    }
  26.    else{
  27.       start=0;
  28.    }
  29. }
  30.  
  31. void main(){
  32.    int kmseg=0x00;
  33.    setup_timer_0(RTCC_INTERNAL | RTCC_DIV_2);
  34.    setup_timer_1(T1_DISABLED);
  35.    setup_timer_2(T2_DISABLED,0,1);
  36.    setup_comparator(NC_NC_NC_NC);
  37.    setup_vref(FALSE);
  38.    ext_int_edge(H_TO_L);
  39.    disable_interrupts(INT_RTCC);
  40.  
  41.    set_timer0(i_ADJ_TIME);   //Precargo el TIMER0 para obtener 1mSeg justo
  42.  
  43.    TRISA=0xF0;
  44.    TRISB=0b00000011;   //Rb0, 1 entradas, el resto salida
  45.  
  46.    output_a(~0x00);              //Saco todos 1 en el BCD
  47.    output_b(input_b() | 0xF0);   //Mando a 5 Rb4 a 7 LE
  48.    delay_us(100);                 //Aseguro la señal LE
  49.    output_b(input_b() & 0x0F);   //Vuelvo a 1 los LE
  50.  
  51.    enable_interrupts(INT_RTCC);  //Ya puedo comenzar a interrumpir por timer
  52.    enable_interrupts(INT_EXT);  //Ya puedo comenzar a interrumpir por timer
  53.    enable_interrupts(GLOBAL);
  54. //   start=1;                      //Esto lo saco cuando pueda usar las INT EXT
  55.  
  56.    do{                        // Bucle infinito
  57.     if(mseg!=kmseg){          // si cambia el mili segundo actualizo las
  58.       time2bcd();             // variables con lo que hay que mostrar
  59.       kmseg=mseg;
  60.     }
  61.     if (start==1){
  62.        display_reloj();          // Muestra constantemente
  63.     }
  64.   }While(TRUE);
  65. }
« Última modificación: 05 de Junio de 2012, 13:57:03 por un Moderador »
-
Leonardo Garberoglio

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18310
    • MicroPIC
Re: Otra de #Int_ext
« Respuesta #3 en: 05 de Junio de 2012, 13:58:03 »
Para formatear el código hay que seleccionarlo y elegir el lenguaje utilizado en el desplegable de GeShi que ves arriba. De todas formas ya te lo he dejado hecho.

Desconectado elgarbe

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Otra de #Int_ext
« Respuesta #4 en: 06 de Junio de 2012, 08:15:58 »
Nocturno, hice lo siguiente:

Código: C
  1. #int_TIMER1
  2. void TIMER1_isr(void){
  3.    if(INPUT(PIN_B0)==0){
  4.       if(f_mostrar==0){
  5.          f_mostrar=1;
  6.          mseg=0;
  7.          seg=0;
  8.       }
  9.    }
  10.    else{
  11.       disable_interrupts(INT_TIMER1);
  12.    }
  13. }
  14.  
  15. #int_EXT
  16. void ext_isr(){
  17.    //f_arranque=~f_arranque;
  18.    set_timer1(45535);
  19.    enable_interrupts(INT_TIMER1);
  20. }

La int externa esta configurada de H_TO_L. El timer1 tiene 20mseg.
Eso parece funcionar....
Ahora el tema es que cuando entra una segunda interrupción debería detener el cronómetro y es ahí donde no se como seguir, probé con algunas banderas, pero no pude lograrlo.

Saludos
-
Leonardo Garberoglio

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18310
    • MicroPIC
Re: Otra de #Int_ext
« Respuesta #5 en: 06 de Junio de 2012, 11:23:02 »
¿Cuándo cambias el valor de f_mostrar?

Desconectado elgarbe

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Otra de #Int_ext
« Respuesta #6 en: 06 de Junio de 2012, 13:43:00 »
Te paso el código completo, el f_mostrar lo cambio en el timer y lo leo en el bucle principal:

Código: C
  1. #include <16F628A.h>
  2.  
  3. #FUSES NOWDT                    //No Watch Dog Timer
  4. #FUSES INTRC_IO                 //Internal RC Osc
  5. #FUSES NOPUT                    //No Power Up Timer
  6. #FUSES NOPROTECT                //Code not protected from reading
  7. #FUSES NOBROWNOUT               //No brownout reset
  8. #FUSES MCLR                     //Master Clear pin enabled
  9. #FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
  10. #FUSES NOCPD                    //No EE protection
  11.  
  12. #use delay(clock=4000000)
  13.  
  14. #byte TRISA=0x85
  15. #byte TRISB=0x86
  16. #byte PORTB=0x06
  17.  
  18. char const RTCCxS=20; // Número de RTCC's para 10 mseg con 4 Mhz / 1:2.
  19. int8 const i_ADJ_TIME=27;
  20. // VARIABLES GLOBALES
  21.  
  22. int nRTCC=0x00;        // Contador de interrupciones RTCC completas
  23. int mseg=0x0;          // mili segundos del Reloj
  24. int seg=0x0;           // segundos del Reloj
  25. int D1=0x00;           // Contenido de los Displays
  26. int D2=0x00;
  27. int D3=0x00;
  28. int D4=0x00;
  29. int l_digit, h_digit;     // Resultado de la conversión bin2bcd
  30. int f_mostrar=0x00;                    // index general
  31. int f_arranque=0x00;                    // index general
  32. int f_stop=0x00;                    // index general
  33.  
  34. void display_reloj(void); // Función que muestra el contenido del reloj
  35. void time2bcd(void);      // Función que convierte seg y mseg a 4 x BCD
  36. void bin2bcd(int valor);  // Función que convierte de Binario a BCD
  37.  
  38. #int_RTCC
  39. void RTCC_isr()
  40. {
  41.   if(++nRTCC==RTCCxS){
  42.     nRTCC=0x00;
  43.     output_toggle(PIN_B2);
  44.     if(++mseg>99){
  45.       output_toggle(PIN_B3);
  46.       mseg=0;
  47.       if(++seg>59){
  48.         seg=0;
  49.       }
  50.     }
  51.   }
  52.   set_timer0(i_ADJ_TIME);
  53. }
  54.  
  55. #int_TIMER1
  56. void TIMER1_isr(void){
  57.    if(INPUT(PIN_B0)==0){
  58.       if(f_mostrar==0){
  59.          f_mostrar=1;
  60.          mseg=0;
  61.          seg=0;
  62.       }
  63.    }
  64.    else{
  65.       disable_interrupts(INT_TIMER1);
  66.    }
  67. }
  68.  
  69. #int_EXT
  70. void ext_isr(){
  71.    //f_arranque=~f_arranque;
  72.    set_timer1(45535);
  73.    enable_interrupts(INT_TIMER1);
  74. }
  75.  
  76.  
  77.  
  78. void main(){
  79.    int kmseg=0x00;
  80.    setup_timer_0(RTCC_INTERNAL | RTCC_DIV_2);
  81.    //El timer1 interrumpira cada (65535-45535)*4*1/4000000=20,00mSeg
  82.    setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
  83.    set_timer1(45535);
  84. //   setup_timer_1(T1_DISABLED);
  85.    setup_timer_2(T2_DISABLED,0,1);
  86.    setup_comparator(NC_NC_NC_NC);
  87.    setup_vref(FALSE);
  88.    ext_int_edge(H_TO_L);
  89.    disable_interrupts(INT_RTCC);
  90.  
  91.    set_timer0(i_ADJ_TIME);   //Precargo el TIMER0 para obtener 1mSeg justo
  92.  
  93.    TRISA=0xF0;
  94.    TRISB=0b00000011;   //Rb0, 1 entradas, el resto salida
  95.  
  96.    output_a(~0x00);              //Saco todos 1 en el BCD
  97.    output_b(input_b() | 0xF0);   //Mando a 5 Rb4 a 7 LE
  98.    delay_us(100);                 //Aseguro la señal LE
  99.    output_b(input_b() & 0x0F);   //Vuelvo a 1 los LE
  100.  
  101.    enable_interrupts(INT_RTCC);  //Ya puedo comenzar a interrumpir por timer
  102. //   enable_interrupts(INT_TIMER1);  //Ya puedo comenzar a interrumpir por timer
  103.    enable_interrupts(INT_EXT);  //Ya puedo comenzar a interrumpir por timer
  104.    enable_interrupts(GLOBAL);
  105. //   start=1;                      //Esto lo saco cuando pueda usar las INT EXT
  106.  
  107.    do{                        // Bucle infinito
  108.     if(mseg!=kmseg){          // si cambia el mili segundo actualizo las
  109.       time2bcd();             // variables con lo que hay que mostrar
  110.       kmseg=mseg;
  111.     }
  112.     if (f_mostrar==1){
  113.        display_reloj();          // Muestra constantemente
  114.     }
  115.   }While(TRUE);
  116. }
  117.  
  118. void display_reloj(void){ // Función que muestra el contenido del reloj
  119.  
  120.   output_a(D1);           // Muestro 1er carácter de segundo
  121.   output_high(PIN_B4);
  122.   delay_us(20);
  123.   output_low(PIN_B4);
  124.  
  125.   output_a(D2);           // Muestro 2do carácter de segundo
  126.   output_high(PIN_B5);
  127.   delay_us(20);
  128.   output_low(PIN_B5);
  129.  
  130.   output_a(D3);           // Muestro 1er carácter de minuto
  131.   output_high(PIN_B6);
  132.   delay_us(20);
  133.   output_low(PIN_B6);
  134.  
  135.   output_a(D4);           // Muestro 2do carácter de minuto
  136.   output_high(PIN_B7);
  137.   delay_us(20);
  138.   output_low(PIN_B7);
  139. }
  140.  
  141. void time2bcd(void){     // Función convierte minutos y segundos a 4 x BCD
  142.   bin2bcd(seg);      // Paso de binario a BCD el segundo y actualizo
  143.   D1 = ~h_digit;          // contenido a mostrar
  144.   D2 = ~l_digit;
  145.   bin2bcd(mseg);       // Paso de binario a BCD el minuto y actualizo
  146.   D3 = ~h_digit;          // contenido a mostrar
  147.   D4 = ~l_digit;
  148. }
  149.  
  150. void bin2bcd(int valor){ // Función que convierte de Binario a BCD
  151.   h_digit=0;
  152.   if (valor>=10){
  153.     do{
  154.       valor-=10;
  155.       h_digit++;
  156.     } while (valor>=10);
  157.   }
  158.   l_digit=valor;
  159. }

La base del programa es tomada del CronoPic de RedPic, despues me queda pendiente acomodarlo un poco (por ejemplo, el timer esta constantemente interrumpiendo y actualizando los mseg, y seg y cuando entra la int_ext  reseteo los contadores y empiezo a mostrar, sería mejor que empieze a contar directamente cuando entra al int_ext, pero es lo veré despues).
Lo unico que me resta para tenerlo funcionando es que con la primera int_ext arranque y con la siguiente pare....

Saludos y muchas gracias!
-
Leonardo Garberoglio

Desconectado elgarbe

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Otra de #Int_ext
« Respuesta #7 en: 10 de Junio de 2012, 15:49:39 »
Bueno, despues de seguir buscando y leyendo cuanta información encontre sobre esto pongo las conclusiones que saco haver si alguien me puede decir que opina:

Mi circuito es un cronómetro con 2 sensores mecánicos (un red switch y un relé de una barrera infrarroja) voy a ponerlos en serie, voy a usar el Normal Cerrado del relé de llegada y el Normal Abierto del Red Switch para el arranque del conteo. Las señales entran por la Int Externa, a la cual le puse una R de pull up de 10K.

Primero configuro la int_ext para flanco de bajada, o sea, cuando se abra la puerta para empezar la carrera el red switch se cierra y me pone a masa la int_ext.

En la int_ext debo configurar el timer1 para que me interrumpa en el tiempo que considero ha pasado el rebote, por ejemplo 20mseg.
Código: C
  1. #int_EXT
  2. void ext_isr(){
  3.    set_timer1(45535);
  4.    enable_interrupts(INT_TIMER1);
  5. }
Esta interrupcion se va a disparar varias veces cuando el contacto del red switch se cierra y cuando el contacto del rele se abra (en este ultimo caso quizá no alla rebote ya que es abrir un contacto). Lo que veo es que cada rebote que tenga, el timer1 se va reiniciar ya que entrará a la int_ext. Por lo que los 20mseg del timer1 será a partir del último rebote, lo que no me convence del todo. Hasta aquí voy bien con la lógica?



Cuando el timer1 llega a interrumpir es porque ya no tengo más rebotes, asi que verifico que la entrada int_ext esté en el nivel que deseo (alto en este caso) y si lo está empiezo a contar y hacer correr el cronómetro.
Lo que no termino de enteder es la condicion de que el Timer1 halla interrumpido y al chequear la Int_Ext me diga que está en 1, eso implicaría que el rebote es más largo de lo que esperaba?
Por otra parte, si el Timer alcanza a interrumpir, pero al chequear la entrada la veo en 1 deshabilito la interrupcion del Timer ya que con la próxima int_ext se habilitará

Código: C
  1. #int_TIMER1
  2. void TIMER1_isr(void){
  3.    if(INPUT(PIN_B0)==0){
  4.       if(f_mostrar==0){
  5.          //ext_int_edge(L_TO_H);
  6.          f_mostrar=1;
  7.          mseg=0;
  8.          seg=0;
  9.       }
  10.    }
  11.    else{
  12.       disable_interrupts(INT_TIMER1);
  13.    }
  14. }

Esto estaría funcionando, aunque me quedan esas dudas. El tema sería como modificar la parte de la interrupcion del Timer1 para esperar la apertura del circuito por (interrupcion por flanco de subida) cuando se corta la barrera infrarroja.

Ayuda?

Saludos!
-
Leonardo Garberoglio

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Otra de #Int_ext
« Respuesta #8 en: 10 de Junio de 2012, 16:34:47 »
1. Habilitas la interrupción externa.
2. Al ejecutarse la interrupción externa habilitas el timer y apagas la externa.
3. Al ejecutarse la interrupción del timer testeas si es un cambio de estado o falsa alarma, luego apagas la del timer y habilitas de nuevo la externa.


Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado elgarbe

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Otra de #Int_ext
« Respuesta #9 en: 10 de Junio de 2012, 16:54:14 »
Perfecto, gracias suky, voy a probar.
Por que si llega a interrumpir el timer y el nivel no es el adecuado (no pasó de alto a bajo) es una falsa alarma? O sea, está bien, es falsa alarma, pero en realidad es que le di poco tiempo al timer, no?
Lo de deshabilitar la int_ext es lo principal que me falta, eso cambia todo lo que yo había pensado... ahora si me empieza a cerrar todo...
Como podría hacer para distinguir entre la primer interrupcuion y la segunda (la de arrancar y parar el cronómetro)?

Saludos
-
Leonardo Garberoglio