Autor Tema: #INT_RB no interrumpe por segunda vez  (Leído 4907 veces)

0 Usuarios y 3 Visitantes están viendo este tema.

Desconectado picalo

  • PIC10
  • *
  • Mensajes: 20
#INT_RB no interrumpe por segunda vez
« en: 26 de Febrero de 2011, 17:23:26 »
Hola amigos de todo pic, estoy con un problema, el siguiente programa lee el puerto b y segun que pin cambia de estado asigno un valor a una variable a traves de int_rb, al volver al programa principal enciende y apaga un led ...

El problema es que una vez leida la interrupcion enciende y apaga el led correspondiente pero mientras esta haciendo esto no se lo puede interrumpir nuevamente HASTA QUE TERMINE CON LA CANTIDAD t1,t2,t3 DE ENCENDIDOS

como puede ser ???

aqui les paso mi programa              MUCHAS GRACIAS POR SU AYUDA !!!

#include <16F628A.h>
#use delay(clock=4000000)         
#fuses XT,NOWDT,NOPROTECT,PUT   
#use fast_io(A)
#use fast_io(B)
int interrupciones=0;
#INT_RB
void IntPortB4_7(void)
{
 if (!input(PIN_B4)&&input(PIN_B5)&&input(PIN_B6)&&input(PIN_B7))
   {interrupciones=1;}
 if (input(PIN_B4)&&!input(PIN_B5)&&input(PIN_B6)&&input(PIN_B7))
   {interrupciones=2;}
 if (input(PIN_B4)&&input(PIN_B5)&&!input(PIN_B6)&&input(PIN_B7))
   {interrupciones=3;}
}
void main(void)
{
unsigned int t1=14;
unsigned int t2=24;
unsigned int t3=30;
set_tris_a(0b000000);
set_tris_b(0b11110000);
enable_interrupts(int_rb);     
enable_interrupts(GLOBAL);
output_low(PIN_B0);
output_low(PIN_B1);
output_low(PIN_B2);
while(true)                     

if (interrupciones==1)
     {
     while (t1>0)
       {
       output_high(PIN_B0);   
       delay_ms(500);
       output_low(PIN_B0);   
       delay_ms(500);
       t1=t1-1;
       }
     t1=14;
     interrupciones=0;
     }   
if (interrupciones==2)
     {
     while (t2>0)
       {
       output_high(PIN_B1);   
       delay_ms(500);
       output_low(PIN_B1);   
       delay_ms(500);
       t2=t2-1;
       }
     t2=24;
     interrupciones=0;
     }   
if (interrupciones==3)
     {
     while (t3>0)
       {
       output_high(PIN_B2);   
       delay_ms(500);
       output_low(PIN_B2);   
       delay_ms(500);
       t3=t3-1;
       }
     t3=30;
     interrupciones=0;
     }   
}
}

Desconectado jhozate

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1698
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #1 en: 26 de Febrero de 2011, 19:24:58 »
debes hacer una lectura/escritura del puerto al entrar o al salir de la interrupción
algo como output_B(input_B());
Ser Colombiano es un Premio, Saludos desde CALI-COLOMBIA

Desconectado jukinch

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 608
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #2 en: 26 de Febrero de 2011, 19:30:33 »
Hola Picalo y jhozate:
           Para detener la secuencia si se produce una interrupción se podría usar una variable que sea actualizada por la interrupción de nombre por ejemplo seProdujoInterrupcion y un IF dentro de los bucles que compruebe si la variable seProdujoInterupcion es igual a 1 y en ese caso ejecute un BREAK para salir del bucle en el que estás trabajando.
           

por ejemplo:
while (t1>0)
       {
       if (seProdujoInterupcion==1)
         {
          seProdujoInterupcion=0;
          break ;
          }
       output_high(PIN_B0);  
       delay_ms(500);
       output_low(PIN_B0);  
       delay_ms(500);
       t1=t1-1;
       }
     t1=14;
     interrupciones=0;
     }    

y en los otros bucles también pondría lo mismo.

               Saludos.
                    Jukinch
"Divide las dificultades que examinas en tantas partes como sea posible para su mejor solución." -René Descartes

Desconectado culebrasx

  • PIC10
  • *
  • Mensajes: 39
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #3 en: 26 de Febrero de 2011, 19:32:43 »
Creo que debes d borrar, generalmente, el bit (flag) que provoca la interrupción en la misma rutina de interrupción para que vuelva a poder ponerse a uno en este caso seria el RBIF

This interrupt can wake the device from Sleep. The
user, in the interrupt service routine, can clear the
interrupt in the following manner:
a) Any read or write of PORTB. This will end the
mismatch condition.
b) Clear flag bit RBIF.


en la pagina 38 del manual de ese pic comentan los detalles de esta interrupción...

un saludo...

Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #4 en: 27 de Febrero de 2011, 10:57:03 »
Hola picalo, en realidad cada que un pin de RB4..RB7 cambia de estado si ocurre una interrupción, o sea que la variable interrupciones  toma el valor deseado.  El que no se va a interrumpir hasta que su condición sea falsa, es el bucle while() que esté en ejecución.  Una posible solución sería que adicionaras algunas banderas para que cuando cambie de estado otro pin de RB4..RB7, haga que la condición del bucle while() actual se vuelva falsa.  Aún así, otra instrucción que no puedes interrumpir es delay_ms() y si al cambiar de estado otro pin de RB4..RB7 esta instrucción está en ejecución, también habrá que esperar hasta que termine.

Saludos!

Edito: Una solución como la que te propone jukinch, también es viable teniendo en cuenta lo que te mencioné con la instrucción delay_ms().
« Última modificación: 27 de Febrero de 2011, 11:04:48 por bmb »

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #5 en: 28 de Febrero de 2011, 05:16:58 »
Una interrupción detiene el programa en cualquier punto, inclusive el delay_ms.

El error lo tienes en tu programa.

Cuando pulsas por ejemplo RB4 --> entra en la interrupción y hace interrupciones=1 y luego vuelve al programa principal empezando el parpadeo en RB0.

Si ahora pulsas RB5 abandona el parpadeo entra en la interrupcion y hace interrupciones=2 regresando al programa principal y siguiendo con el parpadeo, pero al acabar haces interrupciones=0, con lo que se queda todo sin parpadear.

Mira a ver como lo solucionas, para que abandone un parpadeo y empiece otro.

Es obligatorio hacer una lectura/escritura del portb al entrar en la interrupcion: http://www.todopic.com.ar/foros/index.php?topic=21226.0

Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #6 en: 28 de Febrero de 2011, 11:14:31 »
Una interrupción detiene el programa en cualquier punto, inclusive el delay_ms.

Hola Pocher, eso es totalmente cierto:

Hola picalo, en realidad cada que un pin de RB4..RB7 cambia de estado si ocurre una interrupción, o sea que la variable interrupciones  toma el valor deseado.

Tengo entendido que al ocurrir una interrupción, el programa detiene o interrumpe lo que está haciendo (inclusive durante un delay_ms()) para ejecutar el código correspondiente a esa interrupción y que cuando termina de ejecutar ese código vuelve al punto donde ocurrió la interrupción para continuar en lo que estaba.  Si te fijas, cuando ya hay una de las rutinas en ejecución, por ejemplo interrupciones = 1, y otro pin cambia de estado, la interrupción si ocurre cambiando por ejemplo a interrupciones = 2, pero inmediatamente el código regresa a donde estaba, o sea al bucle while(t1>0) correspondiente a interrupciones = 1 ya que el cambio de valor de la variable interrupciones no hará que salga de ese bucle while().  Por supuesto solo saldrá de este bucle cuando su condición se haga falsa, o adicionando alguna de las opciones que hemos sugerido jukinch o yo, que tampoco me parecen la mejor opción ya que si agarras ahi un delay_ms() en ejecución tendrás que esperar a que termine.

Es obligatorio hacer una lectura/escritura del portb al entrar en la interrupcion: http://www.todopic.com.ar/foros/index.php?topic=21226.0

Sobre esto no he tenido ningún problema, puede ser que en las nuevas versiones del CCS ya lo han solucionado.

Saludos!

Desconectado jukinch

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 608
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #7 en: 28 de Febrero de 2011, 11:36:13 »
Tengo entendido que al ocurrir una interrupción, el programa detiene o interrumpe lo que está haciendo (inclusive durante un delay_ms()) para ejecutar el código correspondiente a esa interrupción y que cuando termina de ejecutar ese código vuelve al punto donde ocurrió la interrupción para continuar en lo que estaba.  Si te fijas, cuando ya hay una de las rutinas en ejecución, por ejemplo interrupciones = 1, y otro pin cambia de estado, la interrupción si ocurre cambiando por ejemplo a interrupciones = 2, pero inmediatamente el código regresa a donde estaba, o sea al bucle while(t1>0) correspondiente a interrupciones = 1 ya que el cambio de valor de la variable interrupciones no hará que salga de ese bucle while().  Por supuesto solo saldrá de este bucle cuando su condición se haga falsa, o adicionando alguna de las opciones que hemos sugerido jukinch o yo, que tampoco me parecen la mejor opción ya que si agarras ahi un delay_ms() en ejecución tendrás que esperar a que termine.

También podría dividir el tiempo de duración del delay_ms en cuatro y comprobar la bandera de la interrupción entre cada uno de los delay_ms.-

pseudo código:
delay_ms
comprobar si ocurrió la interrupción
delay_ms
comprobar si ocurrió la interrupción
delay_ms
comprobar si ocurrió la interrupción
delay_ms

"Divide las dificultades que examinas en tantas partes como sea posible para su mejor solución." -René Descartes

Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #8 en: 28 de Febrero de 2011, 11:55:48 »
Hola jukinch, esa sería una forma, aunque creo que tal vez sería mejor (y muy de acuerdo con tu idea) utilizar un temporizador con un tiempo muy bajo y usar banderas en ambas interrupciones para saber que nuevo camino tomar al ocurrir un nuevo cambio de estado en un pin.

Saludos!

Desconectado jukinch

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 608
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #9 en: 28 de Febrero de 2011, 12:04:11 »
Gracias por el dato del temporizador bmb.  :-/
      Saludos.
              Jukinch
"Divide las dificultades que examinas en tantas partes como sea posible para su mejor solución." -René Descartes

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #10 en: 01 de Marzo de 2011, 07:47:45 »
Lo de trocear el delay_ms es una "solución" un poco basta.

bmp, podrías explicar con código lo del temporizador?


Desconectado bmb

  • PIC18
  • ****
  • Mensajes: 423
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #11 en: 01 de Marzo de 2011, 15:17:49 »
Hola pocher claro, con gusto.  He hecho un pequeño programa basado en el de picalo para mostrar una de las posibles formas de utilizar a Timer0 para contar los medios segundos que tiene cada estado del LED.  Los valores de T1, T2 y T3 los puse un poco más bajos para las pruebas, pero es solo cuestión de cambiarlos en los defines al valor deseado.  También debemos recordar que la interrupción por cambios de estado en RB ocurre bien sea con el flanco ascendente o descendente, por lo que al pulsar el botón iniciará el proceso, pero al soltarlo también.  A este inconveniente no le gasté tiempo porque no es el tema ahora.  El Timer0 hará un interrupción cada 4mSeg. aproximadamente y el programa se encarga de cambiar el estado al LED en turno cada que cuente medio segundo, por lo que si tocamos otro botón, se tardará más o menos 4mSeg más la demora de las instrucciones involucradas en hacer el cambio de LED.  Por aqui dejo el código:

Código: C
  1. // clock = 4000000 Hz
  2. // Tosc = (1 / clock)
  3. //
  4. // Tiempo = 4 x Tosc x Valor a contar en Timer0 + 1 x Rango del Divisor
  5. // Tiempo = 4 x 0.00000025 x 256 x 16 = 4.096mS  // Timer 8 bits a 4MHz
  6. // Valor de inicio para Timer0 = 256 - 256 = 0
  7.  
  8.  
  9. #include <16F628A.h>
  10.  
  11. #FUSES NOWDT                    //No Watch Dog Timer
  12. #FUSES XT                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
  13. #FUSES NOPUT                    //No Power Up Timer
  14. #FUSES NOPROTECT                //Code not protected from reading
  15. #FUSES NOBROWNOUT               //No brownout reset
  16. #FUSES MCLR                     //Master Clear pin enabled
  17. #FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
  18. #FUSES NOCPD                    //No EE protection
  19.  
  20. #use delay(clock=4000000)
  21. #use fast_io(b)
  22.  
  23. #define MedioSeg 125            // 125 x 4mS = 0,5 Seg
  24.  
  25. #define T1 10
  26. #define T2 8
  27. #define T3 6
  28.  
  29. int1 Boton1 = false, Boton2 = false, Boton3 = false, MedSegs = false, Nuevo = false;
  30. int  Contador = 0, Segs = 0;
  31.  
  32. #int_RB
  33. void  RB_isr(void)
  34. {
  35.    Nuevo = true;
  36.    
  37.    int actual;
  38.  
  39.    actual = input_b();
  40.  
  41.    if ((!bit_test(actual,4))&&(bit_test(actual,5))&&(bit_test(actual,6))&&(bit_test(actual,7)))
  42.    {
  43.       Boton1 = true;
  44.       Boton2 = false;
  45.       Boton3 = false;
  46.    }
  47.    if ((bit_test(actual,4))&&(!bit_test(actual,5))&&(bit_test(actual,6))&&(bit_test(actual,7)))
  48.    {
  49.       Boton1 = false;
  50.       Boton2 = true;
  51.       Boton3 = false;
  52.    }
  53.    if ((bit_test(actual,4))&&(bit_test(actual,5))&&(!bit_test(actual,6))&&(bit_test(actual,7)))
  54.    {
  55.       Boton1 = false;
  56.       Boton2 = false;
  57.       Boton3 = true;
  58.    }
  59. }
  60.  
  61. #int_TIMER0
  62. void  TIMER0_isr(void)
  63. {
  64.    if(Nuevo)
  65.    {
  66.       Contador = 0;
  67.       MedSegs = false;
  68.       Segs = 0;
  69.       Nuevo = false;
  70.       set_timer0(0);
  71.    }
  72.  
  73.    Contador++;
  74.    if(Contador == MedioSeg)
  75.    {
  76.       MedSegs++;
  77.       if(MedSegs)
  78.          Segs++;
  79.       Contador = 0;
  80.    }
  81. }
  82.  
  83. void main()
  84. {
  85.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);    // 4mSeg. aprox.
  86.    setup_timer_1(T1_DISABLED);
  87.    setup_timer_2(T2_DISABLED,0,1);
  88.    setup_ccp1(CCP_OFF);
  89.    setup_comparator(NC_NC_NC_NC);
  90.    enable_interrupts(INT_RB);
  91.    enable_interrupts(INT_TIMER0);
  92.    enable_interrupts(GLOBAL);
  93.  
  94.    set_tris_b(0xF0);
  95.    
  96.    while(true)
  97.    {
  98.       output_low(PIN_B0);
  99.       output_low(PIN_B1);
  100.       output_low(PIN_B2);
  101.    
  102.       while(Boton1)
  103.       {
  104.          output_low(PIN_B1);
  105.          output_low(PIN_B2);
  106.          
  107.          if(!MedSegs)
  108.             output_high(PIN_B0);  
  109.          else
  110.             output_low(PIN_B0);
  111.              
  112.          if(T1 == Segs)
  113.          {
  114.             MedSegs = false;
  115.             Boton1 = false;
  116.          }
  117.       }
  118.  
  119.       while(Boton2)
  120.       {
  121.          output_low(PIN_B0);
  122.          output_low(PIN_B2);
  123.  
  124.          if(!MedSegs)
  125.             output_high(PIN_B1);  
  126.          else
  127.             output_low(PIN_B1);
  128.            
  129.          if(T2 == Segs)
  130.          {
  131.             MedSegs = false;
  132.             Boton2 = false;
  133.          }
  134.       }
  135.  
  136.       while (Boton3)
  137.       {
  138.          output_low(PIN_B0);
  139.          output_low(PIN_B1);
  140.  
  141.          if(!MedSegs)
  142.             output_high(PIN_B2);  
  143.          else
  144.             output_low(PIN_B2);
  145.      
  146.          if(T3 == Segs)
  147.          {
  148.             MedSegs = false;
  149.             Boton3 = false;
  150.          }
  151.       }    
  152.    }
  153. }

Si le ven algún error me sabrán disculpar, porque lo hice ahora en un rato libre en el trabajo con el fin de mostrar el uso del Timer para este caso.  También dejo un archivo con el hex y un archivo para Proteus.

Saludos!

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #12 en: 02 de Marzo de 2011, 04:23:48 »
Claro, por interrupción de un TMR. Yo también pensé que era la unica posibilidad para hacerlo bien.

Muy bien explicado, gracias bmp.

Desconectado picalo

  • PIC10
  • *
  • Mensajes: 20
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #13 en: 10 de Marzo de 2011, 22:24:10 »
Muchas gracias a todos los que me ayudaron a encontrar la solucion ...

Pocher tenia razon el problema estaba en el programa y aqui les dejo como lo solucione:

#include <16F876A.h>
#use delay(clock=4000000)         
#fuses XT,NOWDT,NOPROTECT,PUT   
#use fast_io(A)
#use fast_io(B)
#use fast_io(c)
int interrupcion=0;
int conteo=0;
#INT_RB
void IntPortB4_7(void)
{
//#asm movf port_b,0 #endasm      NO SE PORQUE ME MARCA ERROR
output_b(input_b());
interrupcion=1;
 if (!input(PIN_B4)&&input(PIN_B5)&&input(PIN_B6)&&input(PIN_B7))
   {conteo=1;}
 if (input(PIN_B4)&&!input(PIN_B5)&&input(PIN_B6)&&input(PIN_B7))
   {conteo=2;}
 if (input(PIN_B4)&&input(PIN_B5)&&!input(PIN_B6)&&input(PIN_B7))
   {conteo=3;}
}
void main(void)
{
unsigned int t1=14;
unsigned int t2=24;
unsigned int t3=30;
set_tris_a(0b000000);
set_tris_b(0b11110000);
set_tris_c(0b00000000);
enable_interrupts(int_rb);     
enable_interrupts(GLOBAL);
output_low(PIN_C0);
output_low(PIN_C1);
output_low(PIN_C2);
while(true)                     

if ((conteo==1)&(interrupcion==1))
     {
     interrupcion=0;
     while ((t1>0)&(interrupcion==0))
       {
       output_high(PIN_C0);   
       delay_ms(500);
       output_low(PIN_C0);   
       delay_ms(500);
       t1=t1-1;
       }
     t1=14;
     }   
if ((conteo==2)&(interrupcion==1))
     {
     interrupcion=0;
     while ((t2>0)&(interrupcion==0))
       {
       output_high(PIN_C1);   
       delay_ms(500);
       output_low(PIN_C1);   
       delay_ms(500);
       t2=t2-1;
       }
     t2=24;
     }   
if ((conteo==3)&(interrupcion==1))
     {
     interrupcion=0;
     while ((t3>0)&(interrupcion==0))
       {
       output_high(PIN_C2);   
       delay_ms(500);
       output_low(PIN_C2);   
       delay_ms(500);
       t3=t3-1;
       }
     t3=30;
     }   
}
}

Desconectado jukinch

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 608
Re: #INT_RB no interrumpe por segunda vez
« Respuesta #14 en: 10 de Marzo de 2011, 23:41:10 »
Que bueno Picalo. Felicitaciones.  :-/
                    Saludos
                              Jukinch
"Divide las dificultades que examinas en tantas partes como sea posible para su mejor solución." -René Descartes


 

anything