Autor Tema: #INT_Rbo  (Leído 2604 veces)

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

Desconectado ORE

  • PIC10
  • *
  • Mensajes: 43
#INT_Rbo
« en: 12 de Mayo de 2006, 14:55:36 »
Hola muy buenas,

Llevo dos días con esta subrutina mediante la interrupción de del pin RB0/INT, y no hay forma de que vuelva al programa principal. Simplemente he colocado en la interrupción que hasta que no se vuelva a pulsar B3 no encienda y apague el led, pero en el programa que estoy realizando hago muchas cosas más, que no se si eso es un problema en CCS, el colocar mucho código en una instrucción y que provoque un problema, esa es mi duda. Por otro lado si coloco en el for, un simple programa que diga hola y encinda un led, no me atiende a la interrupción,pero si ejecuta el programa.

También he estado revisando los mensajes del foro sobre esta cuestión, y no se donde está mi fallo.

Por otro lado he probado de colocar al final de la interrupción un return; y un return 0; y nada de nada.

Agradecería comentarios sobre esto, ya que el resto de interrupciones que estoy programando funciona de mil maravillas.

Importante el dato de declaración del portB, que es donde están los pulsadores, ya que el uso de fast_io, no funciona y con standar_io si...???

Posteo el código:

#include "C:\15 - Program Files C\20060501_prueba_int_rb0_int.h"
#use standar_io(B)
#byte port_b=0X06
#use fast_io (D)
#byte port_d=0X08
#use fast_io (E)
#byte port_e=0X09

#include<lcd.c>

#int_EXT
EXT_isr()
         {
         //Aqui hago lo que sea, mucho código eso si.
         }
void main()
{
   port_b_pullups(FALSE);
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   set_tris_b(0x0F);      //Puerto B como salida/entrada
   set_tris_d(0xFF);            //RD0...RD7 salidas
   set_tris_e(0x00);            //RE0...RE2 entradas
   port_b=0;
   enable_interrupts(int_ext);      //activar interrupcion externa
   ext_int_edge(L_TO_H);         //configuracion:interrupcion cuando señal esta en alta
   enable_interrupts(GLOBAL);      //todas las interrupciones activadas

   for(;;)
  {
           delay_ms(2000);
           lcd_putc("\f");
      lcd_gotoxy(1,1);
           lcd_putc('H');       // Envía caracter al LCD.
           lcd_putc('o');
           lcd_putc('l');
           lcd_putc('a');
           lcd_putc(' ');
           output_high(PIN_B7); //Se activa el led
           delay_ms(1000);      //Hacemos una pausa de 1 segundo
           output_low(PIN_B7);  //Se desactiva el led
           delay_ms(1000);      //Y volvemos a ejecutar el bucle infinito
}   //bucle infinito esperando interrupcion
}

Un saludo y gracias
 

Desconectado kain589

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 324
Re: #INT_Rbo
« Respuesta #1 en: 12 de Mayo de 2006, 15:38:21 »
Si se te queda pillado al atender la instruccion RB0 deberias postear la rutina de servicio a la ionterrupcion, ya que es donde es mas probable que este el error
Saludos desde Córdoba, españa

Desconectado vszener

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2395
Re: #INT_Rbo
« Respuesta #2 en: 12 de Mayo de 2006, 15:50:22 »
Buenas!!!haber, creo recordar que al entrar en las funciones propias del manejo de la pantalla lcd, las interrupciones quedan desactivadas(deberia darte un 'warning' al compilar recordandote lo que te he puesto), por lo tanto, viendo tu codigo, el bucle infinito esta continuamente escribiendo en la lcd lo mismo, te recomiendo que dicho manejo de la lcd lo hagas fuera del codigo, algo asi:
Código: C
  1. #include "C:\15 - Program Files C\20060501_prueba_int_rb0_int.h"
  2. #use standar_io(B)
  3. #byte port_b=0X06
  4. #use fast_io (D)
  5. #byte port_d=0X08
  6. #use fast_io (E)
  7. #byte port_e=0X09
  8.  
  9. #include<lcd.c>
  10.  
  11. #int_EXT
  12. EXT_isr()
  13.          {
  14.          //Aqui hago lo que sea, mucho código eso si.
  15.          }
  16. void main()
  17. {
  18.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  19.  
  20.    set_tris_b(0x0F);      //Puerto B como salida/entrada
  21.    set_tris_d(0xFF);            //RD0...RD7 salidas
  22.    set_tris_e(0x00);            //RE0...RE2 entradas
  23.    port_b=0;
  24.  
  25.    enable_interrupts(int_ext);      //activar interrupcion externa
  26.    ext_int_edge(L_TO_H);         //configuracion:interrupcion cuando señal esta en alta
  27.    enable_interrupts(GLOBAL);      //todas las interrupciones activadas
  28.  
  29.     lcd_putc('H');       // Envía caracter al LCD.
  30.     lcd_putc('o');
  31.     lcd_putc('l');
  32.     lcd_putc('a');
  33.  
  34.    for(; ; ;)
  35.   {
  36.            output_high(PIN_B7); //Se activa el led
  37.            delay_ms(1000);      //Hacemos una pausa de 1 segundo
  38.            output_low(PIN_B7);  //Se desactiva el led
  39.            delay_ms(1000);      //Y volvemos a ejecutar el bucle infinito
  40. }   //bucle infinito esperando interrupcion
  41. }

Prueba asi lo de la interrupcion, haber si va....de todas formas en el post de Ejemplitos en C para 16F648A , el numero 40, trata dicha interrupcion.


Suerte!!! :wink:
· Nos vemos en los bares!!!!!
· Mi Blog: Aqueronte

Desconectado ORE

  • PIC10
  • *
  • Mensajes: 43
Re: #INT_Rbo
« Respuesta #3 en: 12 de Mayo de 2006, 16:54:43 »
Hola,

Gracias por las respuestas. Santa razon tienes vszener, el problema esta en la librería lcd, además he modificado el programa, habilitando las interrupciones dentro del for(;;), con lo cuál esta se activa sin problema. Por otro lado he generado un afunción dentro de la interupción, con lo cual queda más saneado el programa.

Para darle solución, en vista de la respuesta de vszener lo que he realizado es habilitar las interrupciones dentro del for, y posteriormente como en la funcion que implemento dentro de la interrupcion las vuelvo a habilitar. El hacerlo de esta forma funciona, ya que si no habilito dentro de la funcion las interrupciones no funciona, comprobado. Mi pregunta es si debo escribir el habilitar la interrupcion rb0, por nivel alto, y habilitar las globales, a lo mejor con esta ultima es suficiente, voy a probar. Posteo el programa, espero depurarlo:

menu()
{
      //Aqui hago lo que sea, incluido llamada a la funcion del lcd que es la que da problemas
      enable_interrupts(INT_EXT);
      ext_int_edge(L_TO_H);
      enable_interrupts(GLOBAL);
     
}

#int_EXT
EXT_isr()
{
      output_high(PIN_B5); //Se activa el led
      delay_ms(1000);      //Hacemos una pausa de 1 segundo
      output_low(PIN_B5);  //Se desactiva el led
      delay_ms(1000);     
      menu();
}


void main()
{
   port_b_pullups(FALSE);
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   set_tris_b(0x0F);      //Puerto B como salida/entrada
   set_tris_d(0xFF);            //RD0...RD7 salidas
   set_tris_e(0x00);            //RE0...RE2 entradas
   port_b=0;
   
   for(;;)
   {
      enable_interrupts(INT_EXT);
      ext_int_edge(L_TO_H);
      enable_interrupts(GLOBAL);
      output_high(PIN_B7); //Se activa el led
      delay_ms(1000);      //Hacemos una pausa de 1 segundo
      output_low(PIN_B7);  //Se desactiva el led
      delay_ms(1000);      //Y volvemos a ejecutar el bucle infinito*/
   }
}


Desconectado ORE

  • PIC10
  • *
  • Mensajes: 43
Re: #INT_Rbo
« Respuesta #4 en: 12 de Mayo de 2006, 17:12:52 »
Hola,

Creo que lo de habilitar las interrupciones dentro de una propia interrupción, lo que provoca es que puede volver a detectar pulsaciones, y entrar un bucle infinito, ya que vuelve a llamar a la función debido a que se ha pulsado una tecla, en este caso para salir, ¿No hay una forma evitar que pase esto, sabiendo que es el lcd el que da los problemas aunque este sea llamado desde una función que está implementada en la propia interrupcion?

Un saludo,

Nota: estoy probando todas las posibilidades habidas y por haber, colocando este código solamente se ejecuta 1 vez la interrupción, pero si que vuelve al programa principal, ya que vuelve a encender y apagar el led.

menu()
{
//Aqui hago lo que sea, incluido llamada a la funcion del lcd que es la que da problemas
}

#int_EXT
EXT_isr()
{
      output_high(PIN_B5); //Se activa el led
      delay_ms(1000);      //Hacemos una pausa de 1 segundo
      output_low(PIN_B5);  //Se desactiva el led
      delay_ms(1000);     
      menu();
}


void main()
{
//Lo que sea
}
   
   for(;;)
   {
      enable_interrupts(INT_EXT);
      ext_int_edge(L_TO_H);
      enable_interrupts(GLOBAL);
      output_high(PIN_B7); //Se activa el led
      delay_ms(100);      //Hacemos una pausa de 1 segundo
      output_low(PIN_B7);  //Se desactiva el led
      delay_ms(100);      //Y volvemos a ejecutar el bucle infinito*/
   }
}

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5544
    • Picmania by Redraven
Re: #INT_Rbo
« Respuesta #5 en: 12 de Mayo de 2006, 18:26:08 »
Un detalle que yo uso mucho y que elimina una buena parte de lo conflictos que se generan al usar interrupciones.

Hay una regla de oro que siempre es conveniente aplicar: Dentro de la rutina de tratamiento de una interrupción haz exactamente lo mínimo para tratar convenientemente dicha interrupción.

Te pongo por ejemplo tu propia rutina:

Modo 1.-

#int_EXT
EXT_isr()
{
      output_high(PIN_B5); //Se activa el led
      delay_ms(1000);      //Hacemos una pausa de 1 segundo
      output_low(PIN_B5);  //Se desactiva el led
      delay_ms(1000);     
      menu();
}

Ahí llamas a la función menu() que puede ser corta o larga, que puede generar estados incompatibles con lo que estas tratando en la interrupción, o que simplemente mantiene durante mucho tiempo la interrupción viva, sin ser tratada del todo y que por lo tanto puede solaparse con otras interrupciones o incluso consigo misma ....

Una sana practica es habilitar un flag dentro de la interrupción para que sea disparada tu funcion pero ejecutada desde el main() no desde la interrupción.

Yo modificaría tu código de la siguiente forma:

Modo 2.-

int1 ejecutar_menu=0;

#int_EXT
EXT_isr()
{
      output_high(PIN_B5); //Se activa el led
      delay_ms(1000);      //Hacemos una pausa de 1 segundo
      output_low(PIN_B5);  //Se desactiva el led
      delay_ms(1000);     
      ejecutar_menu = 1;
}

main(){

      While(true){
            if(ejecutar_menu==1){
                  ejecutar_menu = 0;
                  menu();
            }
      }
}

Esta forma de hacerlo es muy simple y te aseguras que la funcion menu() no te retrasa la liberación de la rutina de interrupción.

Por otro lado si también deseas que al producirse la interrupción se ejecute cierta rutina una y solo una vez y que hasta que no acabe dicha rutina no permitas una nueva interrupción solo tienes que deshabilitar la interrupción al entrar en ella y habilitarla al terminar ...

Modo 3.-

int1 ejecutar_1_rutina=0;

#int_EXT
EXT_isr()
{
      ejecutar_1_rutina = 1;
}

main(){

      While(true){
            if(ejecutar_1_rutina==1){
                  disable_interrupts(int_ext);
                  ejecutar_1_rutina=0;
                  output_high(PIN_B5);   // Se activa el led
                  delay_ms(1000);         // Hacemos una pausa de 1 segundo
                  output_low(PIN_B5);   // Se desactiva el led
                  delay_ms(1000);     
                  menu();
                  disable_interrupts(int_ext);
            }
      }
}

Y por último una mezcla de ambos mundos, una parte de tu rutina se dispara siempre y otra, el menu, solo una vez y hasta que no concluya completamente no puede volver a dispararse:

Modo 4.-

int1 ejecutar_menu=0;
int1 ejecutando_menu=0;

#int_EXT
EXT_isr()
{
      output_high(PIN_B5); //Se activa el led
      delay_ms(1000);      //Hacemos una pausa de 1 segundo
      output_low(PIN_B5);  //Se desactiva el led
      delay_ms(1000);
      if(ejecutando_menu==0){
            ejecutar_menu = 1;
      }
}

main(){

      While(true){
            if(ejecutar_menu==1){
                  ejecutando_menu=1;
                  ejecutar_menu = 0;
                  menu();
                  ejecutando_menu=0;
            }
      }
}

Con este último método si se producen varias interrupciones consecutivas que se solapen te aseguras de que menu() solo se ejecutará cada vez que haya terminado la ejecución anterior, no todas la veces que ocurra.

Si deseas detectar si has perdido alguna interrupción por el camino solo tienes que unar una variable que las cuente cada vez que se produzcan y poner dicha variable a cero cuando sean convenientemente tratadas ....

Modo 5.-

int1 ejecutar_menu=0;
int1 ejecutando_menu=0;
int  n_interrupciones=0;

#int_EXT
EXT_isr()
{
      ++n_interrupciones;
      output_high(PIN_B5); //Se activa el led
      delay_ms(1000);      //Hacemos una pausa de 1 segundo
      output_low(PIN_B5);  //Se desactiva el led
      delay_ms(1000);
      if(ejecutando_menu==0){
            ejecutar_menu = 1;
      }
}

main(){

      While(true){
            if(ejecutar_menu==1){
                  ejecutando_menu=1;
                  ejecutar_menu = 0;
                  if(n_interrupciones==1){
                        menu_para_una();
                  }
                  else{
                        menu_para_varias();
                  }
                  n_interrupciones=0;
                  ejecutando_menu=0;
            }
      }
}

Bueno, con esto cubres el 90% de casos que se te pueden presentar.

Te suelto todo este rollo porque he aprovechado que he completado mi proyecto Analizador lógico de 3 Canales monitorizado en el PC en el que he estado tratando tres interrupciones externas hasta volverme loco ...  :D  :D  :D

un saludo.

« Última modificación: 12 de Mayo de 2006, 18:29:25 por RedPic »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado vszener

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2395
Re: #INT_Rbo
« Respuesta #6 en: 12 de Mayo de 2006, 20:41:25 »
Modos de hacerlo para dar y regalar!!!jeje


Suerte!!! :wink:
· Nos vemos en los bares!!!!!
· Mi Blog: Aqueronte

Desconectado jfh900

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3595
Re: #INT_Rbo
« Respuesta #7 en: 12 de Mayo de 2006, 22:23:26 »
Yo tube un problema con las interrupciones y encontre ka solucion. Mira este hilo:

http://www.todopic.com.ar/foros/index.php?topic=4889.msg36393#msg36393

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 ORE

  • PIC10
  • *
  • Mensajes: 43
Re: #INT_Rbo
« Respuesta #8 en: 13 de Mayo de 2006, 16:52:20 »
Hola muy buenas,

Bueno, lo primero gracias RedPic, por la sesión magistral sobre el trato de interrupciones. Una de las opciones que me comentas, la habia estado cabilando, ya que uso otra interrupción, en este caso la del desbordamiento del timer0, mediante el metodo de los flags. Esta funciona a las mil maravillas, pero la dichosa interrupción por RB0, ¡¡¡¡¡No hay forma!!!

He probado, la que creo más limpia y ordenada. Solamente se ejecuta una vez, vuelve al programa principal, hace lo que le digo (encender un led), pero ya no vuelve ha atender a la interrupcion, dichosa es ella.

En referencia al hilo que comenta jfh900, estudiaré este tema. Ya que el uso de las interrupciones es una forma muy limpia de programación, aunque imposibilita el atender al programa principal, ya que dejas de hacer lo que estabas haciendo en el programa principal, y ha eso no se como darle solución.

Por cierto he probado, no usar la interrupcion por RB0, y usar un simple if en el programa principal:

if(input(PIN_B0))
                  {
                  while(port_b!=0){}   // No progresamos hasta que ningun pulsador este activo
                  delay_ms(20);
                  menu_teclas();
                  }

y funciona a las mil maravillas, no se si optar por esta opción y no romperme más la cabeza con este tema, aunque soy cabezota y espero encontrar la solucion segun dice jfh900, usando el sistema de RedPic en el caso 2.

Un saludo,

Desconectado ORE

  • PIC10
  • *
  • Mensajes: 43
Re: #INT_Rbo
« Respuesta #9 en: 13 de Mayo de 2006, 17:19:53 »
Hola,

He probado la otra opcion con el siguiente código, y ni siquiera entra en la interrupcion:

#int_EXT
EXT_isr()
         {
         output_high(PIN_B5); //Se activa el led
         delay_ms(1000);      //Hacemos una pausa de 1 segundo
         output_low(PIN_B5);  //Se descactiva el led
         delay_ms(1000);      //Y volvemos a ejecutar el bucle infinito
         interrupcion();
         #asm movf port_b,0 #endasm
         }
         
void main()
{

   enable_interrupts(INT_EXT);   //activar interrupcion externa
   enable_interrupts(GLOBAL);      //todas las interrupciones desactivadas

   for(;;){
            output_high(PIN_B7); //Se activa el led
            delay_ms(1000);      //Hacemos una pausa de 1 segundo
            output_low(PIN_B7);  //Se descactiva el led
            delay_ms(1000);      //Y volvemos a ejecutar el bucle infinito
   }//bucle infinito esperando interrupcion
}

Va ha acabar conmigo esta interrupcion....