interrupts disabled during call to preven re-entrancy:@MULFF

Adjuntaré el código para que puedan verlo.
Código:
#include <16F877A.h>
 
/* Palabra de configuracion*/
 
#FUSES XT,PUT, NOBROWNOUT,NOLVP,CPD // //Oscilador del tipo XT.                    
 
#device ADC=10
/*DEFINIMOS LA FRECUENCIA DEL OSCILADOR*/
#use delay(crystal=2000000) ////Frecuencia de 2 MHz para el cristal de cuarzo.
#include <math.h>              //Libreria necesaria para operaciones matematicas.
#include <kbd.c>
 
/////////////////////////////////////////////////////////////////////////////////////
//------------------------configuracion del LCD------------------------------------//
////////////////////////////////////////////////////////////////////////////////////
 
                                       ///////////////////////////////
#define LCD_ENABLE_PIN  PIN_B1         //        Asignamos los      //
#define LCD_RS_PIN      PIN_B2         //           pines           //
#define LCD_RW_PIN      PIN_B3         //            del            //
#define LCD_DATA4       PIN_B4         //            LCD            //
#define LCD_DATA5       PIN_B5         //                           //
#define LCD_DATA6       PIN_B6         ///////////////////////////////
#define LCD_DATA7       PIN_B7 
#include <lcd.c>
 
#use fast_io(c)//declaramos la librería para la configuración del registro tris
#use fast_io(b)//le damos eficiencia al puertoB
#use fast_io(d)// EFICIENCIA AL PUERTO D PARA MUESTRA DELA SEÑAL DE MUESTREO
#byte PIR1 = 0x0C
#bit TMR1IF = PIR1.0
 
////////////////////////////////////////////////////////////////////////////////
int1 cambio=0; //Variable de control de cambio.                               //
///////////////////////////////////////////////////////////////////////////////
 
/////////////////////////////////////////////////////////////////////////////////////////
////Variables creadas destinadas para la medicion de Temperatura en distintas unidades.//
//------------------------CONFIGURAMOS LAS VARIABLES-----------------------------------//
/////////////////////////////////////////////////////////////////////////////////////////
 
int16 sensor;
float cent;//centigrados
float kelv;//kelvin
float Farh;//faranheit
int   code=2;
 
///////////////////////////////////////////////////////////////////////////////////////
//// -----------------------------Disposición del teclado---------------------------///
//////////////////////////////////////////////////////////////////////////////////////
 
char const map_keys[4][4] = {{\'7\',\'8\',\'9\',\'A\'},
                             {\'4\',\'5\',\'6\',\'B\'},
                             {\'1\',\'2\',\'3\',\'C\'},
                             {\'*\',\'0\',\'#\',\'D\'}};
 
 
////////////////////////////interrupcion timer1 //////////////////////////////////////
 
#INT_TIMER1    
void  interrupcion_tmr1() // funcion que se ejecutara al desbordar timer1    
{
   set_timer1(34286);  //se vuelve a cargar valor de timer1
   output_toggle(pin_d0); //(SALIDA DELA SEÑAL CONFIGURANDO)
   sensor=read_adc();                   //LEE LA CONVERCION ANALOGA DIGITAL ADC
   cent = (float)(sensor)*500.0/1023.0 ;//VALOR EN C° DE CONVERSION
   kelv = cent+273.15;                  //VALOR CONVERTIDO °C  A °K
   farh = cent*1.8+32.0;                //VALOR CONVERTUDO °C A F
}
 
//////////////////////////////////////////////////////////////////////////////////////
 
#INT_EXT          //  (DIRECTICA)se refiere a interrupcion por puerto RB0
void interrupcion_rb0(void)//FUNCION QUE SE EJECUTAR AL DEBORDAR EL RB0
{
   int aux,i,j,scancode;
   aux = 0B11111110;
   output_c(aux);
 
   for (i=0;i<4;i++) //una secuencia de números reunidos en una sola variable.
                     //es un array
   {                     //////////////////////////////
      if(!input(pin_c4)) // codigo de funcionamiento //
      {                  // de teclado matricial 4x4 //
         j=0;            //por metodo de interrupcion//
         break;           //////////////////////////7//
      }
      if(!input(pin_c5))
      {
         j=1;
         break;
      }
      if(!input(pin_c6))
      {
         j=2;
         break;
      }
      if(!input(pin_c7))
      {
         j=3;
         break;
      }
      aux <<=1;   
      output_c(aux);
   }
   scancode=map_keys[i][j];
   if(scancode==\'*\'){      //Integrantes
      code=0b00000001;
   }
   if(scancode==\'8\'){      //Temp en °C
      code=0b00000010;
   }
   if(scancode==\'6\'){      //Temp en °K
      code=0b00000100;
   }
   if(scancode==\'C\'){      //Temp en °F
      code=0b00001000;
   }
   output_c(0b11110000);
 
}
 
////////////////////////////////////////////////////////////////////////////////////////
 
#int_ccp1
void ccp1_int(){                 //Funcion de interrupcion.
  if(++cambio==1){
    setup_ccp1(CCP_COMPARE_CLR_ON_MATCH);  //Modo comparacion, cambio a 0.
  } else{
    setup_ccp1(CCP_COMPARE_SET_ON_MATCH);//Modo comparacion, cambio a 1.
  }
  set_timer1(0);     //Borrado
  CCP_1=199;         //Inicializacion del registro CCPR2 para un duty del 50%.
}
 
////////////////////////////////////////////////////////////////////////////////////////////////////
 
void main()
{
   set_tris_a(0b11111111);//Configurando las lineas del puerto A como entradas.
   set_tris_b(0b00000001); //Puerto con solo 1 linea como entrada.
   set_tris_c(0b11110000); //Puerto C con 4 entradas y 4 salidas.
   set_tris_d(0b11111110);   //Puerto D con 1 linea como salida.
   output_c(0b11110000);   //Puerto D con 1 linea como salida.
 
   setup_adc_ports(AN0_AN1_AN3);
   setup_adc(ADC_CLOCK_INTERNAL);
   output_toggle(pin_d0);
   set_adc_channel(3);
   ext_int_edge(H_TO_L);// interrupcion externa  y la activa con flanco de bajada
                        //RESUMIENDO Cambio de estado de alto a bajo
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
disable_interrupts(global);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);     //Configuracion timer 1.
setup_ccp1(CCP_COMPARE_SET_ON_MATCH);  //Configuracion inicial del modulo CCP.
CCP_1=199;
 
enable_interrupts(int_ccp1);    //Habilitacion interrupcion modulo CCP2.
enable_interrupts(global);     //Habilita la interrupción de forma global.
 
//////////////////////////////////////////////////////////////////////////////////  
  delay_ms(20);//RETARDO DE 30 MILISEGUNDOS
  lcd_init(); //inicializa el LCD
 
    /*Calculo:
      Desborde cada 800ms
      Predivisor timer1 =8;
      Periodo de instruccion = 2us
      Debemos cargar el timer1 con:
         timer1=2^16-(800ms)/(2us*4)
         timer1=15536
   */  
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);  //// preescalador de 8  
   set_timer1(15536);      // EL NUMERO HALLADO NOS INDICA EL INICIO DE LA INTERRUPCION
   enable_interrupts(INT_EXT);  //Habilita la interrupción RBO
   enable_interrupts(INT_TIMER1);  //HABILIT EL TIMER 0
   enable_interrupts(GLOBAL);  //Habilita la interrupción de forma global.
 
   while(TRUE)
     {
      if(bit_test(code,1))
      {
         lcd_gotoxy(1,1);
         printf(lcd_putc, "   TEMPERATURA   ");  
         lcd_gotoxy(1,2);
         printf(lcd_putc, "     %3.1f oC      ",cent); 
      } 
      if(bit_test(code,3))
      {
         lcd_gotoxy(1,1);
         printf(lcd_putc, "   TEMPERATURA   ");  
         lcd_gotoxy(1,2);
         printf(lcd_putc, "     %3.1f oF      ",farh); 
      }
      if(bit_test(code,2))
      {
         lcd_gotoxy(1,1);
         printf(lcd_putc, "   TEMPERATURA   ");  
         lcd_gotoxy(1,2);
         printf(lcd_putc, "     %3.1f oK      ",kelv);
      }
      if(bit_test(code,0))
      {  lcd_gotoxy(1,1);
         printf(lcd_putc, "   ..........  ");  //rellenar siempre con 16 espacios
         lcd_gotoxy(1,2);                       //
         printf(lcd_putc, "   ..........   ");  // si  se quiere mas rapido realizar un clear & home(\\f)
         delay_ms(900);
         lcd_putc("\\f");
 
         lcd_gotoxy(1,1);
         printf(lcd_putc, "     ..........     ");  //rellenar siempre con 16 espacios
         lcd_gotoxy(1,2);                       //
         printf(lcd_putc, "................");  // si  se quiere mas rapido realizar un clear & home(\\f)
         delay_ms(900);
         lcd_putc("\\f");
         lcd_gotoxy(1,1);
         printf(lcd_putc, "     .......  ");  //rellenar siempre con 16 espacios
         lcd_gotoxy(1,2);                       //
         printf(lcd_putc, " .......... ");  // si se quiere mas rapido realizar un clear & home(\\f)
         delay_ms(900);
         lcd_putc("\\f");
         lcd_gotoxy(1,1);
         printf(lcd_putc, "     ........      ");  //rellenar siempre con 16 espacios
         lcd_gotoxy(1,2);                       //
         printf(lcd_putc, " ...................");  //  si se quiere mas rapido realizar un clear & home(\\f)
         delay_ms(900);
 
 
      }
     }
   }
 
Última edición por un moderador:
Pues por eso para que no hagas una rutina reentrante, que normalmente no se puede.
No puedes llamar a una función desde si misma, o si, depende del caso y del uso.
En tu caso no deberías.
 
Adjuntare el codigo para que puedan verlo gracias .
Buenas.
Ese warning sale porque estas utilizando la lectura y conversión dentro de la interrupción del timer1. Si lo que quieres es leer el adc cada cierto tiempo puedes aumentar una variable por desborde del timer1, y cuando esa variable sea igual al tiempo que le asignaste lea y haga la conversión dentro de tu while.
 
buenoo debo sacar el #INT_TIMER1 ???? y colocarlo en while de void main ...........????????????????? si hago eso ya trabajaria por consultaa o nooo .

ya que necesito que trabaje por interrupcion en el timer 1 o de que manera debo aserloo ??? si me pueden corregirmelo gracias de antemano
 
Esa advertencia se da más que nada cuando se usan rutinas que necesitan retardos, como escribir en pantalla, leer el conversor adc, etc.
O simplemente por usar retardos dentro de los servicios de interrupción.
 
Una forma sencilla de eliminar ese problema, es poner #INLINE previamente a la funcion que es llamada dentro de la interrupcion. (en la declaracion de la misma)

Esto cuesta mas memoria, ya que cada llamada a la funcion en el codigo en realidad lo que va a hacer es copiarla en ese lugar, generando redundancia.

Si vas bien de memoria, te lo recomiendo ya que la deshabilitacion automatica de interrupciones puede desbaratar algunos planes.
 
Algo que resulta más conveniente, es sacar las rutinas conflictivas del servicio de interrupción y procesarlas en el bucle main cuando cambie de estado una bandera.

Por ejemplo, en el caso de ese programa:
Código:
[COLOR=Red][B]#INT_TIMER1    [/B][/COLOR]
[COLOR=Blue]void[/COLOR] interrupcion_tmr1()
{
   output_toggle(pin_d0);
   set_timer1([COLOR=DarkGreen]34286[/COLOR]);
   flag_conversion = [COLOR=DarkGreen]1[/COLOR];
}
Ya dentro del bucle del main se procesan:
Código:
     [COLOR=Blue]if[/COLOR](flag_conversion)
     {
         sensor = read_adc();
         cent = (([COLOR=Blue]float[/COLOR]) (sensor * [COLOR=DarkGreen]500.0[/COLOR]) / [COLOR=DarkGreen]1023.0[/COLOR]);
         kelv = cent + [COLOR=DarkGreen]273.15[/COLOR];
         farh = ((cent * [COLOR=DarkGreen]1.8[/COLOR]) + [COLOR=DarkGreen]32.0)[/COLOR];
         flag_conversion = [COLOR=DarkGreen]0[/COLOR];
      }
 
Última edición:
eh puesto el #INLINE en la funcion que es llamada dentro de la interrupcion ...... y me sigue saliendo warning o me estoy equivocando me podria ayudar exactamente como debo cambiar eesoo y gracias de antemano por la ayuda
 
¿Me podría ayudar exactamente como debo cambiar eso?
Ahí arriba expuse cómo lo puedes hacer para que no obtengas esa advertencia y optimices el programa.

Ahora compila el programa con ese agregado:
PHP:
#include <16F877A.h>

/* Palabra de configuracion*/

#FUSES XT,PUT, NOBROWNOUT,NOLVP,CPD // //Oscilador del tipo XT.                    

#device ADC=10
/*DEFINIMOS LA FRECUENCIA DEL OSCILADOR*/
#use delay(crystal=2000000) ////Frecuencia de 2 MHz para el cristal de cuarzo.
#include <math.h>              //Libreria necesaria para operaciones matematicas.
#include <kbd.c>

/////////////////////////////////////////////////////////////////////////////////////
//------------------------configuracion del LCD------------------------------------//
////////////////////////////////////////////////////////////////////////////////////

                                       ///////////////////////////////
#define LCD_ENABLE_PIN  PIN_B1         //        Asignamos los      //
#define LCD_RS_PIN      PIN_B2         //           pines           //
#define LCD_RW_PIN      PIN_B3         //            del            //
#define LCD_DATA4       PIN_B4         //            LCD            //
#define LCD_DATA5       PIN_B5         //                           //
#define LCD_DATA6       PIN_B6         ///////////////////////////////
#define LCD_DATA7       PIN_B7 
#include <lcd.c>

#use fast_io(c)//declaramos la librería para la configuración del registro tris
#use fast_io(b)//le damos eficiencia al puertoB
#use fast_io(d)// EFICIENCIA AL PUERTO D PARA MUESTRA DELA SEÑAL DE MUESTREO
#byte PIR1 = 0x0C
#bit TMR1IF = PIR1.0

////////////////////////////////////////////////////////////////////////////////
int1 cambio=0; //Variable de control de cambio.                               //
///////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////
////Variables creadas destinadas para la medicion de Temperatura en distintas unidades.//
//------------------------CONFIGURAMOS LAS VARIABLES-----------------------------------//
/////////////////////////////////////////////////////////////////////////////////////////

int16 sensor;
float cent;//centigrados
float kelv;//kelvin
float Farh;//faranheit
int   code=2;
int1 flag_conversion = 0;

///////////////////////////////////////////////////////////////////////////////////////
//// -----------------------------Disposición del teclado---------------------------///
//////////////////////////////////////////////////////////////////////////////////////

char const map_keys[4][4] = {{'7','8','9','A'},
                             {'4','5','6','B'},
                             {'1','2','3','C'},
                             {'*','0','#','D'}};


////////////////////////////interrupcion timer1 //////////////////////////////////////

#INT_TIMER1    
void  interrupcion_tmr1()
{
   output_toggle(pin_d0);
   set_timer1(34286);
   flag_conversion = 1;
}

//////////////////////////////////////////////////////////////////////////////////////

#INT_EXT          //  (DIRECTICA)se refiere a interrupcion por puerto RB0
void interrupcion_rb0(void)//FUNCION QUE SE EJECUTAR AL DEBORDAR EL RB0
{

   int aux,i,j,scancode;
   aux = 0B11111110;
   output_c(aux);

   for (i=0;i<4;i++) //una secuencia de números reunidos en una sola variable.
                     //es un array
   {                     //////////////////////////////
      if(!input(pin_c4)) // codigo de funcionamiento //
      {                  // de teclado matricial 4x4 //
         j=0;            //por metodo de interrupcion//
         break;           //////////////////////////7//
      }
      if(!input(pin_c5))
      {
         j=1;
         break;
      }
      if(!input(pin_c6))
      {
         j=2;
         break;
      }
      if(!input(pin_c7))
      {
         j=3;
         break;
      }
      aux <<=1;   
      output_c(aux);
   }
   scancode=map_keys[i][j];
   if(scancode=='*'){      //Integrantes
      code=0b00000001;
   }
   if(scancode=='8'){      //Temp en °C
      code=0b00000010;
   }
   if(scancode=='6'){      //Temp en °K
      code=0b00000100;
   }
   if(scancode=='C'){      //Temp en °F
      code=0b00001000;
   }
   output_c(0b11110000);
   
}

////////////////////////////////////////////////////////////////////////////////////////

#int_ccp1
void ccp1_int()                 //Funcion de interrupcion.
{

  if(++cambio==1){
    setup_ccp1(CCP_COMPARE_CLR_ON_MATCH);  //Modo comparacion, cambio a 0.
  } else{
    setup_ccp1(CCP_COMPARE_SET_ON_MATCH);//Modo comparacion, cambio a 1.
  }
  set_timer1(0);     //Borrado
  CCP_1=199;         //Inicializacion del registro CCPR2 para un duty del 50%.
  
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void main()
{

   //set_tris_a(0b11111111);//Configurando las lineas del puerto A como entradas.
   set_tris_b(0b00000001); //Puerto con solo 1 linea como entrada.
   set_tris_c(0b11110000); //Puerto C con 4 entradas y 4 salidas.
   set_tris_d(0b11111110);   //Puerto D con 1 linea como salida.
   output_c(0b11110000);   //Puerto D con 1 linea como salida.
   
   setup_adc_ports(AN0_AN1_AN3);
   setup_adc(ADC_CLOCK_INTERNAL);
   output_toggle(pin_d0);
   set_adc_channel(3);
   ext_int_edge(H_TO_L);// interrupcion externa  y la activa con flanco de bajada
                        //RESUMIENDO Cambio de estado de alto a bajo
   
///////////////////////////////////////////////////////////////////////////////////////////////////////////

disable_interrupts(global);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);     //Configuracion timer 1.
setup_ccp1(CCP_COMPARE_SET_ON_MATCH);  //Configuracion inicial del modulo CCP.
CCP_1=199;

enable_interrupts(int_ccp1);    //Habilitacion interrupcion modulo CCP2.
enable_interrupts(global);     //Habilita la interrupción de forma global.
  
//////////////////////////////////////////////////////////////////////////////////  
  delay_ms(20);//RETARDO DE 30 MILISEGUNDOS
  lcd_init(); //inicializa el LCD
   /*
    Calculo:
      Desborde cada 800ms
      Predivisor timer1 =8;
      Periodo de instruccion = 2us
      Debemos cargar el timer1 con:
         timer1=2^16-(800ms)/(2us*4)
         timer1=15536
   */
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);  //// preescalador de 8  
   set_timer1(15536);      // EL NUMERO HALLADO NOS INDICA EL INICIO DE LA INTERRUPCION
   enable_interrupts(INT_EXT);  //Habilita la interrupción RBO
   enable_interrupts(INT_TIMER1);  //HABILIT EL TIMER 0
   enable_interrupts(GLOBAL);  //Habilita la interrupción de forma global.

   while (true)
   {
     if(flag_conversion)
     {
         sensor=read_adc();
         cent = ((float) (sensor *500.0)/1023.0);
         kelv = cent+273.15;
         farh = (cent * 1.8) + 32.0;
         flag_conversion = 0;
      }

      
      if(bit_test(code,1))
      {
         lcd_gotoxy(1,1);
         printf(lcd_putc, "   TEMPERATURA   ");  
         lcd_gotoxy(1,2);
         printf(lcd_putc, "     %3.1f oC      ",cent); 
      } 
      
      if(bit_test(code,3))
      {
         lcd_gotoxy(1,1);
         printf(lcd_putc, "   TEMPERATURA   ");  
         lcd_gotoxy(1,2);
         printf(lcd_putc, "     %3.1f oF      ",farh); 
      }
      
      if(bit_test(code,2))
      {
         lcd_gotoxy(1,1);
         printf(lcd_putc, "   TEMPERATURA   ");  
         lcd_gotoxy(1,2);
         printf(lcd_putc, "     %3.1f oK      ",kelv);
      }
      
      if(bit_test(code,0))
      {  lcd_gotoxy(1,1);
         printf(lcd_putc, "   ..........  ");  //rellenar siempre con 16 espacios
         lcd_gotoxy(1,2);                       //
         printf(lcd_putc, "   ..........   ");  // si se quiere mas rapido realizar un clear & home(\f)
         delay_ms(900);
         lcd_putc("\f");
         
         lcd_gotoxy(1,1);
         printf(lcd_putc, "     ..........     ");  //rellenar siempre con 16 espacios
         lcd_gotoxy(1,2);                       //
         printf(lcd_putc, "................");  // si se quiere mas rapido realizar un clear & home(\f)
         delay_ms(900);
         lcd_putc("\f");
         lcd_gotoxy(1,1);
         printf(lcd_putc, "     .......  ");  //rellenar siempre con 16 espacios
         lcd_gotoxy(1,2);                       //
         printf(lcd_putc, " .......... ");  // si se quiere mas rapido realizar un clear & home(\f)
         delay_ms(900);
         lcd_putc("\f");
         lcd_gotoxy(1,1);
         printf(lcd_putc, "     ........      ");  //rellenar siempre con 16 espacios
         lcd_gotoxy(1,2);                       //
         printf(lcd_putc, " ...................");  // si se quiere mas rapido realizar un clear & home(\f)
         delay_ms(900);    // Este retardo debe afectar todo el proceso.
         
      
      }
      
     }
   }
 
Última edición:
Lo que te dice DarkBytes es correcto aunque no siempre se puede aplicar.

Si alguna vez necesitas usar #INLINE, asegurate que la funcion que tiene esa declaracion no tiene llamadas "camufladas" a funciones, como por ejemplo, delays o cualquier otra llamada a funcion que no es inline. Ya que si es asi terminas en la misma y los warnings van a seguir saliendo.
 
Muy buenas con todos.
Tengo problemas con mi programa de sensor de temperatura, donde el periodo de muestreo se generará con el Timer 1 y el módulo CCP1 en modo comparación por interrupción y que me convierte de centígrados a Kelvin y Faranheit.
Tal como se muestra en el archivo adjunto de proteus .

Bueno, el problema está que cuando pongo el CCP1 no me funciona la conversión de "°F" y no me cambia cuando varió los voltajes de entrada del sensor.
Debería cambiarme como el de centígrados Kelvin y cuando tecleo dos veces, "°C" se me cuelga y no hace la conversión.

Ahora, cuando implementé este trabajo no me funciona para nada la tecla de grados Faranheit, que es la tecla C, pero cuando borro el CCP1, me funciona perfectamente.


¿Alguien podría decirme dónde me estoy equivocando?
Gracias de antemano.

Adjunto el código y simulación en proteus.
 
Última edición:
Buenas.
El error que veo en tu código es que la conversión de grados Celcius lo estas haciendo dentro del bucle IF, por lo tanto la conversiones de las otras temperaturas que también están dentro de los bucles IF no se podrán actualizar, deberías poner las conversiones dentro de tu While.
Ademas algunas de las llaves de tu Bucle If estan mal debes ver eso tambien.
El Codigo deberia ser asi:
Código:
  while(TRUE)
     {
     cent = (float)(sensor)*500.0/1023.0 ;//VALOR EN C° DE CONVERSION
      if(bit_test(code,1))
      {//cent = (float)(sensor)*500.0/1023.0 ;//VALOR EN C° DE CONVERSION
         lcd_gotoxy(1,1);
         printf(lcd_putc, "   TEMPERATURA   ");  
         lcd_gotoxy(1,2);
         printf(lcd_putc, "     %3.1f oC      ",cent); 
      } 
    
      if(bit_test(code,2))
      {kelv = cent+273.15;
         lcd_gotoxy(1,1);
         printf(lcd_putc, "   TEMPERATURA   ");  
         lcd_gotoxy(1,2);
         printf(lcd_putc, "     %3.1f oK      ",kelv);
      }
      if(bit_test(code,3))
      {Farh = cent*1.8+32.0;
         lcd_gotoxy(1,1);
         printf(lcd_putc, "   TEMPERATURA   ");  
         lcd_gotoxy(1,2);
         printf(lcd_putc, "     %3.1f oF      ",Farh);
      }
 
Última edición:
Muchas gracias roberttorres ya me ah funcionado a ala perfeccion cada vez voy aprendiendo mas que el orden es fundamental en la programación .
 
Última edición:
Atrás
Arriba