TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: escarrillense en 28 de Febrero de 2013, 05:51:18

Título: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 28 de Febrero de 2013, 05:51:18
Hola buenas días!

Llevo un tiempo siguiendo este foro para aprender lenguaje C pero pocas veces me he animado a escribir en el.
Estoy creando un sistema de alarma mediante una contraseña y una interrupción. El programa funcionaba perfectamente,la parta de grabación y comprobación de contraseña, pero al añadirle la interrupción externa no me funciona y la parte de la interrupción por separado si. Es una cosa un poco rara porque si elimino el cable que une el pin del micro correspondiente a la interrupción del interruptor que la genera, el programa funciona correctamente excepto lo que es la interrupción.
Estoy utilizando un PIC16F876, la versión de Proteus que empleo es la 7.7 y el compilador es CCS.
Aquí les dejo el programa para ver si me podeis ayudar. Tambien adjunto los diferentes archivos del programa con la libreria del teclado y el esquema del circuito electrico.

#fuses XT            //Crystal osc <= 4mhz               
#fuses NOWDT         //deshabilita el Watch Dog Timer
#fuses NOPROTECT     //deshabilita la proteccion del codigo del pic
#fuses PUT           //habilita el reseteo de power up timer
#fuses NOLVP         //No Low Voltage Programming on B3(PIC16) or B5(PIC18,no habilita la programacion en bajo voltaje)
#fuses NOBROWNOUT    //No Reset when brownout detected

#use delay(clock = 4000000)

#use fast_io(A)       //con esta instruccion evitamos que
#use fast_io(B)       //se este configurando cada vez que usamos
#use fast_io(C)       //alguna instruccion de entrada o salida
#BYTE TRISA = 0b10000101   //TRISA = 0x85
#BYTE PORTA = 0b00000101   //PORTA = 0x05
#BYTE TRISB = 0b10000110   //TRISB = 0x86
#BYTE PORTB = 0b00000110   //PORTB = 0x06
#BYTE TRISC = 0b10000111   //TRISC = 0x87
#BYTE PORTC = 0b00000111   //PORTC = 0x07

#include <kbd3x4_2.c>         //libreria manejo keypad 3x4
#include <lcd3.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas

#rom 0x2100={0,0,0,0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h



////////////////DEFINICION DE FUNCIONES////////////////////////////

void menu_principal(void);             //funcion que muestra el menu principal
void escribir_clave(char clave[]);     //funcion que escibre la clave tecleada
void cambia_clave_inicial(void);       //funcion que cambia clave
void cambiar_clave(void);              //funcion que cambia clave
int comparar_claves(int);              //función que compara las claves
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void activar_alarma(void);             //funcion que activa la alarma
void desactivar_alarma(void);          //funcion que desactiva la alarma
void escribir_clave_en_eeprom(int);    //función que escribe las claves en la memoria eeprom
void leer_clave_en_eeprom(int);        //función que lee las claves y las guarda en su correspondiente variable
void alarma_general(void);             //funcion que enciende la sirena
void conteo_intentos(void);            //funcion que cuenta el numero de intentos de ingreso de contraseña



////////////////VARIABLES GLOBALES///////////////////////////

char clave_inicial[3]= {'1','2','3'};  //variable usada como clave de inicio
char clave_eeprom_admin[3];            //variable usada para comparar los datos de la eeprom contra los datos ingresados             
char clave[3];                         //variable usada para recoger la clave tecleada
char k;                                //variable usada para recoger las teclas pulsadas del teclado
signed char i;                         //variable usada para movernos por las posiciones de la memoria
char clave_introducida[3]={};          //variable usada para los datos ingresados
int alarm_cont=0;                      //variable global que cuenta los fallos
int flag;                             //variable usada como bandera para las interrupciones


//////////////////LLAMADA FUNCION INTERRUPCION//////////////
#int_ext
void int_ext_isr(void)  //funcion que detecta la interrupcion

{
   /* //disable_interrupts(INT_EXT);
   //disable_interrupts(GLOBAL);
    flag=1;    //Se habilita la bandera cuando ocurre una interrupcion.
    //enable_interrupts(INT_EXT);
   //enable_interrupts(GLOBAL);*/
   
   /*set_tris_c(0b11100000);      //pines C0 hasta C4 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 10 seg y muestra mensaje
    //lcd_putc("\fALARMA\n");         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    alarm_cont = 0;              //pongo a cero el contador de errores
    //break;
    //desactivar_alarma();*/
   
    //clear_interrupt(int_ext);    //ponemos a '0' el flag
   
   int puerto_1;
   disable_interrupts(INT_ext); //deshabilita las interrupciones
   puerto_1 = PORTB & 0b00000001; //lee portb y lo guarda en puerto_1
      if(puerto_1!=0) //si se presionó una tecla (flanco hacia arriba)
      {
         output_b(0x00);                              //aclaro el puerto b
      }
   flag=1;
   set_tris_b(0b00001111);
   output_b(0x0f);
   clear_interrupt(INT_ext);
   enable_interrupts(INT_ext);
}



////////////////////PROGRAMA PRINCIPAL//////////////////////
void main()

{
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_CLOCK_DIV_2);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   
   flag=0;                       //pongo la variable de la bandera a '0'
   set_tris_b(0b00001111);       //configuro el puerto b
   set_tris_c(0b11100000);       //configuro el puerto c
   port_b_pullups(true);         //activo las resistencias de pullup
   ext_int_edge(L_TO_H);         //activo la interrupcion externa por cambio de bajo a alto
   clear_interrupt(int_ext);     //pongo a '0' el flag de la interrupcion externa
   enable_interrupts(int_ext);   //habilito la interrupcion externa
   enable_interrupts(GLOBAL);    //habilito las interrupciones
   
   
   lcd_init();            //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   
   
   while(true)
   {
     if(flag==1)
      {
         //disable_interrupts(int_ext);  //deshabilitamos la interrupcion externa
         //clear_interrupt(int_ext);     //ponemos a '0' el flag
         flag=0;                       //ponemos la variable flag a '0'
         delay_ms(20);                 //antirrebote
         alarma_general ();            //activamos la alarma
         flag=0;                       //ponemos la variable flag a '0'
         //enable_interrupts(int_ext);   //habilito la interrupcion externa
      }
      else
      {
         cambia_clave_inicial();    //cambio la contraseña que viene por defecto
         menu_principal();          //voy al menu principal
      }
   }
   
}


//////////FUNCION CAMBIAR CLAVE INICIAL
void cambia_clave_inicial(void)             //funcion que cambia clave administrativa

{
int p;
   clave_introducida=0;                //pongo la clave tecleada a 0
   escribir_clave(clave_introducida);  //tecleo la contraseña
   p=strcmp(clave_introducida , clave_inicial);    //comparo la clave por defecto con la tecleada
   if (p==0)                           //si las dos claves son iguales:
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          nueva_clave_admin();      //introduzco la nueva clave
         }
   if (p!=0)                        //si las dos claves son distintas
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;      //borro la clave introducida
          //conteo_intentos();
          alarma_general ();        //activo la alarma
         }
}

//////////FUNCION ESCRIBIR NUEVA CLAVE
void escribir_clave(char clave[])            //funcion que escibre la clave tecleada

{
int i=0;
   lcd_putc("\fEscribir clave:\n");   //presentacion
   do{
         do{               //espera hasta...
            k=kbd_getc();   
           }while(k==0);   //...pulsar una tecla
         
            if(!(k=='*' || k=='#')) // Si no es '*' o '#' en la pantalla aparece un '*'
            {     
            lcd_putc("*");
            clave=k;
            }       
     i++;
     
     }while( !(k=='*' || k=='#') );        //Si '*' o '#' señalamos que hemos terminado de introducir la contraseña
}



/////FUNCION MENU PRINCIPAL   
void menu_principal (void)             //funcion que muestra el menu principal

{
     for(; ;)
    {
      lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
      do{               //espera hasta...
         k=kbd_getc();   
         }while(k==0 || k==1);   //...pulsar una tecla
     
     switch (k)
     {
      case '0':         //si '0' va a activar la alarma
         activar_alarma();
      break;
      case '1':         //si '1' va a comprobar clave para despues cambiar la clave
         cambiar_clave();
      break;
     }
    }   
}


//////////FUNCION CAMBIAR CLAVE
void cambiar_clave(void)             //funcion que cambia clave administrativa

{
int p;
   escribir_clave(clave_introducida);  //escribimos la contraseña
   leer_clave_en_eeprom(i);            //lee la contraseña que antes hemos cambiado
   p=comparar_claves(i);               //compara ambas claves
   if (p==0)                           //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          nueva_clave_admin();         //vamos a la rutina para introducir la nueva clave
         }
   if (p!=0)                           //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;         //borra la clave ahora introducida
          alarma_general ();           //activa la alarma
         }
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)                 //funcion que añade la nueva clave administrativa

{
int i=0;
   lcd_putc("\fNueva clave:\n");   //presentacion
   do{
         do{               //espera hasta...
            k=kbd_getc();   
           }while(k==0);   //...pulsar una tecla
         
            if(k!='*' || k!='#')    // Si no es '*' o '#' en la pantalla aparece un '*'   
            {     
            lcd_putc("*");
            clave=k;
            }
     escribir_clave_en_eeprom(i);   //guardamos la nueva clave en la memoria EEPROM
     i++;
     
     }while( !(k=='*' || k=='#') );       //Si '*' o '#' señalamos que hemos terminado de introducir la contraseña
}


//////////FUNCION COMPARAR CLAVES
int comparar_claves(int)                  //funcion que compara la clave administrativa y la introducida

{
int i=0;
int s=0;
   for (i=0;i<3;i++)    //comparo caracter a caracter las claves
   {
      if (clave_introducida==clave_eeprom_admin)   //si el caracter es igual en las dos claves
        s++;                                             //paso al siguiente caracter
      else                                               //si es distinto la contraseña es incorrecta
        {s=0;
         lcd_putc("\fClave Incorrecta\n");
         break;
        }
   }
   if (s==3)                           //si todos los tres caracteres son iguales
      return 0;                        //devuelvo un '0'
}


//////////ACTIVAR ALARMA
void activar_alarma(void)           //funcion que activa la alarma

{
int i=0;
int p=0;
   escribir_clave(clave_introducida);     //escribimos la contraseña
   leer_clave_en_eeprom(i);               //lee la contraseña administrativa grabada anteriormente en la EEPROM
   p=comparar_claves(i);                  //compara ambas claves
   if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma Activada");
          delay_ms(2000);
          desactivar_alarma();            //vamos a la rutina para desactivar la alarma
         }
   if (p!=0)                                 //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;               //borra la clave ahora introducida
          alarma_general ();                 //activo la alarma
         }
}


//////////DESACTIVAR ALARMA
void desactivar_alarma(void)           //funcion que desactiva la alarma

{
int i=0;
int p=0;
   lcd_putc("\fDesactivar alarma\n");   //presentacion
   escribir_clave(clave_introducida);  //escribimos la contraseña
   leer_clave_en_eeprom(i);            //lee la contraseña administrativa grabada anteriormente en la EEPROM
   p=comparar_claves(i);               //compara ambas claves
   if (p==0)                           //si son iguales...
         {lcd_putc("\fAlarma\nDesactivada");
          delay_ms(2000);
          break;                          //vuelve al menu principal
         }
   if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;            //borra la clave ahora introducida
          alarma_general ();              //activo la alarma
         }
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int i)     //función que escribe las claves en la memoria eeprom

{
   write_eeprom (i,k);             //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                   //en la direccion i + 0 (para no pisar datos) de la eeprom
   i++;                            //en una palabra escribe de la posicion 0 a la 4 (5 lugares)
}


//////////LEER_CLAVE_EN_EEPROM
void leer_clave_en_eeprom(int i)       //función que lee las claves y las guarda en su correspondiente variable

{
    for (i=0;i<3;i++)
    {
      clave_eeprom_admin = read_eeprom(i);      //guardamos cada valor de la direccion i + 0 (para no pisar datos)
      delay_ms(20);                                //de la eeprom en la variable global correspondiente
    }
}



////////////FUNCION CONTEO INTENTOS
/*void conteo_intentos(void)             //funcion que cuenta el numero de intentos de ingreso de contraseña

{
   if (alarm_cont==3)
   {
      alarma_general();
   }
   else
   {
      alarm_cont++;
   }
}*/


//////////FUNCION ALARMA GENERAL
void alarma_general (void)

{
    set_tris_c(0b11100000);      //pines C0 hasta C4 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 10 seg y muestra mensaje
    //lcd_putc("\fALARMA\n");         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    alarm_cont = 0;              //pongo a cero el contador de errores
    //break;
    //desactivar_alarma();
}

Muchas gracias por todo de antemano
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 07 de Marzo de 2013, 05:40:01
Buenos días!

Aquí sigo con mi problema. Dándole muchas vueltas al asunto he descubierto que el problema creo que es la librería del teclado o como la gestiono en el programa ya que se produce un lío si a la vez el programa esta atento a la interrupción. Ya les informare de posibles avances o si alguien me puede ayudar se lo agradecería ya que llevo mucho tiempo atascado con este problema
Título: Re: Problema con interrupcion externa y teclado
Publicado por: Vayadespiste en 08 de Marzo de 2013, 02:47:56
Hola, solo he mirado un poquito el archivo del teclado (no soy experto :( ) por lo poquito que he podido ver en la librería del teclado inicialmente está el nible bajo como entrada y con pull-up activado, es decir que inicialmente está a valor '1' y pasará a '0' cuando se pulsa a tecla. Por tanto la interrupción externa no se debería ver en el flanco que sube, por otra parte yo lo poco que  he usado una interrupción para teclado he usado la de cambio de estado (INTCONTbits.RBIE) y no la de entrada externa(INTCONbits.INT0IE).

Un saludo.
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 08 de Marzo de 2013, 06:24:29
Muchas gracias Vayadespiste por tu atención! Creo que me explique mal en el primer post. La interrupción no la quiero generar con el teclado sino con el switch que está conectado a RB0, por eso utilizo la interrupción de entrada externa ya que será un evento que se producirá de forma puntual. El teclado sólo lo uso para la introducción de contraseñas, que es independiente de lo que es la interrupcion.
Lo del pull-up lo he quitado a ver si es el problema y sigue sin detectar la interrupción.

Un saludo y gracias
Título: Re: Problema con interrupcion externa y teclado
Publicado por: AngelGris en 08 de Marzo de 2013, 09:30:03
  Creo que podría ser  de ayuda si colocas un esquema del circuito.
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 09 de Marzo de 2013, 14:17:22
Ok lo siento! pensaba que lo habia introducido en el .zip que adjunté en el primer post. En el que adjunto ahora he introducido algun cambio sin importancia como el traslado del lcd al puerto B pero ya lo he modificado en su libreria. ¿Podría ser el fallo la librería del teclado o como la gestiono en el programa la causa del problema de que no me detecte las teclas? El otro problema que tengo, el de la interrupción, me detecta la interrupción, entra en ella, pero luego no llega al main para leer el flag=1 de la rutina de la interrupción.  Vuelvo a poner el programa con alguna modificacion que he hecho pero sigue sin funcionar.

#fuses XT            //Crystal osc <= 4mhz               
#fuses NOWDT         //deshabilita el Watch Dog Timer
#fuses NOPROTECT     //deshabilita la proteccion del codigo del pic
#fuses PUT           //habilita el reseteo de power up timer
#fuses NOLVP         //No Low Voltage Programming on B3(PIC16) or B5(PIC18,no habilita la programacion en bajo voltaje)
#fuses NOBROWNOUT    //No Reset when brownout detected

#use delay(clock = 4000000)

#use fast_io(A)       //con esta instruccion evitamos que
#use fast_io(B)       //se este configurando cada vez que usamos
#use fast_io(C)       //alguna instruccion de entrada o salida
#BYTE TRISA = 0b10000101   //TRISA = 0x85 Registro de direccionamiento Puerto A
#BYTE PORTA = 0b00000101   //PORTA = 0x05 Puerto A
#BYTE TRISB = 0b10000110   //TRISB = 0x86 Registro de direccionamiento Puerto B
#BYTE PORTB = 0b00000110   //PORTB = 0x06 Puerto B
#BYTE TRISC = 0b10000111   //TRISC = 0x87 Registro de direccionamiento Puerto C
#BYTE PORTC = 0b00000111   //PORTC = 0x07 Puerto C
//#bit RB0=0x06.1
#byte kbd_port_b = 6

#include <kbd3x4_2.c>         //libreria manejo keypad 3x4
#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas

#rom 0x2100={0,0,0,0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h



////////////////DEFINICION DE FUNCIONES////////////////////////////

void menu_principal(void);             //funcion que muestra el menu principal
void escribir_clave(char clave[]);     //funcion que escibre la clave tecleada
void cambia_clave_inicial(void);       //funcion que cambia clave
void cambiar_clave(void);              //funcion que cambia clave
int comparar_claves(int);              //función que compara las claves
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void activar_alarma(void);             //funcion que activa la alarma
void desactivar_alarma(void);          //funcion que desactiva la alarma
void escribir_clave_en_eeprom(int);    //función que escribe las claves en la memoria eeprom
void leer_clave_en_eeprom(int);        //función que lee las claves y las guarda en su correspondiente variable
void alarma_general(void);             //funcion que enciende la sirena
void conteo_intentos(void);            //funcion que cuenta el numero de intentos de ingreso de contraseña



////////////////VARIABLES GLOBALES///////////////////////////

char clave_inicial[3]= {'1','2','3'};  //variable usada como clave de inicio
char clave_eeprom_admin[3];            //variable usada para comparar los datos de la eeprom contra los datos ingresados             
char clave[3];                         //variable usada para recoger la clave tecleada
char k;                                //variable usada para recoger las teclas pulsadas del teclado
signed char i;                         //variable usada para movernos por las posiciones de la memoria
char clave_introducida[3]={};          //variable usada para los datos ingresados
int alarm_cont=0;                      //variable global que cuenta los fallos
//int flag;                              //variable usada como bandera para las interrupciones
static int flag;


//////////////////LLAMADA FUNCION INTERRUPCION//////////////
#INT_EXT
void int_ext_isr(void)  //funcion que detecta la interrupcion


     flag=1;    //Se habilita la bandera cuando ocurre una interrupcion.
     output_b(input_b()); // leer/escribir el puerto B al finalizar la interrupción para que no se vuelva a ejecutar
   
   
    /*set_tris_c(0b11111110);      //pines C0 como salida
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    output_b(input_b());         // leer/escribir el puerto B al finalizar la interrupción para que no se vuelva a ejecutar
    clear_interrupt(int_ext);    //ponemos a '0' el flag*/
   
}



////////////////////PROGRAMA PRINCIPAL//////////////////////
void main()

{
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_CLOCK_DIV_2);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   
   flag=0;                       //pongo la variable de la bandera a '0'
   set_tris_b(0b00001111);       //configuro el puerto b
   set_tris_c(0b11111111);       //configuro el puerto c
   //port_b_pullups(true);         //activo las resistencias de pullup
   ext_int_edge(L_TO_H);         //activo la interrupcion externa por cambio de bajo a alto
   clear_interrupt(int_ext);     //pongo a '0' el flag de la interrupcion externa
   enable_interrupts(int_ext);   //habilito la interrupcion externa
   enable_interrupts(GLOBAL);    //habilito las interrupciones
   
   lcd_init();            //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   
    while(true)
   {
     
     if(flag==1)
      {
         disable_interrupts(int_ext);  //deshabilitamos la interrupcion externa
         clear_interrupt(int_ext);     //ponemos a '0' el flag
         delay_ms(20);                 //antirrebote
         alarma_general ();            //activamos la alarma
         flag=0;                       //ponemos la variable flag a '0'
         enable_interrupts(int_ext);   //habilito la interrupcion externa
         enable_interrupts(GLOBAL);    //habilito las interrupciones
         
      }
     else
      {
         cambia_clave_inicial();    //cambio la contraseña que viene por defecto
         menu_principal();          //voy al menu principal
      }
   }
}


//////////FUNCION CAMBIAR CLAVE INICIAL
void cambia_clave_inicial(void)             //funcion que cambia clave administrativa

{
int p;
   clave_introducida=0;                //pongo la clave tecleada a 0
   escribir_clave(clave_introducida);  //tecleo la contraseña
   p=strcmp(clave_introducida , clave_inicial);    //comparo la clave por defecto con la tecleada
   if (p==0)                           //si las dos claves son iguales:
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          nueva_clave_admin();      //introduzco la nueva clave
         }
   if (p!=0)                        //si las dos claves son distintas
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;      //borro la clave introducida
          //conteo_intentos();
          alarma_general ();        //activo la alarma
         }
}
 
   
//////////FUNCION ESCRIBIR NUEVA CLAVE
void escribir_clave(char clave[])            //funcion que escibre la clave tecleada

{
int i=0;

   lcd_putc("\fEscribir clave:\n");   //presentacion
   do{
         do{               //espera hasta...
            k=kbd_getc();   
           }while(k==0);   //...pulsar una tecla
         
            if(!(k=='*' || k=='#')) // Si no es '*' o '#' en la pantalla aparece un '*'
            {     
            lcd_putc("*");
            clave=k;
            }       
     i++;
     
     }while( !(k=='*' || k=='#') );        //Si '*' o '#' señalamos que hemos terminado de introducir la contraseña
     
}



/////FUNCION MENU PRINCIPAL   
void menu_principal (void)             //funcion que muestra el menu principal

{
     for(;;)
    {
      lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
      do{               //espera hasta...
         k=kbd_getc();   
         }while(k==0 || k==1);   //...pulsar una tecla
     
     switch (k)
     {
      case '0':         //si '0' va a activar la alarma
         activar_alarma();
      break;
      case '1':         //si '1' va a comprobar clave para despues cambiar la clave
         cambiar_clave();
      break;
     }
    }   
}


//////////FUNCION CAMBIAR CLAVE
void cambiar_clave(void)             //funcion que cambia clave administrativa

{
int p;
   escribir_clave(clave_introducida);  //escribimos la contraseña
   leer_clave_en_eeprom(i);            //lee la contraseña que antes hemos cambiado
   p=comparar_claves(i);               //compara ambas claves
   if (p==0)                           //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          nueva_clave_admin();         //vamos a la rutina para introducir la nueva clave
         }
   if (p!=0)                           //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;         //borra la clave ahora introducida
          alarma_general ();           //activa la alarma
         }
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)                 //funcion que añade la nueva clave administrativa

{
int i=0;
   lcd_putc("\fNueva clave:\n");   //presentacion
   do{
         do{               //espera hasta...
            k=kbd_getc();   
           }while(k==0);   //...pulsar una tecla
         
            if(k!='*' || k!='#')    // Si no es '*' o '#' en la pantalla aparece un '*'   
            {     
            lcd_putc("*");
            clave=k;
            }
     escribir_clave_en_eeprom(i);   //guardamos la nueva clave en la memoria EEPROM
     i++;
     
     }while( !(k=='*' || k=='#') );       //Si '*' o '#' señalamos que hemos terminado de introducir la contraseña
}


//////////FUNCION COMPARAR CLAVES
int comparar_claves(int)                  //funcion que compara la clave administrativa y la introducida

{
int i=0;
int s=0;
   for (i=0;i<3;i++)    //comparo caracter a caracter las claves
   {
      if (clave_introducida==clave_eeprom_admin)   //si el caracter es igual en las dos claves
        s++;                                             //paso al siguiente caracter
      else                                               //si es distinto la contraseña es incorrecta
        {s=0;
         lcd_putc("\fClave Incorrecta\n");
         break;
        }
   }
   if (s==3)                           //si todos los tres caracteres son iguales
      return 0;                        //devuelvo un '0'
}


//////////ACTIVAR ALARMA
void activar_alarma(void)           //funcion que activa la alarma

{
int i=0;
int p=0;
   escribir_clave(clave_introducida);     //escribimos la contraseña
   leer_clave_en_eeprom(i);               //lee la contraseña administrativa grabada anteriormente en la EEPROM
   p=comparar_claves(i);                  //compara ambas claves
   if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma Activada");
          delay_ms(2000);
          desactivar_alarma();            //vamos a la rutina para desactivar la alarma
         }
   if (p!=0)                                 //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;               //borra la clave ahora introducida
          alarma_general ();                 //activo la alarma
         }
}


//////////DESACTIVAR ALARMA
void desactivar_alarma(void)           //funcion que desactiva la alarma

{
int i=0;
int p=0;
   lcd_putc("\fDesactivar alarma\n");   //presentacion
   escribir_clave(clave_introducida);  //escribimos la contraseña
   leer_clave_en_eeprom(i);            //lee la contraseña administrativa grabada anteriormente en la EEPROM
   p=comparar_claves(i);               //compara ambas claves
   if (p==0)                           //si son iguales...
         {lcd_putc("\fAlarma\nDesactivada");
          delay_ms(2000);
          break;                          //vuelve al menu principal
         }
   if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;            //borra la clave ahora introducida
          alarma_general ();              //activo la alarma
         }
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int i)     //función que escribe las claves en la memoria eeprom

{
   write_eeprom (i,k);             //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                   //en la direccion i + 0 (para no pisar datos) de la eeprom
   i++;                            //en una palabra escribe de la posicion 0 a la 4 (5 lugares)
}


//////////LEER_CLAVE_EN_EEPROM
void leer_clave_en_eeprom(int i)       //función que lee las claves y las guarda en su correspondiente variable

{
    for (i=0;i<3;i++)
    {
      clave_eeprom_admin = read_eeprom(i);      //guardamos cada valor de la direccion i + 0 (para no pisar datos)
      delay_ms(20);                                //de la eeprom en la variable global correspondiente
    }
}



////////////FUNCION CONTEO INTENTOS
/*void conteo_intentos(void)             //funcion que cuenta el numero de intentos de ingreso de contraseña

{
   if (alarm_cont==3)
   {
      alarma_general();
   }
   else
   {
      alarm_cont++;
   }
}*/


//////////FUNCION ALARMA GENERAL
void alarma_general (void)

{
    set_tris_c(0b11111110);      //pin C0 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje
    //lcd_putc("\fALARMA\n");         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    alarm_cont = 0;              //pongo a cero el contador de errores
    //break;
    //desactivar_alarma();
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: PalitroqueZ en 09 de Marzo de 2013, 15:02:41
yo que tú, eliminaría todo lo que pudiera dentro de la interrupción, ese retardo de 2 segundos en una interrupción no es conveniente, me imagino que habrá veces que el teclado no responderá.

yo dejaría solo banderas dentro de la interrupción y crearía una función abajo que comprobaría la bandera y haría el resto.

y para complicar (mejorar) mas el asunto, trataría el teclado por interrupción del nibble alto del portb

Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 09 de Marzo de 2013, 15:15:27
Muchas gracias! la parte de codigo donde sale el delay de 2 segundos la tenia anulada y al copiar el codigo no me he acordado de borrarlo, lo siento. Estudiaré lo de tratar el teclado por interrupción del nibble alto, era algo que ya tenia en mente.
 Muchas gracias y aun así se admiten sugerencias
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 09 de Marzo de 2013, 19:56:16
Hola! He probado lo que me contestaste PalitroqueZ y continua si funcionar. Presiono las teclas y no consigo que entre en la interrupcion de nibble alto del portb
Título: Re: Problema con interrupcion externa y teclado
Publicado por: PalitroqueZ en 10 de Marzo de 2013, 22:22:21
podrías poner el último código ya corregido, porque no entiendo, al principio pusiste un código y después resulta que lo corregiste y total que no se entiende bien cual es el problema.

Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 11 de Marzo de 2013, 05:50:29
Perdon a todos! Llevo un par de meses con este problema y despues de hacer tantos cambios y probar tantas cosas ya no se ni lo que guardo ni lo que subo al foro y ya casi ni lo que hago!
El programa funcionaba correctamente, lo que es la parte de introducción de contraseñas mediante el teclado y la comprobación de las mismas. El problema vino al introducir la interrupción externa ya que ya no me detecta las teclas que pulso. El otro problema que tengo, es que detecta la interrupción externa, pero no llega a ir al main para leer la bandera que he puesto en la interrupción a 1 y que se produzca el parpadeo del led, sino que me manda a la libreria del teclado y como no me detecta las teclas pues poco puedo hacer.
Vuelvo a poner el codigo y adjunto todos los archivos y librerias que estoy usando. Voy a seguir probando lo que me dijiste PalitroqueZ del nibble alto pero el otro día no me funcionaba
Muchas gracias y perdon por las molestias que esta causando el caos que llevo en la cabeza

#fuses XT            //Crystal osc <= 4mhz               
#fuses NOWDT         //deshabilita el Watch Dog Timer
#fuses NOPROTECT     //deshabilita la proteccion del codigo del pic
#fuses PUT           //habilita el reseteo de power up timer
#fuses NOLVP         //No Low Voltage Programming on B3(PIC16) or B5(PIC18,no habilita la programacion en bajo voltaje)
#fuses NOBROWNOUT    //No Reset when brownout detected

#use delay(clock = 4000000)

#use fast_io(A)       //con esta instruccion evitamos que
#use fast_io(B)       //se este configurando cada vez que usamos
#use fast_io(C)       //alguna instruccion de entrada o salida
#BYTE TRISA = 0b10000101   //TRISA = 0x85 Registro de direccionamiento Puerto A
#BYTE PORTA = 0b00000101   //PORTA = 0x05 Puerto A
#BYTE TRISB = 0b10000110   //TRISB = 0x86 Registro de direccionamiento Puerto B
#BYTE PORTB = 0b00000110   //PORTB = 0x06 Puerto B
#BYTE TRISC = 0b10000111   //TRISC = 0x87 Registro de direccionamiento Puerto C
#BYTE PORTC = 0b00000111   //PORTC = 0x07 Puerto C
//#bit RB0=0x06.1
#byte kbd_port_b = 6

#include <kbd3x4_2.c>         //libreria manejo keypad 3x4
#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas

#rom 0x2100={0,0,0,0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h



////////////////DEFINICION DE FUNCIONES////////////////////////////

void menu_principal(void);             //funcion que muestra el menu principal
void escribir_clave(char clave[]);     //funcion que escibre la clave tecleada
void cambia_clave_inicial(void);       //funcion que cambia clave
void cambiar_clave(void);              //funcion que cambia clave
int comparar_claves(int);              //función que compara las claves
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void activar_alarma(void);             //funcion que activa la alarma
void desactivar_alarma(void);          //funcion que desactiva la alarma
void escribir_clave_en_eeprom(int);    //función que escribe las claves en la memoria eeprom
void leer_clave_en_eeprom(int);        //función que lee las claves y las guarda en su correspondiente variable
void alarma_general(void);             //funcion que enciende la sirena
void conteo_intentos(void);            //funcion que cuenta el numero de intentos de ingreso de contraseña



////////////////VARIABLES GLOBALES///////////////////////////

char clave_inicial[3]= {'1','2','3'};  //variable usada como clave de inicio
char clave_eeprom_admin[3];            //variable usada para comparar los datos de la eeprom contra los datos ingresados             
char clave[3];                         //variable usada para recoger la clave tecleada
char k;                                //variable usada para recoger las teclas pulsadas del teclado
signed char i;                         //variable usada para movernos por las posiciones de la memoria
char clave_introducida[3]={};          //variable usada para los datos ingresados
int alarm_cont=0;                      //variable global que cuenta los fallos                             
static int flag;                       //variable usada como bandera para las interrupciones


//////////////////LLAMADA FUNCION INTERRUPCION//////////////
#INT_EXT
void int_ext_isr(void)  //funcion que detecta la interrupcion


     flag=1;    //Se habilita la bandera cuando ocurre una interrupcion.
     output_b(input_b()); // leer/escribir el puerto B al finalizar la interrupción para que no se vuelva a ejecutar
}



////////////////////PROGRAMA PRINCIPAL//////////////////////
void main()

{
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_CLOCK_DIV_2);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   
   flag=0;                       //pongo la variable de la bandera a '0'
   set_tris_b(0b00001111);       //configuro el puerto b
   set_tris_c(0b11111111);       //configuro el puerto c
   port_b_pullups(true);         //activo las resistencias de pullup
   ext_int_edge(L_TO_H);         //activo la interrupcion externa por cambio de bajo a alto
   clear_interrupt(int_ext);     //pongo a '0' el flag de la interrupcion externa
   enable_interrupts(int_ext);   //habilito la interrupcion externa
   enable_interrupts(GLOBAL);    //habilito las interrupciones
   
   lcd_init();            //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   
    while(true)
   {
     
     if(flag==1)
      {
         disable_interrupts(int_ext);  //deshabilitamos la interrupcion externa
         clear_interrupt(int_ext);     //ponemos a '0' el flag
         delay_ms(20);                 //antirrebote
         alarma_general ();            //activamos la alarma
         flag=0;                       //ponemos la variable flag a '0'
         enable_interrupts(int_ext);   //habilito la interrupcion externa
         enable_interrupts(GLOBAL);    //habilito las interrupciones
         
      }
     else
      {
         cambia_clave_inicial();    //cambio la contraseña que viene por defecto
         menu_principal();          //voy al menu principal
      }
   }
}


//////////FUNCION CAMBIAR CLAVE INICIAL
void cambia_clave_inicial(void)             //funcion que cambia clave administrativa

{
int p;
   clave_introducida=0;                //pongo la clave tecleada a 0
   escribir_clave(clave_introducida);  //tecleo la contraseña
   p=strcmp(clave_introducida , clave_inicial);    //comparo la clave por defecto con la tecleada
   if (p==0)                           //si las dos claves son iguales:
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          nueva_clave_admin();      //introduzco la nueva clave
         }
   if (p!=0)                        //si las dos claves son distintas
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;      //borro la clave introducida
          alarma_general ();        //activo la alarma
         }
}
 
   
//////////FUNCION ESCRIBIR NUEVA CLAVE
void escribir_clave(char clave[])            //funcion que escibre la clave tecleada

{
int i=0;

   lcd_putc("\fEscribir clave:\n");   //presentacion
   do{
         do{               //espera hasta...
            k=kbd_getc();   
           }while(k==0);   //...pulsar una tecla
         
            if(!(k=='*' || k=='#')) // Si no es '*' o '#' en la pantalla aparece un '*'
            {     
            lcd_putc("*");
            clave=k;
            }       
     i++;
     
     }while( !(k=='*' || k=='#') );        //Si '*' o '#' señalamos que hemos terminado de introducir la contraseña
     
}



/////FUNCION MENU PRINCIPAL   
void menu_principal (void)             //funcion que muestra el menu principal

{
     for(;;)
    {
      lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
      do{               //espera hasta...
         k=kbd_getc();   
         }while(k==0 || k==1);   //...pulsar una tecla
     
     switch (k)
     {
      case '0':         //si '0' va a activar la alarma
         activar_alarma();
      break;
      case '1':         //si '1' va a comprobar clave para despues cambiar la clave
         cambiar_clave();
      break;
     }
    }   
}


//////////FUNCION CAMBIAR CLAVE
void cambiar_clave(void)             //funcion que cambia clave administrativa

{
int p;
   escribir_clave(clave_introducida);  //escribimos la contraseña
   leer_clave_en_eeprom(i);            //lee la contraseña que antes hemos cambiado
   p=comparar_claves(i);               //compara ambas claves
   if (p==0)                           //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          nueva_clave_admin();         //vamos a la rutina para introducir la nueva clave
         }
   if (p!=0)                           //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;         //borra la clave ahora introducida
          alarma_general ();           //activa la alarma
         }
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)                 //funcion que añade la nueva clave administrativa

{
int i=0;
   lcd_putc("\fNueva clave:\n");   //presentacion
   do{
         do{               //espera hasta...
            k=kbd_getc();   
           }while(k==0);   //...pulsar una tecla
         
            if(k!='*' || k!='#')    // Si no es '*' o '#' en la pantalla aparece un '*'   
            {     
            lcd_putc("*");
            clave=k;
            }
     escribir_clave_en_eeprom(i);   //guardamos la nueva clave en la memoria EEPROM
     i++;
     
     }while( !(k=='*' || k=='#') );       //Si '*' o '#' señalamos que hemos terminado de introducir la contraseña
}


//////////FUNCION COMPARAR CLAVES
int comparar_claves(int)                  //funcion que compara la clave administrativa y la introducida

{
int i=0;
int s=0;
   for (i=0;i<3;i++)    //comparo caracter a caracter las claves
   {
      if (clave_introducida==clave_eeprom_admin)   //si el caracter es igual en las dos claves
        s++;                                             //paso al siguiente caracter
      else                                               //si es distinto la contraseña es incorrecta
        {s=0;
         lcd_putc("\fClave Incorrecta\n");
         break;
        }
   }
   if (s==3)                           //si todos los tres caracteres son iguales
      return 0;                        //devuelvo un '0'
}


//////////ACTIVAR ALARMA
void activar_alarma(void)           //funcion que activa la alarma

{
int i=0;
int p=0;
   escribir_clave(clave_introducida);     //escribimos la contraseña
   leer_clave_en_eeprom(i);               //lee la contraseña administrativa grabada anteriormente en la EEPROM
   p=comparar_claves(i);                  //compara ambas claves
   if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma Activada");
          delay_ms(2000);
          desactivar_alarma();            //vamos a la rutina para desactivar la alarma
         }
   if (p!=0)                                 //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;               //borra la clave ahora introducida
          alarma_general ();                 //activo la alarma
         }
}


//////////DESACTIVAR ALARMA
void desactivar_alarma(void)           //funcion que desactiva la alarma

{
int i=0;
int p=0;
   lcd_putc("\fDesactivar alarma\n");   //presentacion
   escribir_clave(clave_introducida);  //escribimos la contraseña
   leer_clave_en_eeprom(i);            //lee la contraseña administrativa grabada anteriormente en la EEPROM
   p=comparar_claves(i);               //compara ambas claves
   if (p==0)                           //si son iguales...
         {lcd_putc("\fAlarma\nDesactivada");
          delay_ms(2000);
          break;                          //vuelve al menu principal
         }
   if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;            //borra la clave ahora introducida
          alarma_general ();              //activo la alarma
         }
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int i)     //función que escribe las claves en la memoria eeprom

{
   write_eeprom (i,k);             //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                   //en la direccion i + 0 (para no pisar datos) de la eeprom
   i++;                            //en una palabra escribe de la posicion 0 a la 4 (5 lugares)
}


//////////LEER_CLAVE_EN_EEPROM
void leer_clave_en_eeprom(int i)       //función que lee las claves y las guarda en su correspondiente variable

{
    for (i=0;i<3;i++)
    {
      clave_eeprom_admin = read_eeprom(i);      //guardamos cada valor de la direccion i + 0 (para no pisar datos)
      delay_ms(20);                                //de la eeprom en la variable global correspondiente
    }
}


//////////FUNCION ALARMA GENERAL
void alarma_general (void)

{
    set_tris_c(0b11111110);      //pin C0 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje     
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    alarm_cont = 0;              //pongo a cero el contador de errores
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 11 de Marzo de 2013, 17:19:56
Bueno que yo sepa lo de leer o escribir el puerto B se hace para la interrupcion por cambio de estado en el puerto B no para la interrupcion externa.

Ahora,cuando abro tu archivo en proteus veo que segun el codigo debes tener las pullups habilitadas en el puerto B,sin embargo en proteus no se mantienen de echo papadean van de tierra a vcc continuamente,desconozco si en lo que programaste,solo le di un vistazo rapido.

Por ultimo,yo no me confiaria de la funcion clear_interrupt() para borrar el flag de interrupcion,ya me paso,yo checaria directamente el bit en el registro de interrupcion y veria si se mantiene o si efectivamente se limpia.

ahora que tenga mas tiempo lo simulo con mas calma y si puedo aportar mas lo hare vale

Saludos y no desesperes que ya saldra
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 12 de Marzo de 2013, 06:03:22
Hola a todos!Aquí sigo con mi lucha.

Lo de leer o escribir el puerto B lo puse porque solo escribiendo flag=1 no me funcionaba e investigando por el foro lo encontré y lo puse por probar, pero no sabía que solo se sirve para la interrupción por cambio de estado en el puerto B (otra cosa mas que ya he aprendido).

Lo del parpadeo de las pull-ups también me tiene bastante intrigado pero por lo menos he conseguido que me detecte las teclas. Y la solución ha sido sustituir el pull-up que tenía montado en Proteus por una pull-down.La interrupción externa sigue sin funcionar, no la detecta, no se si por problemas de rebotes o por otro motivo, así que seguiré probando cosas.Adjunto el nuevo archivo de Proteus

muchas gracias por intentar ayudarme.

Intento no desesperar y seguir luchando. Un saludo
Título: Re: Problema con interrupcion externa y teclado
Publicado por: AngelGris en 12 de Marzo de 2013, 09:41:50
  Pido disculpas por si esta intervención ocasiona mas dudas. pero... o yo no estoy entendiendo bien el programa o hay algo mal.

  Dentro del while, se chequea si la variable flag es 1 y de ser así se activa la alarma.
  Si flag es 0, se ingresa siempre al cambio de clave inicial y también se ingresa siempre al menu principal.
  Menu principal es un ciclo infinito, por lo tanto nunca podrías atender el flag generado por la interrupción externa. Creo que dicho flag deberías evaluarlo dentro de la rutina del menu principal.
Título: Re: Problema con interrupcion externa y teclado
Publicado por: PalitroqueZ en 12 de Marzo de 2013, 13:41:12
escarrillense he probado el último archivo que subiste y al parecer no hay problemas con el teclado. pero hay un par de cosas que desde mi punto de vista no haría.

- colocar los mismos pines del teclado para la pantalla lcd, las librerías del teclado configuran sus pines para una función especifica, y entonces la librería de la lcd hace lo mismo. Habría que estudiar a fondo ambas librerías y determinar si no hay un "choque" de configuración de pines cuando cada periférico le toque hacer uso de esos 4 pines del portb.

- la linea

output_b(input_b()); // leer/escribir el puerto B al finalizar la interrupción para que no se vuelva a ejecutar

dentro de int_ext no comprendo su utilidad, en la datasheet de estos pic, mencionan limpiar el puerto, pero es cuando se está utilizando la interrupcion del nibble alto del portb y la libreria kbd3x4_2.c no hace uso de interrupciones.

si quieres usar correctamente la interrupción por cambio de flanco del pin rb0, los pasos son los siguientes:

- definir rb0 como entrada (usar el trisb con precaución, sin alterar el estado de los otros pines)
- definir el flanco mediante ext_int_edge();
- configurar la interrupción.
- colocar solo el flag en int_ext
- colocar una rutina o funcion en main que pregunte por ese flag
-- si es muy importante atender esa interrupción, entonces apagar las interrupciones globalmente, sino, apagar solo la de int_ext
-- hacer lo que quieras hacer con esa interrupcion
-- antes de salir de esa función, apagar banderas y usar clear_interrupt(INT_EXT);
- a nivel de hardware es preferible usar pull-up externas, aquí en el foro han habido reportes de problemas con pull-up internas, entonces es preferible sacrificar unos milímetros de espacio en el pcb y poner unas resistencia de 1/8w a que lidiar con los bugs del pic o del compilador.

la librería que estás usando está correcta, si te funciona esa librería entonces no hay necesidad de complicarse (aunque en el futuro descubrirás que es mejor usar el teclado por interrupciones).

en resumen, creo que lo que está causando problemas es esa dualidad del nibble alto del portb, y como dices que llevas tiempo con ese problema, lo mejor es rediseñar el hardware y reescribir el código.


saludos


Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 12 de Marzo de 2013, 15:47:33
Hola! muchas gracias por las molestias que os estais tomando.

He efectuado los cambios que me explicasteis y sigue sin detectar la interrupción. He pasado el lcd al puerto c (concretamente a los pines C1, C2, C3 y C4) y eliminado la instrucción output_b(input_b(). Tambien hice caso a AngelGris y pase la lectura del flag de la interrupción a la rutina menu principal.

Escribo la parte del codigo que afecta a las partes criticas y adjunto los archivos empleados:

//////////////////LLAMADA FUNCION INTERRUPCION//////////////
#INT_EXT
void int_ext_isr(void)  //funcion que detecta la interrupcion

{  
    flag=1;    //Se habilita la bandera cuando ocurre una interrupcion.
  
}



////////////////////PROGRAMA PRINCIPAL//////////////////////
void main()

{
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_CLOCK_DIV_2);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
  
   flag=0;                       //pongo la variable de la bandera a '0'
   set_tris_b(0b00001111);       //configuro el puerto b
   set_tris_c(0b11111111);       //configuro el puerto c
   ext_int_edge(H_TO_L);         //activo la interrupcion externa por cambio de bajo a alto
  
   //bit_clear(INTCON,1); //Borra bandera de la interrupcion
   enable_interrupts(int_ext);   //habilito la interrupcion externa
   enable_interrupts(GLOBAL);    //habilito las interrupciones
  
   lcd_init();            //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   cambia_clave_inicial();    //cambio la contraseña que viene por defecto
   menu_principal();          //voy al menu principal
    
}

/////FUNCION MENU PRINCIPAL  
void menu_principal (void)             //funcion que muestra el menu principal

{
     for( ; ; )
    {
      if(flag==1)
      {
         disable_interrupts(int_ext);  //deshabilitamos la interrupcion externa
         //disable_interrupts(GLOBAL);
         delay_ms(20);                 //antirrebote
         alarma_general ();            //activamos la alarma
         flag=0;                       //ponemos la variable flag a '0'
         clear_interrupt(int_ext);     //ponemos a '0' el flag
         enable_interrupts(int_ext);   //habilito la interrupcion externa
         //enable_interrupts(GLOBAL);    //habilito las interrupciones
      }
      else
      {
         lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
         do{               //espera hasta...
            k=kbd_getc();  
            }while(k==0 || k==1);   //...pulsar una tecla
      
         switch (k)
         {
         case '0':         //si '0' va a activar la alarma
            activar_alarma();
         break;
         case '1':         //si '1' va a comprobar clave para despues cambiar la clave
          cambiar_clave();
         break;
         }
      }
    }  
}


He estado investigando por el foro lo de gestionar el teclado por interrupciones pero no termino de entender su funcionamiento ni como adaptarlo a mi programa. Si me lo pudierais explicar me hariais un gran favor.

Muchas gracias por todo a todos
Título: Re: Problema con interrupcion externa y teclado
Publicado por: AngelGris en 12 de Marzo de 2013, 19:29:14
  Perdón, pero observando mejor la estructura de la función "menu principal" sigue existiendo un inconveniente y es que sigues quedando a la espera de pulsar o bien la tecla 0 o bien la tecla 1.

  No sé como funcione la librería de teclado que estás utilizando. Obviamente, lo ideal sería utilizarla por medio de interrupciones.
  De todas maneras, si existe una función que te permita chequear con aterioridad si se presionó alguna tecla, se podría hacer uso  de ella. Algo así...


Código: C
  1. for(;;)
  2. {
  3.   if (flag == 1)
  4.   {
  5.     todo lo que tengas que hacer
  6.   }
  7.   if (kbd_hit)
  8.   {
  9.     k = kbd_getc();
  10.     switch (k)
  11.     {
  12.     }
  13.   }
  14. }

  de esa manera sólo leerías el teclado si es que se presionó alguna tecla. De no ser así se repite constantemente el ciclo y por lo tanto si podrías leer el flag.
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 13 de Marzo de 2013, 09:17:06
Muchas gracias AngelGris! Creo que estas en lo cierto, que el problema que tengo es como gestiono el teclado. Estoy constantemente en un bucle esperando a pulsar una tecla y no llego a detectar la interrupción. He probado el codigo que me pusiste y no me funciona, creo que es porque esa instrucción solo es válida para comunicación rs-232 y en mi caso no la estoy utilizando en este pryecto.
Estoy intentando gestionar el teclado por medio de interrupciones pero no consigo lograrlo. Seguire probando y tambien estudiare lo de la comunicación serie por si es una posible solución.

Muchas gracias y a ver si consigo avanzar
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 13 de Marzo de 2013, 13:42:18
ok escarrillense,porque no como sugerencia vamos armando poco a poco el código y haciendo funcionar una a una las cosas porque me parece que de lo liado que estas ya no se puede trabajar con ese código jeje solo es una sugerencia,en unos momentos subo un código donde trabaje la interrupción externa que es la que no quiere la bendita  :? aunque es raro,y de ahí vamos metiendole cosas una por una te parece.

ahora,pregunta,que pic usas?? el 16F876?? que es el que veo en la simulación del proteus,porque no se como le estas haciendo que no veo el include correspondiente al pic en tu codigo,es decir,#include<pic16f876.h>,pero bueno si te compila y hace algo es porque va bien.

dame chancecita que ahorita subo el codigo para que pruebes y me dices que chow
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 13 de Marzo de 2013, 14:14:59
Ok ahi va,utilizando el mismo PIC que veo en tu simulacion,he creado este codigo que configura la interrupcion externa y cuando esta se activa,un led en RB1 togglea (osea que,de estar apagado va a encendido y de encendido va a apagado),he creado tambien la simulacion sencilla en Proteus 7.9,espero te sirva,cualquier duda por aqui andamos.

Código: [Seleccionar]
#include<16f876.h>
#fuses XT,PUT,NOWDT,NODEBUG
#use delay(clock=4MHZ)

#byte TRISB=0x086

char bandera=0;

#INT_EXT
void externa(void)
{
bandera=1;
}

void configura_int_ext(void)
{
bit_set(TRISB,0);
clear_interrupt(INT_EXT);
ext_int_edge(L_TO_H);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
}

void main(void)
{
configura_int_ext();
while(true)
{
if(bandera==1)
{
bandera=0;
output_toggle(PIN_B1);
}
}
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 14 de Marzo de 2013, 15:15:14
Muchas gracias thegame por el codigo! Lo he probado y funciona perfectamente pero al añadirle el teclado volvemos al problema de siempre aunque no ponga bucles como los que me estaban dado problemas hasta ahora. La interrupción ahora funciona pero no la captura de teclas. Estoy utilizando un PIC16F876. El include con el modelo de PIC no me es necesario ponerlo (no me pregunten por qué ya que no lo se, es muy raro ya lo se). De forma paralela sigo trabajando con la gestión del teclado por interrupciones, por si fuera la solución. Les pongo el código que he probado (las librerías son las anteriormente utilizadas, las saque del foro y hasta ahora funcionaban perfectamente):

#include<16f876.h>
#fuses XT,PUT,NOWDT,NODEBUG
#fuses NOPROTECT     //deshabilita la proteccion del codigo del pic
#fuses NOLVP         //No Low Voltage Programming on B3(PIC16) or B5(PIC18,no habilita la programacion en bajo voltaje)
#fuses NOBROWNOUT    //No Reset when brownout detected
#use delay(clock=4MHZ)

#use fast_io(A)       //alguna instruccion de entrada o salida
//#use fast_io(C)       //alguna instruccion de entrada o salida
#BYTE TRISA = 0b10000101   //TRISA = 0x85 Registro de direccionamiento Puerto A
#BYTE PORTA = 0b00000101   //PORTA = 0x05 Puerto A
#byte TRISB=0x086
#BYTE TRISC = 0b10000111
#BYTE PORTC = 0b00000111   //PORTC = 0x07 Puerto C

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <kbd3x4_2.c>         //libreria manejo keypad 3x4
#byte kbd_port_b = 6

////////////////DEFINICION DE FUNCIONES////////////////////////////

void menu_principal(void);             //funcion que muestra el menu principal
void escribir_clave(char clave[]);            //funcion que escibre la clave tecleada


char bandera=0;
int k;
char clave_introducida[3]={};          //variable usada para los datos ingresados

#INT_EXT
void externa(void)
{
   bandera=1;
}

void configura_int_ext(void)
{
   bit_set(TRISB,0);
   clear_interrupt(INT_EXT);
   ext_int_edge(L_TO_H);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
}

void main(void)
{
   set_tris_b(0b00001111);       //configuro el puerto b
   //port_b_pullups(true);         //activo las resistencias de pullup
   lcd_init();            //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
  
   configura_int_ext();
  
   while(true)
   {
      if(bandera==1)
      {
         bandera=0;
         output_toggle(PIN_C0);
      }
      else
      {
      
      escribir_clave(clave_introducida);
      }
   }
}

//////////FUNCION ESCRIBIR NUEVA CLAVE
void escribir_clave(char clave[])            //funcion que escibre la clave tecleada

{
int i=0;
   lcd_putc("\fEscribir clave:\n");   //presentacion
   do{
           if(k!=0)
           {
        
               if(!(k=='*' || k=='#')) // Si no es '*' o '#' en la pantalla aparece un '*'
               {      
               lcd_putc("*");
               clave=k;
               }      
            i++;
           }
            else
            {
               break;
            }
    
     }while( !(k=='*' || k=='#') );        //Si '*' o '#' señalamos que hemos terminado de introducir la contraseña
}

Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 14 de Marzo de 2013, 19:27:20
Que tal escarillense,bueno por ahi veo unas cosas que no cuadran para mi,me explico:

1.- Porque colocas las declaraciones individuales de los registros si no veo que los uses con instrucciones como bit_clear() o bit_set(),es decir para que poner:

Código: [Seleccionar]
#BYTE TRISA = 0b10000101   //TRISA = 0x85 Registro de direccionamiento Puerto A
#BYTE PORTA = 0b00000101   //PORTA = 0x05 Puerto A

y

Código: [Seleccionar]
#BYTE TRISC = 0b10000111
#BYTE PORTC = 0b00000111   //PORTC = 0x07 Puerto C

si no se estan usando,ahora,no que alla problema con que las coloques pero se revuelve mas el codigo.
yo si la coloque en el codigo que te envie porque si la uso para configurar el direccionamiento del pin.

2.- Dentro de configura_int_ext(),ya no es necesaria la instruccion bit_set(TRISB,0); ya que previamente utilizas:

Código: [Seleccionar]
set_tris_b(0b00001111);       //configuro el puerto b
por lo que tambien puedes quitar de tu codigo esta parte:

Código: [Seleccionar]
#byte TRISB=0x086
que fue de lo que yo te mande si no me equivoco.

Ok,veamos que cambios podemos hacer y echar a andar esto,estamos en contacto. Suerte no desesperes,igual un usuario con mayor experiencia nos echa la mano jeje
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 14 de Marzo de 2013, 20:45:56
Estuve revisando la libreria para el teclado,creo que por ahi el barrido que hace de las columnas ya no seria el mismo,dado que tu utilizas RB0 como interrupcion externa y no para el teclado.... :? lo estoy checando jeje
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 15 de Marzo de 2013, 05:24:54
Muchas gracias thegame!  He quitado lo que me dijiste del #byte tirs y port. Tenías razón con lo de la librería del teclado y las columnas, como he hecho tantos cambios en este tiempo debí de postear la librería que no era. El cambio realizado en la librería del teclado es el siguiente: en la línea 46 hay que sustituir
for(c=0x01, j=0; j<3; c<<=1, j++) por lo sigiente for(c=0x02, j=0; j<3; c<<=1, j++).

He modificado la rutina escribir_clave y me detecta las teclas (machacandolas, eso si) pero ahora la interrupción no. En resumen, o me funciona una cosa o la otra, pero las dos a la vez no. Copio la parte de codigo que he modificado de esta rutina, ya que el resto sigue como anteriormente:

//////////FUNCION ESCRIBIR NUEVA CLAVE
void escribir_clave(char clave[])            //funcion que escibre la clave tecleada

{
int i=0;
   lcd_putc("\fEscribir clave:\n");   //presentacion
   delay_ms(1000);
   k=kbd_getc();
           
    if(!(k=='*' || k=='#')) // Si no es '*' o '#' en la pantalla aparece un '*'
    {     
       lcd_putc("*");
       clave=k;         
    }       
       //i++;
    if((k=='*' || k=='#'))
    {
       break;
    }
    i++;
}

Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 15 de Marzo de 2013, 13:20:47
si asi es amigo,ya habia modificado esa parte de la libreria,te comento mis avances.

La interrupcion externa me funciona junto con el teclado,solo que modifique la función que tu utilizas para la captura de la clave,me funciona a medias porque siempre me marca acceso denegado jajaja (eso se lo puse yo jojo),entonces haciendo debug con el proteus he checado que no me esta guardando las teclas de entrada (clave_introducida) igual yo no lo estoy haciendo bien pero creo que tarde o temprano saldra esto jeje seguire intentando,te dejo lo que yo he echo or si le ves algun detalle y yo metere esta nueva funcion que has puesto hoy.

Código: [Seleccionar]
#include<16f876.h>
#fuses XT,PUT,NOWDT,NODEBUG
#fuses NOPROTECT     //deshabilita la proteccion del codigo del pic
#fuses NOLVP         //No Low Voltage Programming on B3(PIC16) or B5(PIC18,no habilita la programacion en bajo voltaje)
#fuses NOBROWNOUT    //No Reset when brownout detected
#use delay(clock=4MHZ,crystal=4MHZ)

#include<LCD4.c>             //libreria manejo lcd 8 bits
#include<kbd3x4_2.c>         //libreria manejo keypad 3x4

////////////////DEFINICION DE FUNCIONES////////////////////////////

char bandera=0,i=0;
char clave_introducida[4]={};
char clave_correcta[4]={'1','2','3'};

#INT_EXT
void externa(void)
{
   bandera=1;
}

void configura_int_ext(void)
{
clear_interrupt(INT_EXT);
ext_int_edge(H_TO_L);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
       
lcd_init();           
delay_ms(500);
lcd_putc ("   Bienvenido   ");
delay_ms(500);
}

void main(void)
{
configura_int_ext();
lcd_putc("\fEscribir clave:\n");   //presentacion

while(true)
{
if(bandera==1)
{
                            bandera=0;
                            output_toggle(PIN_C0);
}
     
if(kbd_getc()!=0)
{
if((kbd_getc()!='*' || kbd_getc()!='#'))
{     
clave_introducida[i]==kbd_getc();
                                lcd_putc(kbd_getc());
i++;
}

if(i==4 && (kbd_getc()=='*' || kbd_getc()=='#'))
{
if(clave_correcta==clave_introducida)
{
lcd_putc("\fAcceso concedido\n");
}
else
{
lcd_putc("\fAcceso denegado\n");
}
}

        }
}
}

pero me hace cosas raras,dejame decirte que me he estado divirtiendo con tu problema jeje,he aprendido mucho,asi que como decimos en mi tierra...o sales o sales k....jajaja
no desesperes que si queda,probare lo que tu modificaste
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 15 de Marzo de 2013, 13:40:41
Muchas gracias thegame! He probado tu código y siento decirte que no me funciona. No se si sera mi versión de proteus o el que, seguiré investigando.

En la parte donde comparas la clave introducida y la correcta, yo lo hago de esta manera y hasta ahora funcionaba:

int p;
clave_introducida=0;                //pongo la clave tecleada a 0
   escribir_clave(clave_introducida);  //tecleo la contraseña
   p=strcmp(clave_introducida , clave_correcta);    //comparo la clave por defecto con la tecleada
   if (p==0)                           //si las dos claves son iguales:
         {
              lcd_putc("\fClave Correcta\n");
         
         }
   if (p!=0)                        //si las dos claves son distintas
         {
           lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave_introducida=0;      //borro la clave introducida
         
         }
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 15 de Marzo de 2013, 15:52:22
mmm que mal,bueno a seguir buscando
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 17 de Marzo de 2013, 01:47:52
Algun avance amigo escarrillense??
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 18 de Marzo de 2013, 05:44:30
Hola! Pues este fin de semana no he podido probar nada del programa ya que no he tenido tiempo y casi me ha venido bien para cargar pilas. Estuve hablando con un amigo y me dijo que lo mejor es gestionar el teclado por interrupciones. Me dijo que de esta manera te ahorras muchos problemas como los que me estan pasando. Despues de una mañana luchando he conseguido que el teclado funcione por interrupciones. Lo que me pasa que el * y # no me los detecta y me sale el valor ASCII creo que es. El esquema es el anteriormente utilizado. Si descubris alguna manera de mejorar este código recibiré vuestras opiniones gratamente. El siguiente paso es añadir la dichosa interrupción externa que tantos quebraderos de cabeza me esta provocando. Aqui os lo dejo:

#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay (CLOCK=4000000)
#use fast_io(A)
#use fast_io(B)
#byte port_b = 0x06
#byte tris_b = 0xff

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas
int flag_teclado;
int tecla,fila,columna;
 
/********************************
Esta Rutina permite rastrear el teclado
y devuelve el valor de la tecla que se
ha presionado
************************************/
int captura(void)
{
int const teclado[4][4] = {{0,1,2,3},
                           {0,4,5,6},
                           {0,7,8,9},
                           {0,'*',0,'#'}};
int tecla,lectura,i;
for(i=0;i<4;i++)
{
output_b(0);
bit_set(port_b,i);
lectura = port_b & 0b11110000;
switch(lectura)
{
case 0b00010000: fila=0;
 columna=i;
 break;
case 0b00100000: fila=1;
 columna=i;
 break;
case 0b01000000: fila=2;
 columna=i;
 break;
case 0b10000000: fila=3;
 columna=i;
 break;
}
}
tecla = teclado[fila][columna];
return(tecla);
}
 
/***************************************
Rutina de Interrupcion.
- Antirebote.
- Llama a rutina "captura" para saber
  la tecla presionada.
- Activa la bandera "flag_teclado"
  a usar en el main o en otra parte
  del programa.
***************************************/
#INT_RB
void tecla_presionada()
{
   int lectura_1,lectura_2;
   lectura_1 = port_b & 0b11110000; //lee portb4:7 y lo guarda en lectura_1
   delay_ms(10); //Funcion AntiRebotes: Espero 10ms.
   lectura_2 = port_b & 0b11110000; //Vuelvo a leer el puerto.
   if(lectura_1==lectura_2 && lectura_1!=0) //Si el valor es igual y distinto de 0 es porque en realidad se presiono una tecla.
   {                                   
      tecla = captura();
      flag_teclado=1;
   }
   set_tris_b(0b11110000);
   output_b(0b00001111);
   clear_interrupt(INT_RB);
   input_b();
}


//////////////PROGRAMA PRINCIPAL///////////////////////
void main()
{
   set_tris_b(0b11110000);
   enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);
   
   lcd_init();            //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   
   while(TRUE)
   {
   if(flag_teclado==1)
      {
      printf(lcd_putc "Tecla: %i\n\r",tecla);
      flag_teclado=0;
      }
   }
}   
 
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 19 de Marzo de 2013, 09:23:40
Hola a todos! Continuo con los avances. He conseguido meter la interrupcion externa y que funcionen ambas cosas. Lo que no consigo es que me guarde las teclas pulsadas como una cadena para que aparezcan en el display una detras de otra. En el display las teclas las oculto mediante asteriscos. Seguiré intentando lo de la cadena y mas avances. Por cierto, os pediría un favor, ¿como se hace para poner el código en una pequeña ventanita mas pegueña? Lo veo en muchos post y no se como se hace y así lograría que los mios no ocupasen tanto jajajaj. Pongo el código:

#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay (CLOCK=4000000)
#use fast_io(A)
#use fast_io(B)
#byte port_b = 0x06
#byte tris_b = 0xff

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas


////////////////DEFINICION DE FUNCIONES////////////////////////////

void escribir_clave(char clave[]);     //funcion que escibre la clave tecleada
void alarma_general(void);             //funcion que enciende la sirena


////////////////VARIABLES GLOBALES///////////////////////////

int flag_teclado;
int tecla,fila,columna;
char bandera=0;
char clave[3];                         //variable usada para recoger la clave tecleada
char clave_introducida[3]={};          //variable usada para los datos ingresados
signed char i;                         //variable usada para movernos por las posiciones de la memoria

 
/********************************
Esta Rutina permite rastrear el teclado
y devuelve el valor de la tecla que se
ha presionado
************************************/
int captura(void)
{
int const teclado[4][4] = {{0,'1','2','3'},
                           {0,'4','5','6'},
                           {0,'7','8','9'},
                           {0,'*','0','#'}};
int tecla,lectura,i;
for(i=0;i<4;i++)
{
output_b(0);
bit_set(port_b,i);
lectura = port_b & 0b11110000;
switch(lectura)
{
case 0b00010000: fila=0;
 columna=i;
 break;
case 0b00100000: fila=1;
 columna=i;
 break;
case 0b01000000: fila=2;
 columna=i;
 break;
case 0b10000000: fila=3;
 columna=i;
 break;
}
}
tecla = teclado[fila][columna];
return(tecla);
}
 
/***************************************
Rutina de Interrupcion.
- Antirebote.
- Llama a rutina "captura" para saber
  la tecla presionada.
- Activa la bandera "flag_teclado"
  a usar en el main o en otra parte
  del programa.
***************************************/
#INT_RB
void tecla_presionada()
{
   int lectura_1,lectura_2;
   lectura_1 = port_b & 0b11110000;          //lee portb4:7 y lo guarda en lectura_1
   delay_ms(10);                             //Funcion AntiRebotes: Espero 10ms.
   lectura_2 = port_b & 0b11110000;          //Vuelvo a leer el puerto.
   if(lectura_1==lectura_2 && lectura_1!=0)  //Si el valor es igual y distinto de 0 es porque en realidad se presiono una tecla.
   {                                   
      tecla = captura();
      flag_teclado=1;
   }
   set_tris_b(0b11110000);
   output_b(0b00001111);
   clear_interrupt(INT_RB);
   set_tris_b(0b11110001);
   //input_b();
}


//////////////INTERRUPCION EXTERNA//////////////////
#INT_EXT
void externa(void)
{
   bandera=1;
}


//////////////PROGRAMA PRINCIPAL///////////////////////
void main()
{
   set_tris_b(0b11110001);
   set_tris_c(0b11111111);       //configuro el puerto c
   enable_interrupts(INT_RB);
   ext_int_edge(H_TO_L);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
   
   lcd_init();            //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
 
   while(TRUE)
   {
   if(flag_teclado==1)
      {
      escribir_clave(clave_introducida);  //tecleo la contraseña
      flag_teclado=0;
      //break;
      }
    if(bandera==1)
      {
         bandera=0;
         alarma_general();
         //break;
      }
   }
}   


//////////FUNCION ESCRIBIR NUEVA CLAVE
void escribir_clave(char clave[])            //funcion que escibre la clave tecleada

{
int i=0;
     
         lcd_putc("\fEscribir clave:\n");   //presentacion
         
            if(!(tecla=='*' || tecla=='#')) // Si no es '*' o '#' en la pantalla aparece un '*'
            {     
            lcd_putc("*");
            clave=tecla;
            }
            i++;     
}



//////////FUNCION ALARMA GENERAL
void alarma_general (void)

{
    set_tris_c(0b11111110);      //pin C0 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje
    //lcd_putc("\fALARMA\n");         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: AngelGris en 19 de Marzo de 2013, 10:14:28
  Una vez obtenida la tecla pulsada, la puedes ir almacenando en un array de caracteres y vas incrementando el contador a medida que presionas las teclas.
  En este punto, podrías hacer que el array termine de incrementarse cuando el contador del mismo llegue a un número determinado de letras (lo cual daría una longitud de clave fija). O bien crear un array grande y con la posibilidad de finalizar el ingreso con una tecla determinada. Por supuesto tendrás que evaluar algún flag para determinar cuando has culminado de ingresar la clave.

  En cuanto a colocar el programa en una "ventanita", debes usar la opción GeSHi del editor de mensaje.
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 19 de Marzo de 2013, 13:43:25
Hola escarrillense,me alegra que ya tengas avances,para lo que comentas de guardar la clave puede ser como comenta AngelGris,un arreglo,bueno como yo lo veo se podría hacer lo siguiente:

1.- Ya tienes declarada una variable dentro de tu rutina de interrupción por cambio de estado que se llama tecla,esa variable yo la colocaría global de manera que las funciones pudieran tener acceso a ella.
2.- De hacerse eso me parece que el arreglo de clave_introducida ya no seria necesario porque utilizarías directamente a tecla por lo tanto tu función escribe clave ya no recibiría parámetros.
3.- Para la captura se podría hacer algo así:

Código: [Seleccionar]
void escribir_clave()            //funcion que escibre la clave tecleado
{
int i=0;
        lcd_putc("\fEscribir clave:\n");   //presentacion
if(!(tecla=='*' || tecla=='#')) // Si no es '*' o '#' en la pantalla aparece un '*'
        {     
           lcd_putc("*");
           clave[i]=tecla;
   if(i<3)
   {
                i++;
           }
   else
   {
i=0;
   }
       } 
}

con lo que cada ves que llames a la función escribir_clave() iniciara guardando la tecla presionada en la posición 0 del arreglo,y preguntara si ya esta cubierta la longitud de la clave esperada,en este caso 3 posiciones,si no se ha cubierto incrementa i,que funciona como un indice para el arreglo,si la longitud ya se ha cumplido se reinicia el indice ( i ) y asi puedes capturar una nueva clave.

4.- Cabe mencionar que para validar la clave tu tendrías que realizar una rutina de checado de los datos del arreglo clave[3],o comparar la cadena como lo habías echo anteriormente con strcmp(str1,str2),yo personalmente siempre comparo valor a valor del arreglo recibido contra uno fijo en mi código,es o debería dar el mismo resultado.

bueno compañero solo son algunas sugerencias jeje ojala tu proyecto te quede excelente ya casi esta solo le falta el ultimo empujon

Saludos desde Morelia
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 19 de Marzo de 2013, 15:24:48
Muchas gracias a los dos por vuestra ayuda! No se que sería de este proyecto sin vosotros porque estaba chocando todo el rato con una pared y me habeis ayudado a ver la luz al final del tunel. Gracias!

Thegame he probado tu código y funciona perfectamente, eso si, para que me guardara bien los arreglos la variable int i=0 la he tenido que guardar como global porque o me machacaba los datos o en la primera posicion de memoria siempre guardaba un cero si la guardaba de la forma que me has indicado. Lo que no consiguo es que en el lcd aparezca un asterisco por cada tecla que presiono, pero bueno, lo que es el arreglo lo guarda perfectamente.

He conseguido comparar las claves y funciona perfecto. Siguiente paso es poder grabar una clave tecleada en la eeprom.Lo he intentado pero me vuelve siempre al main y se reinicia todo el proceso.Las rutinas escribir_clace y comprobar_claves funcionan, la que no va es la de nueva_clave_admin. Os copio lo nuevo. Ya me direis si he conseguido hacer lo de GeSHI bien jajajja

lcd_init();            //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   
   while(TRUE)
   {
   if(flag_teclado==1)
      {
      cambia_clave_inicial();    //cambio la contraseña que viene por defecto
      flag_teclado=0;
      }
    if(bandera==1)
      {
         bandera=0;
         alarma_general();
      }
   }
}   


//////////FUNCION CAMBIAR CLAVE INICIAL
void cambia_clave_inicial(void)             //funcion que cambia clave administrativa

{
int p;
   
   escribir_clave();  //tecleo la contraseña
   if (d==3)
   {
      p=strncmp(clave , clave_inicial,3);    //comparo la clave por defecto con la tecleada
      if (p==0)                           //si las dos claves son iguales:
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          nueva_clave_admin();      //introduzco la nueva clave
         }
      if (p!=0)                        //si las dos claves son distintas
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          clave=0;      //borro la clave introducida
          alarma_general ();        //activo la alarma
         }
   }
   
}

//////////FUNCION ESCRIBIR NUEVA CLAVE
void escribir_clave()            //funcion que escibre la clave tecleada

{
   lcd_putc("\fEscribir clave:\n");   //presentacion
   if(!(tecla=='*' || tecla=='#')) // Si no es '*' o '#' en la pantalla aparece un '*'
   {     
      lcd_putc("*");
      clave[d]=tecla;
      if(d<3)
      {
         d++;
      }
      else
      {
         d=0;
      }
   } 
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)                 //funcion que añade la nueva clave administrativa
{
//int e=0;
   clave=0;                //pongo la clave tecleada a 0
   tecla=0;
   lcd_putc("\fNueva clave:\n");   //presentacion
   if(!(tecla=='*' || tecla=='#')) // Si no es '*' o '#' en la pantalla aparece un '*'
   {     
      lcd_putc("*");
      clave[e]=tecla;
      if(e<3)
      {
         escribir_clave_en_eeprom(e);   //guardamos la nueva clave en la memoria EEPROM
         e++;
      }
      else
      {
         e=0;
      }
   } 
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int e)     //función que escribe las claves en la memoria eeprom

{
   write_eeprom (e,tecla);             //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                   //en la direccion e + 0 (para no pisar datos) de la eeprom
   e++;                            //en una palabra escribe de la posicion 0 a la 2 (3 lugares)
}

Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 20 de Marzo de 2013, 13:27:50
hola,que bueno que ha quedado,con lo de la eeprom déjame ver que puedo investigar o probar, básicamente quieres que la clave tecleada se grabe en la eeprom por lo que entiendo,es así??,lo importante es que gran parte de tu proyecto ya esta funcionando.

p.d. jeje no te ha salido lo del geshi, podrías usar la etiqueta de código,es la que lleva el símbolo de gatito,con esa queda bien
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 21 de Marzo de 2013, 07:52:55
Correcto! Lo que quiero es que una vez que introduzco la clave, en este caso llamada clave_inicial, que viene por defecto (como en muchos aparatos que hay que escribir 0000, o en mi caso 123, cuando los conectas por primera vez), cambiar esa clave por otra que yo quiera, en mi caso la llamare clave_admin, y que esta nueva clave se grabe en la eeprom. Y usar esta clave para el resto de menus que necesito como activar y desactivar la alarma o volver a cambiar esta clave por la razon que sea.

La parte de teclear las clave_inicial y comprobar si es la correcta funciona (ya lo puse en mi anterior post). Lo que no consigo hacer es grabar la nueva clave en la eeprom. Limpio la variable tecla y el arreglo clave (este último se me limpian las dos primeras teclas pero la ultima no se porque no). Despues, al pulsar una tecla para introducir la nueva clave vuelve a la parte del main de flag_teclado==1 y continua con lo de cambiar la clave_inicial, es decir, que se reinicia todo el proceso de nuevo. Lo cual me impide grabar la nueva clave en la eeprom. El problema creo que lo tengo en que no se bien donde poner las rutinas si dentro del While o dentro del if (flag_teclado==1) o donde. Me imagino que este asunto me dará problemas en el futuro con la gestión de los menus (tengo ya uno hecho de cuando empecé con este proyecto con un switch para que según la tecla pulsada active la alarma o cambie la clave_admin) y con la escritura y lectura de claves en la eeprom para los cambios de clave y activación y desactivación de la alarma.

Espero haberme explicado bien y que hayais entendido lo que quiero hacer. Muchas gracias por vuestra ayuda y seguiré luchando

pd: es para que me mateis pero no encuentro lo de la etiqueta de código (simbolo del gatito) o no me aparece. Creo que el bloqueo mental que llevo me impide verlo y seguro que lo tengo en frente de mis narices
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 21 de Marzo de 2013, 13:39:42
Hola compañero,ok entendido y enterado,vamos por partes

1.- Para el borrado del arreglo clave (o inicializacion),lo que deberemos hacer es un pequeño ciclo de borrado,algo como lo que sigue:

     for(k=0;k<3;k++)
     {
            clave[k]=0x00;
      }

     Obviamente deberemos declarar la variable k previamente,si checas inicia desde la pocision 0 hasta la posicion 2 ya que al llegar a 3 la condición de "paro" del for ya no se cumple por lo que ahi termina,si deseas que borre mas posiciones solo hay que incrementar este numero de "paro" o "fin".

     Ahora,el cuando llames este pequeño ciclo,tendria que ser al accesar a la funcion que te cambia la clave por default es decir nueva_clave_admin .


2.- Con lo que comentas de que te regresa al proceso de introducción de clave y no al de cambio de clave,yo pondria dos claves,una de usuario regular y una de administrador y en esta parte:

Código: [Seleccionar]
p=strncmp(clave , clave_inicial,3);    //comparo la clave por defecto con la tecleada
pondria:

Código: [Seleccionar]
p1=strncmp(clave_usuario , clave_inicial,3);    //comparo la clave de usuario
p2=strncmp(clave_admin , clave_inicial,3);    //comparo la clave de administrador

y despues preguntaria cual de las dos es la que se acceso:

Código: [Seleccionar]
if((p1==0)&&(p2!=0))
{
    lcd_putc("\fClave Correcta\n");
    //Y aqui colocas todo lo que puede hacer el usuario regular
}
if((p1!=0)&&(p2==0))
{
    lcd_putc("\fClave de administrador Correcta\n");
    lcd_putc("\fDeseas cambiar tu clave??  1=si  2=no\n");

    while(flag_tecla!=1);
     
     if(flag_tecla==1)
    {
          if(tecla==1)
         {
              nueva_clave_admin();
         }
         else
         {
              break;
         }
     }
}


basicamente lo que se intenta hacer es: si es clave de usuario le das acceso y funciones de usuario,si es de administrador le das acceso y opciones de administrador,esto le da un grado mas de seguridad ya que si no cualquiera podria cambiar la contraseña de administrador ya que nunca haces distincion de si puede o no.

solo es una posible solucion ya sabes que hay muchos caminos para llegar a roma.


P.D. checa la imagen para lo de la etiqueta codigo:
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 21 de Marzo de 2013, 15:08:07
Muchas gracias thegame! Ahora me pongo a añadir lo que me has puesto y ya voy comentando los progresos. Lo de distinguir entre usuario y administrador es buena idea pero de momento voy a intentar hacerlo con uno solo y mas adelante iré añadiendo mejoras.

Acabo de probar lo de borrar la clave y funciona perfectamente.

Gracias tambien por la imagen. Ya me olía yo que lo tenía delante y no lo veía jajja
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 22 de Marzo de 2013, 07:42:14
Hola! Sigo con lo de intentar grabar la nueva clave en la eeprom pero no lo consigo. Llego a la función nueva_clave_admin y puedo poner el primer valor en el arreglo clave pero al introducir el segundo, el programa me lleva de nuevo a la función comprobar_clave por lo que se me reinicia todo. Copio el código para ver si me podeis echar una mano.

Código: [Seleccionar]
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay (CLOCK=4000000)
#use fast_io(A)
#use fast_io(B)
#byte port_b = 0x06
#byte tris_b = 0xff

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas

#rom 0x2100={0,0,0,0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h


////////////////DEFINICION DE FUNCIONES////////////////////////////

void cambia_clave_inicial(void);       //funcion que cambia la clave iinicial
void escribir_clave(void);             //funcion que escibre la clave tecleada
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void limpiar_clave(void);
void alarma_general(void);             //funcion que enciende la sirena


////////////////VARIABLES GLOBALES///////////////////////////

int flag_teclado;
int tecla,fila,columna;
char bandera=0;
char clave[3]={};                         //variable usada para recoger la clave tecleada y guardarla en ROM
char clave_inicial[3]= {'1','2','3'};  //variable usada como clave de inicio                         
int d=0;                               //variable usada para movernos por las posiciones de la memoria
//int e=0;
             
 
/********************************
Esta Rutina permite rastrear el teclado
y devuelve el valor de la tecla que se
ha presionado
************************************/
int captura(void)
{
int const teclado[4][4] = {{0,'1','2','3'},
                           {0,'4','5','6'},
                           {0,'7','8','9'},
                           {0,'*','0','#'}};
int lectura,i;
for(i=0;i<4;i++)
{
output_b(0);
bit_set(port_b,i);
lectura = port_b & 0b11110000;
switch(lectura)
{
case 0b00010000: fila=0;
 columna=i;
 break;
case 0b00100000: fila=1;
 columna=i;
 break;
case 0b01000000: fila=2;
 columna=i;
 break;
case 0b10000000: fila=3;
 columna=i;
 break;
}
}
tecla = teclado[fila][columna];
return(tecla);
}
 
/***************************************
Rutina de Interrupcion.
- Antirebote.
- Llama a rutina "captura" para saber
  la tecla presionada.
- Activa la bandera "flag_teclado"
  a usar en el main o en otra parte
  del programa.
***************************************/
#INT_RB
void tecla_presionada()
{
   int lectura_1,lectura_2;
   lectura_1 = port_b & 0b11110000;          //lee portb4:7 y lo guarda en lectura_1
   delay_ms(10);                             //Funcion AntiRebotes: Espero 10ms.
   lectura_2 = port_b & 0b11110000;          //Vuelvo a leer el puerto.
   if(lectura_1==lectura_2 && lectura_1!=0)  //Si el valor es igual y distinto de 0 es porque en realidad se presiono una tecla.
   {                                   
      tecla = captura();
      flag_teclado=1;
   }
   set_tris_b(0b11110000);
   output_b(0b00001111);
   clear_interrupt(INT_RB);
   set_tris_b(0b11110001);

}


//////////////INTERRUPCION EXTERNA//////////////////
#INT_EXT
void externa(void)
{
   bandera=1;
}


//////////////PROGRAMA PRINCIPAL///////////////////////
void main()
{
   set_tris_b(0b11110001);
   set_tris_c(0b11111111);       //configuro el puerto c
   enable_interrupts(INT_RB);
   ext_int_edge(H_TO_L);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
   
   lcd_init();            //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   
   while(TRUE)
   {
   if(flag_teclado==1)
      {
      cambia_clave_inicial();    //cambio la contraseña que viene por defecto
      flag_teclado=0;
      }
    if(bandera==1)
      {
         bandera=0;
         alarma_general();
      }
   }
}   


//////////FUNCION CAMBIAR CLAVE INICIAL
void cambia_clave_inicial(void)             //funcion que cambia clave administrativa

{
int p;
   
   escribir_clave();  //tecleo la contraseña
   if (d==3)
   {
      p=strncmp(clave , clave_inicial,3);    //comparo la clave por defecto con la tecleada
      if (p==0)                           //si las dos claves son iguales:
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
     limpiar_clave();
          nueva_clave_admin();      //introduzco la nueva clave
         }
      if (p!=0)                        //si las dos claves son distintas
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();
          alarma_general ();        //activo la alarma
         }
   }
   
}

//////////FUNCION ESCRIBIR NUEVA CLAVE
void escribir_clave()            //funcion que escibre la clave tecleada

{
   lcd_putc("\fEscribir clave:\n");   //presentacion
   lcd_putc("*");
   clave[d]=tecla;
      if(d<3)
      {
         d++;
      }
      else
      {
         d=0;
      }
   
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)                 //funcion que añade la nueva clave administrativa
{
int d=0;
 clave=0;                //pongo la clave tecleada a 0
 tecla=0;
//int fila=0;
//int columna=0;
   lcd_putc("\fNueva clave:\n");   //presentacion
   if(tecla!=0)
   {   
      lcd_putc("*");
      clave[d]=tecla;
      if(d<3)
      {
         escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
         d++;
      }
      else
      {
         d=0;
      }
      }
   
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void limpiar_clave()     //función que escribe las claves en la memoria eeprom

{
int k;
   for(k=0;k<3;k++)
     {
        clave[k]=0x00;
     }
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int d)     //función que escribe las claves en la memoria eeprom

{
   write_eeprom (d,tecla);             //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                   //en la direccion e + 0 (para no pisar datos) de la eeprom
   d++;                            //en una palabra escribe de la posicion 0 a la 2 (3 lugares)
}


//////////FUNCION ALARMA GENERAL
void alarma_general (void)

{
    set_tris_c(0b11111110);      //pin C0 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje
    //lcd_putc("\fALARMA\n");         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    //alarm_cont = 0;              //pongo a cero el contador de errores
    break;
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 22 de Marzo de 2013, 16:14:12
ok veamos checa los cambios que he echo

1.- En la funcion captura() no es necesario que la declares que regresa un valor int,en este caso modificas a la variable tecla y como es global no hace falta que regrese algún valor

2.- Coloque un mensaje en el display de "Escribir clave" despues del "Bienvenido inicial,ya que solo lo veo que lo tienes pero hasta que presionan una tecla

3.- La variable d,es global,no es necesario redeclararla,eso lo tienes para varias variables,checalo,si esta como global no tiene sentido redeclararla

4.- Cambie la forma en la que inicializas la variable clave,de clave=0 a clave[3]={'0','0','0'},es lo mismo en teoria pero no me fio jeje

5.- Coloque un delay de 500ms despues del mensaje de "Nueva Clave"

6.- Cambie el lugar donde tienes tu funcion de captura,solo la movi mas abajo,despues del main()

6.- En tu funcion que cambia la clave de administrador agregue un ciclo para asegurarnos que no salga de alli hasta que alla capturado los 3 nuevos valores y claro que los alla guardado

coloco el codigo checalo y prueba y ya me diras si va o no va


Código: [Seleccionar]
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay (CLOCK=4000000)
#use fast_io(A)
#use fast_io(B)
#byte port_b = 0x06
#byte tris_b = 0xff

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas

#rom 0x2100={0,0,0,0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h


////////////////DEFINICION DE FUNCIONES////////////////////////////

void cambia_clave_inicial(void);       //funcion que cambia la clave iinicial
void escribir_clave(void);             //funcion que escibre la clave tecleada
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void limpiar_clave(void);
void alarma_general(void);             //funcion que enciende la sirena


////////////////VARIABLES GLOBALES///////////////////////////

int flag_teclado;
int tecla,fila,columna;
char bandera=0;
char clave[3]={};                         //variable usada para recoger la clave tecleada y guardarla en ROM
char clave_inicial[3]= {'1','2','3'};  //variable usada como clave de inicio                         
int d=0;                               //variable usada para movernos por las posiciones de la memoria
//int e=0;
 
/***************************************
Rutina de Interrupcion.
- Antirebote.
- Llama a rutina "captura" para saber
  la tecla presionada.
- Activa la bandera "flag_teclado"
  a usar en el main o en otra parte
  del programa.
***************************************/
#INT_RB
void tecla_presionada()
{
   int lectura_1,lectura_2;
   lectura_1 = port_b & 0b11110000;          //lee portb4:7 y lo guarda en lectura_1
   delay_ms(10);                             //Funcion AntiRebotes: Espero 10ms.
   lectura_2 = port_b & 0b11110000;          //Vuelvo a leer el puerto.
   if(lectura_1==lectura_2 && lectura_1!=0)  //Si el valor es igual y distinto de 0 es porque en realidad se presiono una tecla.
   {                                   
      flag_teclado=1;
  captura();
   }
   set_tris_b(0b11110000);
   output_b(0b00001111);
   clear_interrupt(INT_RB);
   set_tris_b(0b11110001);

}


//////////////INTERRUPCION EXTERNA//////////////////
#INT_EXT
void externa(void)
{
   bandera=1;
}


//////////////PROGRAMA PRINCIPAL///////////////////////
void main()
{
   set_tris_b(0b11110001);
   set_tris_c(0b11111111);       //configuro el puerto c
   enable_interrupts(INT_RB);
   ext_int_edge(H_TO_L);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
   
   lcd_init();            //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   lcd_putc("\fEscribir clave:\n");
   
   while(TRUE)
   {
   if(flag_teclado==1)
      {
flag_teclado=0;
cambia_clave_inicial();    //cambio la contraseña que viene por defecto
     
      }
    if(bandera==1)
      {
         bandera=0;
         alarma_general();
      }
   }
}   

/********************************
Esta Rutina permite rastrear el teclado
y devuelve el valor de la tecla que se
ha presionado
************************************/
void captura(void)
{
int const teclado[4][4] = {{0,'1','2','3'},
                           {0,'4','5','6'},
                           {0,'7','8','9'},
                           {0,'*','0','#'}};
int lectura,i;
for(i=0;i<4;i++)
{
output_b(0);
bit_set(port_b,i);
lectura = port_b & 0b11110000;
switch(lectura)
{
case 0b00010000: fila=0;
 columna=i;
 break;
case 0b00100000: fila=1;
 columna=i;
 break;
case 0b01000000: fila=2;
 columna=i;
 break;
case 0b10000000: fila=3;
 columna=i;
 break;
}
}
tecla = teclado[fila][columna];
return(tecla);
}
//////////FUNCION CAMBIAR CLAVE INICIAL
void cambia_clave_inicial(void)             //funcion que cambia clave administrativa
{
int p;
   
   escribir_clave();  //tecleo la contraseña
   if (d==3)
   {
      p=strncmp(clave , clave_inicial,3);    //comparo la clave por defecto con la tecleada
      if (p==0)                           //si las dos claves son iguales:
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
  limpiar_clave();
          nueva_clave_admin();      //introduzco la nueva clave
         }
      if (p!=0)                        //si las dos claves son distintas
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();
          alarma_general ();        //activo la alarma
         }
   }
   
}

//////////FUNCION ESCRIBIR NUEVA CLAVE
void escribir_clave()            //funcion que escibre la clave tecleada
{
   lcd_putc("*");
   clave[d]=tecla;
      if(d<3)
      {
         d++;
      }
      else
      {
         d=0;
      }
   
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)                 //funcion que añade la nueva clave administrativa
{
 clave[3]={'0','0','0'};                //pongo la clave tecleada a 0
 tecla=0;
aux=0;
//int fila=0;
//int columna=0;
   lcd_putc("\fNueva clave:\n");   //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
while(tecla==0);
      flag_teclado=0;
      lcd_putc("*");
      clave[d]=tecla;
      if(d<3)
      {
         escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
         tecla=0;
         d++;
      }
      else
      {
         d=0;
      }
   }
   
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void limpiar_clave()     //función que escribe las claves en la memoria eeprom
{
int k;
   for(k=0;k<3;k++)
     {
        clave[k]=0x00;
     }
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int d)     //función que escribe las claves en la memoria eeprom
{
   write_eeprom (d,tecla);             //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                   //en la direccion e + 0 (para no pisar datos) de la eeprom
   d++;                            //en una palabra escribe de la posicion 0 a la 2 (3 lugares)
}


//////////FUNCION ALARMA GENERAL
void alarma_general (void)
{
    set_tris_c(0b11111110);      //pin C0 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje
    //lcd_putc("\fALARMA\n");         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    //alarm_cont = 0;              //pongo a cero el contador de errores
    break;
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 23 de Marzo de 2013, 08:47:43
Muchas gracias thegame! Las molestias y la atención que estas tomando conmigo no tienen precio. Pues he probado todo lo que me dijiste y solo he encontrado un par de fallos, uno lo he solucionado y el otro estoy en ello. Te comento punto a punto y asi nos entenderemos mejor:

1.- La función captura() la tengo que declarar que regresa un valor int ya que al final de la misma tenemos un return (tecla) y si la pongo como void me da error. Así que declarándola como int captura (void) funciona perfectamente

2.- Lo de escribir el mensaje "Escribir clave" es un detalle del que me había dado cuenta pero lo había ido dejando y ya no lo había puesto, gracias de todas formas

3.- Lo de la variable d no me había dado cuenta y la tenía declarada como global int d=0, por lo que tienes razon en que no tenía por qué redeclararla

4.- Me he dado cuenta que poner clave=0 o clave[3]={'0','0','0'} no es necesario ya que antes de ir a la función nueva_clave_admin tenemos la rutina limpiar_clave que ya deja la variable clave con todos sus valores a '0'

5.- Gracias por poner ese delay antes de "Nueva clave" ya que de esta manera queda mejor

6.- El mover el lugar de la función captura me ha gustado ya que yo también prefiero poner todas las funciones después del main ya que está todo mas ordenado, pero como empezamos haciéndolo así ya no la moví

7.- No había caido en lo del ciclo para asegurarnos de que no saliera hasta que hubiera capturado los tres valores. Los coge perfectamente pero al teclear el primer valor de la nueva variable en el display aparece un asterisco de sobra aunque en el arreglo solo aparece un valor (que es lo que quiero). El motivo es que el valor de la variable d viene con valor 0x03 de la anterior función. Así que si poniendo d=0 antes del mensaje "Nueva clave" se soluciona. Otro detalle del que me he dado cuenta es que en la función nueva clave admin hay que declarar la variable aux e igualarla a 0 que se nos había olvidado

Me he dado cuenta que mientras ingresamos la nueva clave la interrupción externa no funciona

De momento el código va así con todos los cambios hechos:

Código: [Seleccionar]
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay (CLOCK=4000000)
#use fast_io(A)
#use fast_io(B)
#byte port_b = 0x06
#byte tris_b = 0xff

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas

#rom 0x2100={0,0,0,0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h


////////////////DEFINICION DE FUNCIONES////////////////////////////

int captura(void);
void cambia_clave_inicial(void);       //funcion que cambia la clave iinicial
void escribir_clave(void);             //funcion que escibre la clave tecleada
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void limpiar_clave(void);
void escribir_clave_en_eeprom(int d);     //función que escribe las claves en la memoria eeprom
void alarma_general(void);             //funcion que enciende la sirena


////////////////VARIABLES GLOBALES///////////////////////////

int flag_teclado;
int tecla,fila,columna;
char bandera=0;
char clave[3]={};                         //variable usada para recoger la clave tecleada y guardarla en ROM
char clave_inicial[3]= {'1','2','3'};  //variable usada como clave de inicio                         
int d=0;


/***************************************
Rutina de Interrupcion.
- Antirebote.
- Llama a rutina "captura" para saber
  la tecla presionada.
- Activa la bandera "flag_teclado"
  a usar en el main o en otra parte
  del programa.
***************************************/
#INT_RB
void tecla_presionada()
{
   int lectura_1,lectura_2;
   lectura_1 = port_b & 0b11110000;          //lee portb4:7 y lo guarda en lectura_1
   delay_ms(10);                             //Funcion AntiRebotes: Espero 10ms.
   lectura_2 = port_b & 0b11110000;          //Vuelvo a leer el puerto.
   if(lectura_1==lectura_2 && lectura_1!=0)  //Si el valor es igual y distinto de 0 es porque en realidad se presiono una tecla.
   {                                   
      flag_teclado=1;
     captura();
   }
   set_tris_b(0b11110000);
   output_b(0b00001111);
   clear_interrupt(INT_RB);
   set_tris_b(0b11110001);

}


//////////////INTERRUPCION EXTERNA//////////////////
#INT_EXT
void externa(void)
{
   bandera=1;
}


//////////////PROGRAMA PRINCIPAL///////////////////////
void main()
{
   set_tris_b(0b11110001);       //configuro el puerto b
   set_tris_c(0b11111111);       //configuro el puerto c
   enable_interrupts(INT_RB);
   ext_int_edge(H_TO_L);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
   
   lcd_init();            //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   lcd_putc("\fEscribir clave:\n");
   
   while(TRUE)
   {
   if(flag_teclado==1)
      {
      flag_teclado=0;
      cambia_clave_inicial();    //cambio la contraseña que viene por defecto
     
      }
    if(bandera==1)
      {
         bandera=0;
         alarma_general();
      }
   }
}   


/********************************
Esta Rutina permite rastrear el teclado
y devuelve el valor de la tecla que se
ha presionado
************************************/
int captura(void)
{
int const teclado[4][4] = {{0,'1','2','3'},
                           {0,'4','5','6'},
                           {0,'7','8','9'},
                           {0,'*','0','#'}};
int lectura,i;
for(i=0;i<4;i++)
{
output_b(0);
bit_set(port_b,i);
lectura = port_b & 0b11110000;
switch(lectura)
{
case 0b00010000: fila=0;
 columna=i;
 break;
case 0b00100000: fila=1;
 columna=i;
 break;
case 0b01000000: fila=2;
 columna=i;
 break;
case 0b10000000: fila=3;
 columna=i;
 break;
}
}
tecla = teclado[fila][columna];
return(tecla);
}


//////////FUNCION CAMBIAR CLAVE INICIAL
void cambia_clave_inicial(void)             //funcion que cambia clave administrativa
{
int p;
   
   escribir_clave();  //tecleo la contraseña
   if (d==3)
   {
      p=strncmp(clave , clave_inicial,3);    //comparo la clave por defecto con la tecleada
      if (p==0)                           //si las dos claves son iguales:
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();
          nueva_clave_admin();      //introduzco la nueva clave
         }
      if (p!=0)                        //si las dos claves son distintas
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();
          alarma_general ();        //activo la alarma
         }
   }
   
}

//////////FUNCION ESCRIBIR CLAVE
void escribir_clave()            //funcion que escibre la clave tecleada
{
   lcd_putc("*");
   clave[d]=tecla;
      if(d<3)
      {
         d++;
      }
      else
      {
         d=0;
      }
   
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin()                 //funcion que añade la nueva clave administrativa
{
tecla=0;
int aux=0;
d=0;

   lcd_putc("\fNueva clave:\n");   //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
   while(tecla==0);
    {
      flag_teclado=0;
      lcd_putc("*");
      clave[d]=tecla;
      if(d<3)
      {
         escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
         tecla=0;
         d++;
      }
      else
      {
         d=0;
      }
     }
   }
   
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void limpiar_clave()     //función que escribe las claves en la memoria eeprom
{
int k;
   for(k=0;k<3;k++)
     {
        clave[k]=0x00;
     }
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int d)     //función que escribe las claves en la memoria eeprom
{
   write_eeprom (d,tecla);             //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                   //en la direccion e + 0 (para no pisar datos) de la eeprom
   d++;                            //en una palabra escribe de la posicion 0 a la 2 (3 lugares)
}


//////////FUNCION ALARMA GENERAL
void alarma_general (void)
{
    set_tris_c(0b11111110);      //pin C0 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje
    //lcd_putc("\fALARMA\n");         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    //alarm_cont = 0;              //pongo a cero el contador de errores
    break;
}

De nuevo muchas gracias por todo ya que sin vuestra ayuda no se como estaría ahora. Muchas veces nos atascamos en algo durante tiempo y con la ayuda de otra persona se resuelve en un momento. Ya iré comentando mis avances y lo que vaya añadiendo al proyecto. Le quiero ir añadiendo lo que tenía hecho en el primer post que escribí, que en resumen es: añadir un menu y comparar ahora la clave tecleada con la que tengo en la eeprom para activar y desactivar la alarma
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 23 de Marzo de 2013, 16:04:58
hola compañero

ok lo que creo que pasa en el punto 1 acerca de la funcion es que como la tienes declarada en las definiciones de funciones,como que te regresa un c¿valor int,por eso marca el error al ponerla como void en el cuerpo de la funcion,hay que cambiar eso,ademas de que tienes que quitarle el return dentro de la misma,porque como anteriormente te comente,tecla es global y todas las funciones tienen acceso a ella por lo que el decirle que la regrese podria estar de mas,pero,si asi queda no hay problema jeje :D

ahora,lo del punto numero 4,tienes razon el arreglo se limpia antes.

lo que me causa intriga es lo de la interrupcion externa,tendrias que revisar si en algun momento deshabilitas la interrupcion o si se esta deshabilitando,esto lo puedes checar en el registro INTCON me parece,que es donde se ve si esta o no habilitada,lo puedes hacer en proteus o en el mismo MPLAB haciendo debug paso a paso y checando que pasa cuando entras en la rutina de cambio de clave,si se llegara a deshabilitar en ese punto,se tendria que agregar una instruccion de enable_interrupts(INT_EXT) para asegurar que no se deshabilite,pero primero checalo.

seguimos al pendiente por aqui.

saludos y suerte
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 24 de Marzo de 2013, 06:33:00
Hola thegame!

He cambiado lo de la función captura. La he declarado como void captura (void) y quitado lo del return y funciona correctamente. No se que haría ayer mal.

En lo de la interrupción externa si que hay mas tela que cortar. Compruebo el INTCON y la interrupción está habilitada constantemente. Al pulsar el interruptor se ve en proteus como los pines cambian de estado pero ya no hace nada mas. Creo que el problema está en el while (tecla==0). El uso de whiles ya me ha dado problemas anteriormente cuando quería usar a la vez la interrupción externa, así que probaré otras formas de hacer lo mismo para no usar el while.

Un saludo y muchas gracias por todo
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 24 de Marzo de 2013, 20:09:31
que tal compañero escarillense

mmm  :?,bueno el uso del while en esa parte del codigo lo coloque de manera que se mantuviera en el hasta que tecla cambiara,al ser tecla global si se daria cuenta del cambio de valor en la misma,pero tienes razon no es que no se dispare la interrupcion si no que como ocurre cuando tu programa esta atrapado en el while,regresa a ese mismo while y continua quedandose atrapado el flujo del programa jeje lo siento ese ha sido error mio,lo que podrias hacer es colocar dentro de la condicional tecla==0 una comparativa con la bandera  de la interrupcion es decir en ves de:

Código: [Seleccionar]
while(tecla==o);
colocar algo como;

Código: [Seleccionar]
while(tecla==0 && bandera==0);
de esta forma despues de cambiar el estado de bandera se saldria de ese while y ya no quedaria atrapado en el mismo,ahora despues de eso tendrias que colocar una llamada a la funcion que atiende cuando se dispara la interrupcion.

talves es lo que necesitas,yo no considere que se oprimiria la int_ext estando en la rutina de cambio de clave de admin,pense que ese proceso seria continuo hasta terminar de introducir la clave nueva de admin,pero con esa modificacion tambien se considera el caso que comentas,solo recuerda borrar el flag de bandera de la int_ext

saludos
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 25 de Marzo de 2013, 06:03:57
Muchas gracias thegame! no se me había ocurrido lo de while(tecla==0 && bandera==0); , la verdad es que soy un poco torpe con las puertas lógicas, y solo con ese cambio el programa funciona correctamente. Una vez que salta la interrupción se produce el parpadeo del led como quería. Lo único que cuando salta la int_ext se añaden uno o dos '*' en el display según el número de teclas pulsadas que lleve y aparecen tres '*'. Es decir, si llevo una tecla pulsada se añaden dos '*' y si llevo dos teclas pulsadas se añade un '*'. Pero ni en el arreglo clave[3] ni en la eeprom se añade ningun valor.

He empezado con lo del menu y la comparación de claves. Lo que pretendo es que una vez guardada la nueva clave admin, ir a un menu en el cual segun la tecla pulsada podamos cambiar la clave o activar y desactivar la alarma. He conseguido que llegue al menu pero a la hora de introducir las funciones para que haga lo que quiero según la tecla pulsada me sale el siguiente error al compilar y no se que puede ser:
Recursion not permitted. The linker will not allow recursive function calls.  A function may not call itself and it may not call any other function that will eventually re-call it.

La estructura es la misma que cuando empecé con el proyecto en el primer post de este tema y al compliar no me salía dicho error.

Copio el programa para que le podais echar un vistazo. Saludos y muchas gracias

Código: [Seleccionar]
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay (CLOCK=4000000)
#use fast_io(A)
#use fast_io(B)
#byte port_b = 0x06
#byte tris_b = 0xff

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas

#rom 0x2100={0,0,0,0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h


////////////////DEFINICION DE FUNCIONES////////////////////////////

void captura(void);                    //funcion que captura la clave tecleada
void cambia_clave_inicial(void);       //funcion que cambia la clave inicial
void escribir_clave(void);             //funcion que escibre la clave tecleada
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void limpiar_clave(void);              //funcion que pone a '0' la variable clave
void escribir_clave_en_eeprom(int d);  //función que escribe las claves en la memoria eeprom
void menu_principal(void);             //funcion que muestra el menu principal
void cambiar_clave(void);              //funcion que cambia clave admin
void leer_clave_en_eeprom(int);        //función que lee las claves y las guarda en su correspondiente variable
int comparar_claves(int);              //función que compara las claves
void alarma_general(void);             //funcion que enciende la sirena


////////////////VARIABLES GLOBALES///////////////////////////

int flag_teclado=0;                       //flag que señala que una tecla ha sido pulsada
char bandera=0;                           //flag que señala que se ha producido una interrupcion externa
int tecla;                                //variable que recoge la tecla pulsada
int fila,columna;                         //variables que recogen la fila y columna de la tecla pulsada
char clave[3]={};                         //variable usada para recoger la clave tecleada
char clave_inicial[3]= {'1','2','3'};     //variable usada como clave de inicio                         
int d=0;                                  //variable usada para movernos por las posiciones de la memoria
char clave_eeprom_admin[3];               //variable usada para comparar los datos de la eeprom contra los datos ingresados

/***************************************
Rutina de Interrupcion.
- Antirebote.
- Llama a rutina "captura" para saber
  la tecla presionada.
- Activa la bandera "flag_teclado"
  a usar en el main o en otra parte
  del programa.
***************************************/
#INT_RB
void tecla_presionada()
{
   int lectura_1,lectura_2;                  //variables locales para detectar la tecla pulsada
   lectura_1 = port_b & 0b11110000;          //lee portb4:7 y lo guarda en lectura_1
   delay_ms(10);                             //Funcion AntiRebotes: Espero 10ms.
   lectura_2 = port_b & 0b11110000;          //Vuelvo a leer el puerto.
   if(lectura_1==lectura_2 && lectura_1!=0)  //Si el valor es igual y distinto de 0 es porque en realidad se presiono una tecla.
   {                                   
     flag_teclado=1;                         //marcamos que se ha pulsado una tecla
     captura();                              //capturamos dicha tecla
   }
   set_tris_b(0b11110000);
   output_b(0b00001111);
   clear_interrupt(INT_RB);
   set_tris_b(0b11110001);

}


//////////////INTERRUPCION EXTERNA//////////////////
#INT_EXT
void externa(void)
{
   bandera=1;                    //marcamos que se ha producido una interrupcion externa
}


//////////////PROGRAMA PRINCIPAL///////////////////////
void main()
{
   set_tris_b(0b11110001);       //configuro el puerto b
   set_tris_c(0b11111111);       //configuro el puerto c
   enable_interrupts(INT_RB);    //habilito la interrupcion por cambio de nibble alto
   ext_int_edge(H_TO_L);         //habilito la interrupcion externa por cambio de flanco
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);    //habilito las interrupciones
   
   lcd_init();                   //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   lcd_putc("\fEscribir clave:\n");
   
   while(TRUE)
   {
      if(flag_teclado==1)           //Si se ha pulsado una tecla
      {
         flag_teclado=0;
         cambia_clave_inicial();    //cambio la contraseña que viene por defecto
      }
      if(bandera==1)                //Si se ha producido una interrupcion externa
      {
         bandera=0;
         alarma_general();          //activo la sirena
      }
   }
}   


/********************************
Esta Rutina permite rastrear el teclado
y devuelve el valor de la tecla que se
ha presionado
************************************/
void captura(void)               //funcion que captura la clave tecleada
{
int const teclado[4][4] = {{0,'1','2','3'},
                           {0,'4','5','6'},
                           {0,'7','8','9'},
                           {0,'*','0','#'}};
int lectura,i;
for(i=0;i<4;i++)
{
output_b(0);
bit_set(port_b,i);
lectura = port_b & 0b11110000;
switch(lectura)
{
case 0b00010000: fila=0;
 columna=i;
 break;
case 0b00100000: fila=1;
 columna=i;
 break;
case 0b01000000: fila=2;
 columna=i;
 break;
case 0b10000000: fila=3;
 columna=i;
 break;
}
}
tecla = teclado[fila][columna];
}


//////////FUNCION CAMBIAR CLAVE INICIAL
void cambia_clave_inicial(void)              //funcion que cambia la clave inicial
{
int p;
   
   escribir_clave();                         //tecleo la contraseña
   if (d==3)                                 //Si ya se han introducido todos los valores de la clave
   {
      p=strncmp(clave , clave_inicial,3);    //comparo la clave por defecto con la tecleada
      if (p==0)                              //si las dos claves son iguales:
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          nueva_clave_admin();               //introduzco la nueva clave
         }
      if (p!=0)                              //si las dos claves son distintas
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          alarma_general ();                 //activo la alarma
         }
   }
   
}

//////////FUNCION ESCRIBIR CLAVE
void escribir_clave()            //funcion que escibre la clave tecleada
{
   lcd_putc("*");
   clave[d]=tecla;
      if(d<3)                    //Si no se han introducido todos los valores...
      {
         d++;                    //... incremento una posicion de memoria
      }
      else                       //Si se han introducido todos los valores...
      {
         d=0;                    //... salgo
      }
}


//////////LIMPIAR CLAVE
void limpiar_clave()     //función que pone a '0' la variable clave
{
int k;
   for(k=0;k<3;k++)      //limpiamos uno a uno cada valor de la variable
     {
        clave[k]=0x00;
     }
}


/////FUNCION MENU PRINCIPAL   
void menu_principal (void)             //funcion que muestra el menu principal

{
tecla=0;
d=0;
     lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
     delay_ms(2000);
     while(tecla==0 && bandera==0);
     {
         switch (tecla)
         {
         case '0':         //si '0' va a activar la alarma
            //activar_alarma();
            alarma_general();
         break;
         case '1':         //si '1' va a comprobar clave para despues cambiar la clave
            cambiar_clave();
         break;
         }
     }
}


//////////FUNCION CAMBIAR CLAVE
void cambiar_clave(void)             //funcion que cambia clave administrativa

{
int p;
   escribir_clave();  //escribimos la contraseña
   if (d==3)                                 //Si ya se han introducido todos los valores de la clave
   {
      leer_clave_en_eeprom(d);            //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);               //compara ambas claves
      if (p==0)                           //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          nueva_clave_admin();         //vamos a la rutina para introducir la nueva clave
         }
      if (p!=0)                           //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          alarma_general ();           //activa la alarma
         }
   }
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)          //funcion que añade la nueva clave administrativa
{
tecla=0;                          //limpio las variables
int aux=0;
d=0;

   lcd_putc("\fNueva clave:\n");   //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
      while(tecla==0 && bandera==0);
      {
         flag_teclado=0;
         lcd_putc("*");
         clave[d]=tecla;
         if(d<3)
         {
            escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
            tecla=0;
            d++;
         }
         else
         {
            d=0;
            break;
         }
      }   
   }
   menu_principal();          //voy al menu principal
}


//////////FUNCION COMPARAR CLAVES
int comparar_claves(int)                  //funcion que compara la clave administrativa y la introducida

{
d=0;
int s=0;
   for (d=0;d<3;d++)    //comparo caracter a caracter las claves
   {
      if (clave[d]==clave_eeprom_admin[d])   //si el caracter es igual en las dos claves
        s++;                                             //paso al siguiente caracter
      else                                               //si es distinto la contraseña es incorrecta
        {s=0;
         lcd_putc("\fClave Incorrecta\n");
         break;
        }
   }
   if (s==3)                           //si todos los tres caracteres son iguales
      return 0;                        //devuelvo un '0'
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int d)     //función que escribe las claves en la memoria eeprom
{
   write_eeprom (d,tecla);               //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                         //en la direccion d + 0 (para no pisar datos) de la eeprom
   d++;                                  //en una palabra escribe de la posicion 0 a la 2 (3 lugares)
}


//////////LEER_CLAVE_EN_EEPROM
void leer_clave_en_eeprom(int d)       //función que lee las claves y las guarda en su correspondiente variable

{
    for (d=0;d<3;d++)
    {
      clave_eeprom_admin[d] = read_eeprom(d);      //guardamos cada valor de la direccion i + 0 (para no pisar datos)
      delay_ms(20);                                //de la eeprom en la variable global correspondiente
    }
}


//////////FUNCION ALARMA GENERAL
void alarma_general (void)       //funcion que enciende la sirena
{
    set_tris_c(0b11111110);      //pin C0 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje
    //lcd_putc("\fALARMA\n");         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    //alarm_cont = 0;            //pongo a cero el contador de errores
    break;
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 25 de Marzo de 2013, 15:06:30
pues si efectivamente lo he compilado y me sale lo mismo que a ti,al parecer estas haciendo que la funcion se llame a si misma jeje,al parecer el problema esta en la ubicación de la llamada a menu_principal(),normalmente este tipo de menus yo los he visto en el while infinito del main,es decir,dentro del main,ahora la pregunta es: quieres que siempre se muestre el menu??? o quieres que solo en ciertas situaciones se muestre?? o presionando una tecla en particular??? eso ya es facil,solo cambia la ubicacion de la llamada a la funcion de menu_principal(),si quieres que se vea siempre,ponlo dentro del while infinito,si quieres que se muestre con una tecla en particular (que para mi punto de vista seria lo ideal),solo coloca una condicional dentro del while infinito para que cuando se presione ese tecla se muestre el menu.

con eso se soluciona el problema de la compilacion,por ahi sale un warning referente a la deshabilitacion de alguna de las interrupciones,yo pienso que se refiere a la de cambio de estado del puerto B,recuerda que muchas operaciones dentro de una interrupcion no son muy recomendables,el manejo de banderas es lo que se recomienda,podrias igual que en la int_ext colocar una bandera en la de int_rb,y chequearla de la misma manera dentro del while infinito del main. con eso se quita el warning,aunque no te da problemas si lo dejas jeje

saludos y seguimos en contacto
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 25 de Marzo de 2013, 15:12:18
checa,compilando con las modificaciones que te menciono no hay mas problema

Código: [Seleccionar]
#include<16f876.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay (CLOCK=4000000)
#use fast_io(A)
#use fast_io(B)
#byte port_b = 0x06
#byte tris_b = 0xff

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas

#rom 0x2100={0,0,0,0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h


////////////////DEFINICION DE FUNCIONES////////////////////////////

void captura(void);                    //funcion que captura la clave tecleada
void cambia_clave_inicial(void);       //funcion que cambia la clave inicial
void escribir_clave(void);             //funcion que escibre la clave tecleada
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void limpiar_clave(void);              //funcion que pone a '0' la variable clave
void escribir_clave_en_eeprom(int d);  //función que escribe las claves en la memoria eeprom
void menu_principal(void);             //funcion que muestra el menu principal
void cambiar_clave(void);              //funcion que cambia clave admin
void leer_clave_en_eeprom(int);        //función que lee las claves y las guarda en su correspondiente variable
int comparar_claves(int);              //función que compara las claves
void alarma_general(void);             //funcion que enciende la sirena


////////////////VARIABLES GLOBALES///////////////////////////

int flag_teclado=0;                       //flag que señala que una tecla ha sido pulsada
char bandera=0,bandera_rb=0;                           //flag que señala que se ha producido una interrupcion externa
int tecla;                                //variable que recoge la tecla pulsada
int fila,columna;                         //variables que recogen la fila y columna de la tecla pulsada
char clave[3]={};                         //variable usada para recoger la clave tecleada
char clave_inicial[3]= {'1','2','3'};     //variable usada como clave de inicio                         
int d=0;                                  //variable usada para movernos por las posiciones de la memoria
char clave_eeprom_admin[3];               //variable usada para comparar los datos de la eeprom contra los datos ingresados
int lectura_1,lectura_2;                  //variables locales para detectar la tecla pulsada

/***************************************
Rutina de Interrupcion.
- Antirebote.
- Llama a rutina "captura" para saber
  la tecla presionada.
- Activa la bandera "flag_teclado"
  a usar en el main o en otra parte
  del programa.
***************************************/
#INT_RB
void tecla_presionada()
{
   bandera_rb=1;
}


//////////////INTERRUPCION EXTERNA//////////////////
#INT_EXT
void externa(void)
{
   bandera=1;                    //marcamos que se ha producido una interrupcion externa
}


//////////////PROGRAMA PRINCIPAL///////////////////////
void main()
{
   set_tris_b(0b11110001);       //configuro el puerto b
   set_tris_c(0b11111111);       //configuro el puerto c
   enable_interrupts(INT_RB);    //habilito la interrupcion por cambio de nibble alto
   ext_int_edge(H_TO_L);         //habilito la interrupcion externa por cambio de flanco
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);    //habilito las interrupciones
   
   lcd_init();                   //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   lcd_putc("\fEscribir clave:\n");
   
   while(TRUE)
   {
  menu_principal();
      if(flag_teclado==1)           //Si se ha pulsado una tecla
      {
         flag_teclado=0;
         cambia_clave_inicial();    //cambio la contraseña que viene por defecto
      }
  if(bandera_rb==1)
  {
   bandera_rb=0;
     lectura_1 = port_b & 0b11110000;          //lee portb4:7 y lo guarda en lectura_1
   delay_ms(10);                             //Funcion AntiRebotes: Espero 10ms.
   lectura_2 = port_b & 0b11110000;          //Vuelvo a leer el puerto.
   if(lectura_1==lectura_2 && lectura_1!=0)  //Si el valor es igual y distinto de 0 es porque en realidad se presiono una tecla.
   {                                   
     flag_teclado=1;                         //marcamos que se ha pulsado una tecla
     captura();                              //capturamos dicha tecla
   }
   set_tris_b(0b11110000);
   output_b(0b00001111);
   clear_interrupt(INT_RB);
   set_tris_b(0b11110001);
  }
      if(bandera==1)                //Si se ha producido una interrupcion externa
      {
         bandera=0;
         alarma_general();          //activo la sirena
      }
   }
}   


/********************************
Esta Rutina permite rastrear el teclado
y devuelve el valor de la tecla que se
ha presionado
************************************/
void captura(void)               //funcion que captura la clave tecleada
{
int const teclado[4][4] = {{0,'1','2','3'},
                           {0,'4','5','6'},
                           {0,'7','8','9'},
                           {0,'*','0','#'}};
int lectura,i;
for(i=0;i<4;i++)
{
output_b(0);
bit_set(port_b,i);
lectura = port_b & 0b11110000;
switch(lectura)
{
case 0b00010000: fila=0;
 columna=i;
 break;
case 0b00100000: fila=1;
 columna=i;
 break;
case 0b01000000: fila=2;
 columna=i;
 break;
case 0b10000000: fila=3;
 columna=i;
 break;
}
}
tecla = teclado[fila][columna];
}


//////////FUNCION CAMBIAR CLAVE INICIAL
void cambia_clave_inicial(void)              //funcion que cambia la clave inicial
{
int p;
   
   escribir_clave();                         //tecleo la contraseña
   if (d==3)                                 //Si ya se han introducido todos los valores de la clave
   {
      p=strncmp(clave , clave_inicial,3);    //comparo la clave por defecto con la tecleada
      if (p==0)                              //si las dos claves son iguales:
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          nueva_clave_admin();               //introduzco la nueva clave
         }
      if (p!=0)                              //si las dos claves son distintas
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          alarma_general ();                 //activo la alarma
         }
   }
   
}

//////////FUNCION ESCRIBIR CLAVE
void escribir_clave()            //funcion que escibre la clave tecleada
{
   lcd_putc("*");
   clave[d]=tecla;
      if(d<3)                    //Si no se han introducido todos los valores...
      {
         d++;                    //... incremento una posicion de memoria
      }
      else                       //Si se han introducido todos los valores...
      {
         d=0;                    //... salgo
      }
}


//////////LIMPIAR CLAVE
void limpiar_clave()     //función que pone a '0' la variable clave
{
int k;
   for(k=0;k<3;k++)      //limpiamos uno a uno cada valor de la variable
     {
        clave[k]=0x00;
     }
}


/////FUNCION MENU PRINCIPAL   
void menu_principal (void)             //funcion que muestra el menu principal

{
tecla=0;
d=0;
     lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
     delay_ms(2000);
     while(tecla==0 && bandera==0);
     {
         switch (tecla)
         {
         case '0':         //si '0' va a activar la alarma
            //activar_alarma();
            alarma_general();
         break;
         case '1':         //si '1' va a comprobar clave para despues cambiar la clave
            cambiar_clave();
         break;
         }
     }
}


//////////FUNCION CAMBIAR CLAVE
void cambiar_clave(void)             //funcion que cambia clave administrativa

{
int p;
   escribir_clave();  //escribimos la contraseña
   if (d==3)                                 //Si ya se han introducido todos los valores de la clave
   {
      leer_clave_en_eeprom(d);            //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);               //compara ambas claves
      if (p==0)                           //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          nueva_clave_admin();         //vamos a la rutina para introducir la nueva clave
         }
      if (p!=0)                           //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          alarma_general ();           //activa la alarma
         }
   }
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)          //funcion que añade la nueva clave administrativa
{
tecla=0;                          //limpio las variables
int aux=0;
d=0;

   lcd_putc("\fNueva clave:\n");   //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
      while(tecla==0 && bandera==0);
      {
         flag_teclado=0;
         lcd_putc("*");
         clave[d]=tecla;
         if(d<3)
         {
            escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
            tecla=0;
            d++;
         }
         else
         {
            d=0;
            break;
         }
      }   
   }
   //menu_principal();          //voy al menu principal
}


//////////FUNCION COMPARAR CLAVES
int comparar_claves(int)                  //funcion que compara la clave administrativa y la introducida

{
   d=0;
   int s=0;
   for (d=0;d<3;d++)    //comparo caracter a caracter las claves
   {
      if (clave[d]==clave_eeprom_admin[d])   //si el caracter es igual en las dos claves
        s++;                                             //paso al siguiente caracter
      else                                               //si es distinto la contraseña es incorrecta
        {s=0;
         lcd_putc("\fClave Incorrecta\n");
         break;
        }
   }
   if (s==3)                           //si todos los tres caracteres son iguales
      return 0;                        //devuelvo un '0'
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int d)     //función que escribe las claves en la memoria eeprom
{
   write_eeprom (d,tecla);               //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                         //en la direccion d + 0 (para no pisar datos) de la eeprom
   d++;                                  //en una palabra escribe de la posicion 0 a la 2 (3 lugares)
}


//////////LEER_CLAVE_EN_EEPROM
void leer_clave_en_eeprom(int d)       //función que lee las claves y las guarda en su correspondiente variable

{
    for (d=0;d<3;d++)
    {
      clave_eeprom_admin[d] = read_eeprom(d);      //guardamos cada valor de la direccion i + 0 (para no pisar datos)
      delay_ms(20);                                //de la eeprom en la variable global correspondiente
    }
}


//////////FUNCION ALARMA GENERAL
void alarma_general (void)       //funcion que enciende la sirena
{
    set_tris_c(0b11111110);      //pin C0 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje
    //lcd_putc("\fALARMA\n");         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    //alarm_cont = 0;            //pongo a cero el contador de errores
    break;
}


solo comente la linea de la llamada a menu_principal() que es la que causa el error y la coloque al inicio del while,pero como mencione puedes cambiarla segun tus necesidades

saludos
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 26 de Marzo de 2013, 08:18:26
Hola thegame! Probé tu código y no me funciona. Se queda en el mensaje del menu principal y de ahí no se mueve. Detecta que se pulsan las teclas y la interrupción externa pero no hace nada.
 
Lo que quiero hacer es que siempre que acabe de introducir la nueva clave (la que guardo en eeprom) vaya despues al menú principal, por eso había puesto al final de nueva_clave_admin la llamada al menú. Consigo llegar al menú con el código que postee ayer y que detecte la tecla pulsada (sé que le detecta porque he hecho que parpadee el led cuando la detecte). El problema viene porque en la función cambiar_clave (función que utilizo para cambiar la clave guardada en la eeprom) llamo a nueva_clave_admin() para introducir la nueva clave que nos apetezca. Pero esa llamada es la que da el error. La solución creo que está en quitar dicha llamada y enganchar de alguna manera ambas funciones. He probado el poner la función del menú despues de la de cambiar_clave_inicial que hay en el main pero no funciona o no lo hago de la manera correcta. También he probado el poner ambas funciones despues de comprobar ambas banderas y tampoco. Otra cosa que he probado ha sido el quitar cambiar_clave_inicial del main y sustituirlo por escribir_calve() únicamente y gestionar fuera de la lectura de las banderas el cambiar la clave inicial, el menú y todo y tampoco me ha funcionado o no he sabido hacerlo correctamente.

Solucionar este problema y conseguir comparar la clave tecleada con la que tenemos en la eeprom creo que son los dos grandes obstáculos que me quedan y seguire luchando por conseguir sacar adelante este proyecto
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 26 de Marzo de 2013, 13:06:55
hola compañero,mmm ok, haré algunas pruebas mas y te cuento,ya casi esta solo son detalles que se están escapando
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 27 de Marzo de 2013, 08:47:00
Hola the game! Yo también continuo haciendo pruebas pero sigo sin conseguir el resultado que yo quiero. El error consigo que se vaya si elimino la llamada a la función nueva_clave_admin que hay en cambiar_clave() y lo sustituyo por otra cosa pero ya no consigo hacer lo que deseo.

Informaré de como van mis resultados. Un saludo
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 28 de Marzo de 2013, 15:55:27
que pasa amigo escarrilense,has logrado algo mas?? yo no he tenido chance por el trabajo pero ya se viene el puente de semana santa (a bendito dios  :-/) y me pondre a checar y hacer algunas pruebas

saludos
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 01 de Abril de 2013, 05:21:13
Hola compañero! Pues no hay avances, además tampoco he tenido tiempo de hacer mucho y el puente he estado fuera (que necesitaba un poco de descanso) así que a ver si esta semana le doy un buen empujon y saco esto a delante
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 01 de Abril de 2013, 14:44:56
hola,si este puente ha venido bien para descansar un poco,yo he tenido algo de trabajo y tampoco he podido checar esos detallitos que aun estan,pero seguimos en la batalla jeje
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 02 de Abril de 2013, 08:10:06
Hola! He solucionado lo de la recursion de una manera un poco chapucera pero ya no me da error. He creado una función igual que la llamada nueva_clave_admin pero con el nombre cambio_clave_admin. Ya se que no es la mejor solución pero de momento nos evitamos el error.

Ahora consigo entrar en la función cambiar_clave del menú principal pero al escribir la clave para luego compararla con la que tenemos en la eeprom el primer dato que tecleo se me escribe dos veces y no se por qué. Copio los cambios realizados en el código por si me podeis echar una mano. El resto sigue como en anteriores post

Código: [Seleccionar]
/////FUNCION MENU PRINCIPAL   
void menu_principal (void)             //funcion que muestra el menu principal

{
tecla=0;
d=0;
     lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
     delay_ms(2000);
     while(tecla==0 && bandera==0);
     {
         switch (tecla)
         {
         case '0':         //si '0' va a activar la alarma
            //activar_alarma();
            alarma_general();
         break;
         case '1':         //si '1' va a comprobar clave para despues cambiar la clave
           
            cambiar_clave();
           
         break;
         }
     }
}


//////////FUNCION CAMBIAR CLAVE
void cambiar_clave(void)             //funcion que cambia clave administrativa

{
int p;
tecla=0;
d=0;

   lcd_putc("\fEscribir clave:\n");
   limpiar_clave();                          //pongo a '0' la variable clave
    while(tecla==0 && bandera==0);
    {
   escribir_clave();                         //escribimos la contraseña
   if (d==3)                                 //Si ya se han introducido todos los valores de la clave
   {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          cambio_clave_admin();             //vamos a la rutina para introducir la nueva clave
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          alarma_general ();                 //activa la alarma
         }
   }
    }
}


//////////FUNCION CAMBIO CLAVE ADMIN
void cambio_clave_admin(void)           //funcion que añade la nueva clave administrativa
{
tecla=0;                               //limpio las variables
int aux=0;
d=0;

   lcd_putc("\fNueva clave:\n");       //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
      while(tecla==0 && bandera==0);
      {
         flag_teclado=0;
         lcd_putc("*");
         clave[d]=tecla;
         if(d<3)
         {
            escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
            tecla=0;
            d++;
         }
         else
         {
            d=0;
            break;
         }
      }   
   }
 
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 03 de Abril de 2013, 15:15:24
Hola! Esto parece que marcha! Solucionados los problemas que postee ayer. He conseguido ir desde el menu principal a las distintas funciones, que coja las teclas correctamente como su posterior comparación con la de la eeprom y la grabación en la eeprom de una nueva clave en el caso que deseemos cambiar la que tenemos.

Pero como este proyecto no está siendo un camino de rosas me ha aparecido un inconveniente que ya me ha dado problemas anteriormente y es el de la recursión. Una vez acabada la función cambio_clave_admin y en el caso de que desactivemos la alarma me gustaría volver al menú principal pero aparece dicho problema. Cuando se acaba la alarma (parpadeo del led) querría ir a la función cambiar_clave y tambien me da ese error. Copio la parte nueva de código por si me podeis echar una mano ya que el resto sigue igual. He marcado los puntos donde me aparece el error de la recursión comentando esa línea con la palabra ERROR.

El siguiente paso que quiero hacer es añadir un contador de errores, es decir, tener tres intentos para introducir la clave o si no que se active la alarma y no como ahora que al primer error ya saltaba. Lo que no se es como hacerlo para que despues de los dos primeros intentos vuelva al principio de la función en la que estoy. Me pongo con ambas cosas a ver si las consigo sacar.

Muchas gracias por vuestra ayuda y un saludo muy fuerte

Código: [Seleccionar]
//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)           //funcion que añade la nueva clave administrativa
{
tecla=0;                               //limpio las variables
int aux=0;
d=0;

   lcd_putc("\fNueva clave:\n");       //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
      while(tecla==0 && bandera==0);
      {
         flag_teclado=0;
         lcd_putc("*");
         clave[d]=tecla;
         if(d<3)
         {
            escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
            tecla=0;
            d++;
         }
         else
         {
            d=0;
            limpiar_clave();
            break;
         }
      }   
   }
   menu_principal();          //voy al menu principal
}



/////FUNCION MENU PRINCIPAL   
void menu_principal (void)             //funcion que muestra el menu principal

{
tecla=0;
d=0;
     lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
     delay_ms(2000);
     while(tecla==0 && bandera==0);
     {
         switch (tecla)
         {
         case '0':         //si '0' va a activar la alarma
            activar_alarma();
         break;
         case '1':         //si '1' va a comprobar clave para despues cambiar la clave
            cambiar_clave();
         break;
         }
     }
}


//////////FUNCION CAMBIAR CLAVE
void cambiar_clave(void)             //funcion que cambia clave administrativa
{
int p;
tecla=0;
d=0;
int aux=0;
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                         
   while(tecla==0 && bandera==0);
   {
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          cambio_clave_admin();              //vamos a la rutina para introducir la nueva clave
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          alarma_general ();                 //activa la alarma
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////FUNCION COMPARAR CLAVES
int comparar_claves(int)                  //funcion que compara la clave administrativa y la introducida

{
d=0;
int s=0;
   for (d=0;d<3;d++)    //comparo caracter a caracter las claves
   {
      if (clave[d]==clave_eeprom_admin[d])   //si el caracter es igual en las dos claves
         s++;                                             //paso al siguiente caracter
      else                                               //si es distinto la contraseña es incorrecta
        {s=0;
         lcd_putc("\fClave Incorrecta\n");
         break;
        }
   }
   if (s==3)                           //si todos los tres caracteres son iguales
      return 0;                        //devuelvo un '0'
}


//////////FUNCION CAMBIO CLAVE ADMIN
void cambio_clave_admin(void)           //funcion que añade la nueva clave administrativa
{
tecla=0;                               //limpio las variables
int aux=0;
d=0;

   lcd_putc("\fNueva clave:\n");       //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
      while(tecla==0 && bandera==0);
      {
         flag_teclado=0;
         lcd_putc("*");
         clave[d]=tecla;
         if(d<3)
         {
            escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
            tecla=0;
            d++;
         }
         else
         {
            d=0;
            break;
         }
      }   
   }
   //menu_principal();          //ERROR
}


//////////ACTIVAR ALARMA
void activar_alarma(void)           //funcion que activa la alarma
{
int p;
tecla=0;
d=0;
int aux=0;
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                         
   while(tecla==0 && bandera==0);
   {
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma Activada\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          desactivar_alarma();            //vamos a la rutina para desactivar la alarma
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          alarma_general ();                 //activa la alarma
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////DESACTIVAR ALARMA
void desactivar_alarma(void)           //funcion que desactiva la alarma
{
int p;
tecla=0;
d=0;
int aux=0;
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                         
   while(tecla==0 && bandera==0);
   {
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma\nDesactivada");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          break;
          //menu_principal();          //ERROR
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fALARMA\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          alarma_general ();                 //activa la alarma
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int d)     //función que escribe las claves en la memoria eeprom
{
   write_eeprom (d,tecla);               //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                         //en la direccion d + 0 (para no pisar datos) de la eeprom
   d++;                                  //en una palabra escribe de la posicion 0 a la 2 (3 lugares)
}


//////////LEER_CLAVE_EN_EEPROM
void leer_clave_en_eeprom(int d)       //función que lee las claves y las guarda en su correspondiente variable

{
    for (d=0;d<3;d++)
    {
      clave_eeprom_admin[d] = read_eeprom(d);      //guardamos cada valor de la direccion i + 0 (para no pisar datos)
      delay_ms(20);                                //de la eeprom en la variable global correspondiente
    }
}


//////////FUNCION ALARMA GENERAL
void alarma_general (void)       //funcion que enciende la sirena
{
    set_tris_c(0b11111110);      //pin C0 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
   
    //cambio_clave_admin();   //ERROR
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 08 de Abril de 2013, 07:42:40
Hola! Sigo con los problemas del contador y la recursion. El problema de la recursión no se como solucionarlo porque no puedo estar continuamente copiando funciones y cambiandoles el nombre, ya que esa solución me parece muy chapucera.

El contador de errores lo tengo hecho y cuando cambio la clave inicial me funciona. El problema me viene cuando lo utilizo en el resto de funciones ya que al salir del contador me lleva al while(true) que tengo en el main y no al punto de escribir de nuevo la funcion.

Copio el código por si me podeis ayudar

Código: [Seleccionar]
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay (CLOCK=4000000)
#use fast_io(A)
#use fast_io(B)
#byte port_b = 0x06
#byte tris_b = 0xff

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas

#rom 0x2100={0,0,0,0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h


////////////////DEFINICION DE FUNCIONES////////////////////////////

void captura(void);                    //funcion que captura la clave tecleada
void cambia_clave_inicial(void);       //funcion que cambia la clave inicial
void escribir_clave(void);             //funcion que escibre la clave tecleada
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void limpiar_clave(void);              //funcion que pone a '0' la variable clave
void escribir_clave_en_eeprom(int d);  //función que escribe las claves en la memoria eeprom
void menu_principal(void);             //funcion que muestra el menu principal
void cambiar_clave(void);              //funcion que cambia clave admin
int comparar_claves(int);              //función que compara las claves
void cambio_clave_admin(void);         //funcion que añade la nueva clave administrativa
void activar_alarma(void);             //funcion que activa la alarma
void desactivar_alarma(void);          //funcion que desactiva la alarma
void leer_clave_en_eeprom(int);        //función que lee las claves y las guarda en su correspondiente variable
void conteo_intentos(void);            //funcion que cuenta el numero de intentos de ingreso de contraseña
void alarma_general(void);             //funcion que enciende la sirena


////////////////VARIABLES GLOBALES///////////////////////////

int flag_teclado=0;                       //flag que señala que una tecla ha sido pulsada
char bandera=0;                           //flag que señala que se ha producido una interrupcion externa
int tecla;                                //variable que recoge la tecla pulsada
int fila,columna;                         //variables que recogen la fila y columna de la tecla pulsada
char clave[3]={};                         //variable usada para recoger la clave tecleada
char clave_inicial[3]= {'1','2','3'};     //variable usada como clave de inicio                         
int d=0;                                  //variable usada para movernos por las posiciones de la memoria
char clave_eeprom_admin[3];               //variable usada para comparar los datos de la eeprom contra los datos ingresados
int alarm_cont=0;                         //variable global que cuenta los fallos


/***************************************
Rutina de Interrupcion.
- Antirebote.
- Llama a rutina "captura" para saber
  la tecla presionada.
- Activa la bandera "flag_teclado"
  a usar en el main o en otra parte
  del programa.
***************************************/
#INT_RB
void tecla_presionada()
{
   int lectura_1,lectura_2;                  //variables locales para detectar la tecla pulsada
   lectura_1 = port_b & 0b11110000;          //lee portb4:7 y lo guarda en lectura_1
   delay_ms(10);                             //Funcion AntiRebotes: Espero 10ms.
   lectura_2 = port_b & 0b11110000;          //Vuelvo a leer el puerto.
   if(lectura_1==lectura_2 && lectura_1!=0)  //Si el valor es igual y distinto de 0 es porque en realidad se presiono una tecla.
   {                                   
     flag_teclado=1;                         //marcamos que se ha pulsado una tecla
     captura();                              //capturamos dicha tecla
   }
   set_tris_b(0b11110000);
   output_b(0b00001111);
   clear_interrupt(INT_RB);
   set_tris_b(0b11110001);
}


//////////////INTERRUPCION EXTERNA//////////////////
#INT_EXT
void externa(void)
{
   bandera=1;                    //marcamos que se ha producido una interrupcion externa
}


//////////////PROGRAMA PRINCIPAL///////////////////////
void main()
{
   set_tris_b(0b11110001);       //configuro el puerto b
   set_tris_c(0b11111111);       //configuro el puerto c
   enable_interrupts(INT_RB);    //habilito la interrupcion por cambio de nibble alto
   ext_int_edge(H_TO_L);         //habilito la interrupcion externa por cambio de flanco
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);    //habilito las interrupciones
   
   lcd_init();                   //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
   lcd_putc("\fEscribir clave:\n");
   
   while(TRUE)
   {
      if(flag_teclado==1)           //Si se ha pulsado una tecla
      {
         flag_teclado=0;
         cambia_clave_inicial();    //cambio la contraseña que viene por defecto
      }
      if(bandera==1)                //Si se ha producido una interrupcion externa
      {
         bandera=0;
         alarma_general();          //activo la sirena
      }
   }
}   


/*********************************
Esta Rutina permite rastrear el teclado
y devuelve el valor de la tecla que se
ha presionado
************************************/
void captura(void)               //funcion que captura la clave tecleada
{
int const teclado[4][4] = {{0,'1','2','3'},
                           {0,'4','5','6'},
                           {0,'7','8','9'},
                           {0,'*','0','#'}};
int lectura,i;
for(i=0;i<4;i++)
{
output_b(0);
bit_set(port_b,i);
lectura = port_b & 0b11110000;
switch(lectura)
{
case 0b00010000: fila=0;
 columna=i;
 break;
case 0b00100000: fila=1;
 columna=i;
 break;
case 0b01000000: fila=2;
 columna=i;
 break;
case 0b10000000: fila=3;
 columna=i;
 break;
}
}
tecla = teclado[fila][columna];
}


/////////FUNCION CAMBIAR CLAVE INICIAL
void cambia_clave_inicial(void)              //funcion que cambia la clave inicial
{
int p;
   
   escribir_clave();                         //tecleo la contraseña
   if (d==3)                                 //Si ya se han introducido todos los valores de la clave
   {
      p=strncmp(clave , clave_inicial,3);    //comparo la clave por defecto con la tecleada
      if (p==0)                              //si las dos claves son iguales:
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          nueva_clave_admin();               //introduzco la nueva clave
         }
      if (p!=0)                              //si las dos claves son distintas
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
   }
   
}

//////////FUNCION ESCRIBIR CLAVE
void escribir_clave()            //funcion que escibre la clave tecleada
{
   flag_teclado=0;
   lcd_putc("*");
   clave[d]=tecla;
      if(d<3)                    //Si no se han introducido todos los valores...
      {
         d++;                    //... incremento una posicion de memoria
      }
      else                       //Si se han introducido todos los valores...
      {
         d=0;                    //... salgo
      }
   
}


//////////LIMPIAR CLAVE
void limpiar_clave()     //función que pone a '0' la variable clave
{
int k;
   for(k=0;k<3;k++)      //limpiamos uno a uno cada valor de la variable
     {
        clave[k]=0x00;
     }
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)           //funcion que añade la nueva clave administrativa
{
tecla=0;                               //limpio las variables
int aux=0;
d=0;

   lcd_putc("\fNueva clave:\n");       //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
      while(tecla==0 && bandera==0);
      {
         flag_teclado=0;
         lcd_putc("*");
         clave[d]=tecla;
         
         if(d<3)
         {
            escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
            tecla=0;
            d++;
         }
         else
         {
            d=0;
            limpiar_clave();
            break;
         }
      }   
   }
   menu_principal();          //voy al menu principal
}



/////FUNCION MENU PRINCIPAL   
void menu_principal (void)             //funcion que muestra el menu principal

{
tecla=0;
d=0;
     lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
     delay_ms(2000);
     while(tecla==0 && bandera==0);
     {
         switch (tecla)
         {
         case '0':         //si '0' va a activar la alarma
            activar_alarma();
         break;
         case '1':         //si '1' va a comprobar clave para despues cambiar la clave
            cambiar_clave();
         break;
         }
     }
}


//////////FUNCION CAMBIAR CLAVE
void cambiar_clave(void)             //funcion que cambia clave administrativa
{
int p;
tecla=0;
d=0;
int aux=0;
   limpiar_clave();
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                         
   while(tecla==0 && bandera==0);
   {
     flag_teclado=0;
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          cambio_clave_admin();              //vamos a la rutina para introducir la nueva clave
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////FUNCION COMPARAR CLAVES
int comparar_claves(int)                  //funcion que compara la clave administrativa y la introducida

{
d=0;
int s=0;
   for (d=0;d<3;d++)    //comparo caracter a caracter las claves
   {
      if (clave[d]==clave_eeprom_admin[d])   //si el caracter es igual en las dos claves
         s++;                                             //paso al siguiente caracter
      else                                               //si es distinto la contraseña es incorrecta
        {s=0;
         lcd_putc("\fClave Incorrecta\n");
         break;
        }
   }
   if (s==3)                           //si todos los tres caracteres son iguales
      return 0;                        //devuelvo un '0'
}


//////////FUNCION CAMBIO CLAVE ADMIN
void cambio_clave_admin(void)           //funcion que añade la nueva clave administrativa
{
tecla=0;                               //limpio las variables
int aux=0;
d=0;

   lcd_putc("\fNueva clave:\n");       //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
      while(tecla==0 && bandera==0);
      {
         flag_teclado=0;
         lcd_putc("*");
         clave[d]=tecla;
         if(d<3)
         {
            escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
            tecla=0;
            d++;
         }
         else
         {
            d=0;
            break;
         }
      }   
   }
   //menu_principal();          //ERROR RECURSION
}


//////////ACTIVAR ALARMA
void activar_alarma(void)           //funcion que activa la alarma
{
int p;
tecla=0;
d=0;
int aux=0;
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                         
   while(tecla==0 && bandera==0);
   {
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma Activada\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          desactivar_alarma();            //vamos a la rutina para desactivar la alarma
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////DESACTIVAR ALARMA
void desactivar_alarma(void)           //funcion que desactiva la alarma
{
int p;
tecla=0;
d=0;
int aux=0;
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                         
   while(tecla==0 && bandera==0);
   {
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma\nDesactivada");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          //menu_principal();          //ERROR RECURSION
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int d)     //función que escribe las claves en la memoria eeprom
{
   write_eeprom (d,tecla);               //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                         //en la direccion d + 0 (para no pisar datos) de la eeprom
   d++;                                  //en una palabra escribe de la posicion 0 a la 2 (3 lugares)
}


//////////LEER_CLAVE_EN_EEPROM
void leer_clave_en_eeprom(int d)       //función que lee las claves y las guarda en su correspondiente variable

{
    for (d=0;d<3;d++)
    {
      clave_eeprom_admin[d] = read_eeprom(d);      //guardamos cada valor de la direccion i + 0 (para no pisar datos)
      delay_ms(20);                                //de la eeprom en la variable global correspondiente
    }
}


////////////FUNCION CONTEO INTENTOS
void conteo_intentos(void)             //funcion que cuenta el numero de intentos de ingreso de contraseña
{
   if (alarm_cont==2)
   {
      alarm_cont = 0;            //pongo a cero el contador de errores
      alarma_general();
   }
   else
   {
      alarm_cont++;
      tecla=0;                               //limpio las variables
      d=0;
      lcd_putc("\fEscribir clave:\n");
   }
}


//////////FUNCION ALARMA GENERAL
void alarma_general (void)       //funcion que enciende la sirena
{
    set_tris_c(0b11111110);      //pin C0 como salida                             
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje
    //lcd_putc("\fALARMA\n");         
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
   
    //cambio_clave_admin();
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: AngelGris en 08 de Abril de 2013, 08:47:05
  En ocasiones ocurre que es necesario replantearse el orden o la estructura del programa.

  Tal vez deberías dejar el menu_principal() dentro del main y llamar desde allí mismo al resto de las funciones. Así, cuando retornes de cualquier función, volverías al flujo normal del programa.
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 08 de Abril de 2013, 14:20:01
que tal amigo escarrillense,yo pienso que el problema esta como dice el amigo AngelGris en la secuencia o flujo del programa por eso te los problemas de la recursividad, no he tenido chance de probar pero porque no haces lo que te sugiere y pruebas
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 09 de Abril de 2013, 08:20:30
Muchas gracias a ambos por dar en el clavo! Teníais toda la razón con lo de mover la función menu_principal al main y reestructurar el programa. He hecho lo del main y eliminado alguna función como la de escribir_clave y la de cambio_clave_inicial y directamente he grabado la clave por defecto en la eeprom al inicio del programa y así he evitado duplicidades y funciones muy parecidas con el mismo nombre.

Quedan por pulir un par de detalles que ahora comento. El primero de ellos trata sobre el contador de errores. Cuando sale de esa función me lleva al while(true) y me gustaría que me llevara de nuevo a la función donde se ha producido la clave incorrecta. He intentado hacerlo pero no se como o es que no se puede hacer lo que yo quiero. De la forma en que está ahora tampoco me desagrada y si se tiene que quedar asi tampoco sufriría pero de la otra me gusta mas jeje. O si opinais que así queda mejor seguiré vuestros sabios consejos.

El segundo detalle es que cuando se produce la interrupción externa se llena el arreglo de la clave y lo cuenta como un intento incorrecto y despues me lleva a la función alarma_general (que es lo que yo quiero que haga), ¿cómo puedo hacer para que directamente me lleve a esa función sin pasar por la del contador de intentos?. Igual tampoco se puede hacer lo que deseo. Tampoco sufriría si se queda así pero me gustaría de la otra forma.
Otro fallo que tengo es que al producirse la interrupción externa cuando estoy en la funcion nueva_clave_admin se me borra la clave que tengo guardada en la eeprom a partir de la tecla pulsada en adelante. Es decir, si llevo una tecla pulsada y se producen la interrupción, se me borran los dos valores siguientes y en la eeprom solo se me queda guardado el que he pulsado, lo cual daría lugar a futuros fallos ya que no sabriamos cuantos valores tenemos en caso de que se produjera un problema.

Espero haberme expresado bien y muchas gracias por toda la ayuda mostrada. Copio el código por si me podeis ayudar

Código: [Seleccionar]
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay (CLOCK=4000000)
#use fast_io(A)
#use fast_io(B)
#byte port_b = 0x06
#byte tris_b = 0xff

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas

#rom 0x2100={'1','2','3',0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h


////////////////DEFINICION DE FUNCIONES////////////////////////////

void captura(void);                    //funcion que captura la clave tecleada
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void limpiar_clave(void);              //funcion que pone a '0' la variable clave
void escribir_clave_en_eeprom(int d);  //función que escribe las claves en la memoria eeprom
void menu_principal(void);             //funcion que muestra el menu principal
void cambiar_clave(void);              //funcion que cambia clave admin
int comparar_claves(int);              //función que compara las claves
void activar_alarma(void);             //funcion que activa la alarma
void desactivar_alarma(void);          //funcion que desactiva la alarma
void leer_clave_en_eeprom(int);        //función que lee las claves y las guarda en su correspondiente variable
void conteo_intentos(void);            //funcion que cuenta el numero de intentos de ingreso de contraseña
void alarma_general(void);             //funcion que enciende la sirena


////////////////VARIABLES GLOBALES///////////////////////////

int flag_teclado=0;                       //flag que señala que una tecla ha sido pulsada
char bandera=0;                           //flag que señala que se ha producido una interrupcion externa
int tecla;                                //variable que recoge la tecla pulsada
int fila,columna;                         //variables que recogen la fila y columna de la tecla pulsada
char clave[3]={};                         //variable usada para recoger la clave tecleada                        
int d=0;                                  //variable usada para movernos por las posiciones de la memoria
char clave_eeprom_admin[3];               //variable usada para comparar los datos de la eeprom contra los datos ingresados
int alarm_cont=0;                         //variable global que cuenta los fallos


/***************************************
Rutina de Interrupcion.
- Antirebote.
- Llama a rutina "captura" para saber
  la tecla presionada.
- Activa la bandera "flag_teclado"
  a usar en el main o en otra parte
  del programa.
***************************************/
#INT_RB
void tecla_presionada()
{
   int lectura_1,lectura_2;                  //variables locales para detectar la tecla pulsada
   lectura_1 = port_b & 0b11110000;          //lee portb4:7 y lo guarda en lectura_1
   delay_ms(10);                             //Funcion AntiRebotes: Espero 10ms.
   lectura_2 = port_b & 0b11110000;          //Vuelvo a leer el puerto.
   if(lectura_1==lectura_2 && lectura_1!=0)  //Si el valor es igual y distinto de 0 es porque en realidad se presiono una tecla.
   {                                    
     flag_teclado=1;                         //marcamos que se ha pulsado una tecla
     captura();                              //capturamos dicha tecla
   }
   set_tris_b(0b11110000);
   output_b(0b00001111);
   clear_interrupt(INT_RB);
   set_tris_b(0b11110001);
}


//////////////INTERRUPCION EXTERNA//////////////////
#INT_EXT
void externa(void)
{
   bandera=1;                    //marcamos que se ha producido una interrupcion externa
}


//////////////PROGRAMA PRINCIPAL///////////////////////
void main()
{
   set_tris_b(0b11110001);       //configuro el puerto b
   set_tris_c(0b11111111);       //configuro el puerto c
   enable_interrupts(INT_RB);    //habilito la interrupcion por cambio de nibble alto
   ext_int_edge(H_TO_L);         //habilito la interrupcion externa por cambio de flanco
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);    //habilito las interrupciones
  
   lcd_init();                   //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
  
   while(TRUE)
   {
      lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
      delay_ms(1000);
      if(flag_teclado==1)           //Si se ha pulsado una tecla
      {
         flag_teclado=0;
         menu_principal();          //voy al menu principal
      
      }
      if(bandera==1)                //Si se ha producido una interrupcion externa
      {
         bandera=0;
         alarma_general();          //activo la sirena
      }
   }
  
}  


/*********************************
Esta Rutina permite rastrear el teclado
y devuelve el valor de la tecla que se
ha presionado
************************************/
void captura(void)               //funcion que captura la clave tecleada
{
int const teclado[4][4] = {{0,'1','2','3'},
                           {0,'4','5','6'},
                           {0,'7','8','9'},
                           {0,'*','0','#'}};
int lectura,i;
for(i=0;i<4;i++)
{
output_b(0);
bit_set(port_b,i);
lectura = port_b & 0b11110000;
switch(lectura)
{
case 0b00010000: fila=0;
 columna=i;
 break;
case 0b00100000: fila=1;
 columna=i;
 break;
case 0b01000000: fila=2;
 columna=i;
 break;
case 0b10000000: fila=3;
 columna=i;
 break;
}
}
tecla = teclado[fila][columna];
}


///////FUNCION MENU PRINCIPAL  
void menu_principal (void)             //funcion que muestra el menu principal
{
d=0;
     switch (tecla)
         {
         case '0':         //si '0' va a activar la alarma
            activar_alarma();
         break;
         case '1':         //si '1' va a comprobar clave para despues cambiar la clave
            cambiar_clave();
         break;
         }
}


//////////FUNCION CAMBIAR CLAVE
void cambiar_clave(void)             //funcion que cambia clave administrativa
{
int p;
tecla=0;
d=0;
int aux=0;
   limpiar_clave();
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                          
   while(tecla==0 && bandera==0);
   {
     flag_teclado=0;
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          nueva_clave_admin();               //introduzco la nueva clave
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////FUNCION COMPARAR CLAVES
int comparar_claves(int)                  //funcion que compara la clave administrativa y la introducida

{
d=0;
int s=0;
   for (d=0;d<3;d++)    //comparo caracter a caracter las claves
   {
      if (clave[d]==clave_eeprom_admin[d])   //si el caracter es igual en las dos claves
         s++;                                             //paso al siguiente caracter
      else                                               //si es distinto la contraseña es incorrecta
        {s=0;
         lcd_putc("\fClave Incorrecta\n");
         break;
        }
   }
   if (s==3)                           //si todos los tres caracteres son iguales
      return 0;                        //devuelvo un '0'
}


//////////LIMPIAR CLAVE
void limpiar_clave()     //función que pone a '0' la variable clave
{
int k;
   for(k=0;k<3;k++)      //limpiamos uno a uno cada valor de la variable
     {
        clave[k]=0x00;
     }
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)           //funcion que añade la nueva clave administrativa
{
tecla=0;                               //limpio las variables
int aux=0;
d=0;

   lcd_putc("\fNueva clave:\n");       //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
      while(tecla==0 && bandera==0);
      {
         flag_teclado=0;
         lcd_putc("*");
         clave[d]=tecla;
         if(d<3)
         {
            escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
            tecla=0;
            d++;
         }
         else
         {
            d=0;
            limpiar_clave();
         }
      }  
   }
}


//////////ACTIVAR ALARMA
void activar_alarma(void)           //funcion que activa la alarma
{
int p;
tecla=0;
d=0;
int aux=0;
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                          
   while(tecla==0 && bandera==0);
   {
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma Activada\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          desactivar_alarma();            //vamos a la rutina para desactivar la alarma
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////DESACTIVAR ALARMA
void desactivar_alarma(void)           //funcion que desactiva la alarma
{
int p;
tecla=0;
d=0;
int aux=0;
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                          
   while(tecla==0 && bandera==0);
   {
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma\nDesactivada");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int d)     //función que escribe las claves en la memoria eeprom
{
   write_eeprom (d,tecla);               //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                         //en la direccion d + 0 (para no pisar datos) de la eeprom
   d++;                                  //en una palabra escribe de la posicion 0 a la 2 (3 lugares)
}


//////////LEER_CLAVE_EN_EEPROM
void leer_clave_en_eeprom(int d)       //función que lee las claves y las guarda en su correspondiente variable
{
    for (d=0;d<3;d++)
    {
      clave_eeprom_admin[d] = read_eeprom(d);      //guardamos cada valor de la direccion i + 0 (para no pisar datos)
      delay_ms(20);                                //de la eeprom en la variable global correspondiente
    }
}


////////////FUNCION CONTEO INTENTOS
void conteo_intentos(void)             //funcion que cuenta el numero de intentos de ingreso de contraseña
{
   if (alarm_cont==2)
   {
      alarm_cont = 0;            //pongo a cero el contador de errores
      alarma_general();
   }
   else
   {
      alarm_cont++;
      tecla=0;                               //limpio las variables
      d=0;
      lcd_putc("\fEscribir clave:\n");
   }
}


//////////FUNCION ALARMA GENERAL
void alarma_general (void)       //funcion que enciende la sirena
{
    set_tris_c(0b11111110);      //pin C0 como salida                            
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje
    lcd_putc("\fALARMA\n");          
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 11 de Abril de 2013, 14:17:27
Hola de nuevo! He conseguido solucionar el segundo detalle, el de la interrupción. Lo he hecho creando una nueva función llamada regreso_menu() que nos hace escribir la contraseña que teníamos cuando se produjo la interrupción y a continuación escribir una nueva clave. No se si es la forma mas bonita pero funciona. Asi de esta forma no se nos queda la clave a cero o con valores incontrolados. Lo que respecta al contador de errores no he conseguido solucionarlo de la mejor manera. He puesto alarm_cont =0 en los lugares necesarios y de esta manera no lo sumaría. Creo que entra en la función del conteo de intentos porque cuando se produce la interrupción primero tiene que terminar de hacer lo que le pide la función en la que está (así que tiene que pasar por la funcion conteo_intentos) y después hace lo que le pide la interrupción. ¿Estoy en lo cierto?

Lo del primer punto a corregir, lo que respecta al contador de intentos que me lleva al while(true) no lo consigo programar como me gustaría. Veré que hago aunque no sería problema dejarlo así.

Me estoy volviendo un poco loco y estoy barajando la posibilidad de añadirle un simulador de presencia al sistema, para que se enciendan unos led a unas determinadas horas. He visto que se puede hacer con un ds1307 o similar y me ha surgido una duda. ¿Se podría hacer solo por software o sería muy complicado?

Copio el código y gracias por todo

Código: [Seleccionar]
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay (CLOCK=4000000)
#use fast_io(A)
#use fast_io(B)
#byte port_b = 0x06
#byte tris_b = 0xff

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas

#rom 0x2100={'1','2','3',0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h


////////////////DEFINICION DE FUNCIONES////////////////////////////

void captura(void);                    //funcion que captura la clave tecleada
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void limpiar_clave(void);              //funcion que pone a '0' la variable clave
void escribir_clave_en_eeprom(int d);  //función que escribe las claves en la memoria eeprom
void menu_principal(void);             //funcion que muestra el menu principal
void cambiar_clave(void);              //funcion que cambia clave admin
int comparar_claves(int);              //función que compara las claves
void activar_alarma(void);             //funcion que activa la alarma
void desactivar_alarma(void);          //funcion que desactiva la alarma
void leer_clave_en_eeprom(int);        //función que lee las claves y las guarda en su correspondiente variable
void conteo_intentos(void);            //funcion que cuenta el numero de intentos de ingreso de contraseña
void alarma_general(void);             //funcion que enciende la sirena
void regreso_menu(void);

////////////////VARIABLES GLOBALES///////////////////////////

int flag_teclado=0;                       //flag que señala que una tecla ha sido pulsada
char bandera=0;                           //flag que señala que se ha producido una interrupcion externa
int tecla;                                //variable que recoge la tecla pulsada
int fila,columna;                         //variables que recogen la fila y columna de la tecla pulsada
char clave[3]={};                         //variable usada para recoger la clave tecleada                        
int d=0;                                  //variable usada para movernos por las posiciones de la memoria
char clave_eeprom_admin[3];               //variable usada para comparar los datos de la eeprom contra los datos ingresados
int alarm_cont=0;                         //variable global que cuenta los fallos


/***************************************
Rutina de Interrupcion.
- Antirebote.
- Llama a rutina "captura" para saber
  la tecla presionada.
- Activa la bandera "flag_teclado"
  a usar en el main o en otra parte
  del programa.
***************************************/
#INT_RB
void tecla_presionada()
{
   int lectura_1,lectura_2;                  //variables locales para detectar la tecla pulsada
   lectura_1 = port_b & 0b11110000;          //lee portb4:7 y lo guarda en lectura_1
   delay_ms(10);                             //Funcion AntiRebotes: Espero 10ms.
   lectura_2 = port_b & 0b11110000;          //Vuelvo a leer el puerto.
   if(lectura_1==lectura_2 && lectura_1!=0)  //Si el valor es igual y distinto de 0 es porque en realidad se presiono una tecla.
   {                                    
     flag_teclado=1;                         //marcamos que se ha pulsado una tecla
     captura();                              //capturamos dicha tecla
   }
   set_tris_b(0b11110000);
   output_b(0b00001111);
   clear_interrupt(INT_RB);
   set_tris_b(0b11110001);
}


//////////////INTERRUPCION EXTERNA//////////////////
#INT_EXT
void externa(void)
{
   bandera=1;                    //marcamos que se ha producido una interrupcion externa
}


//////////////PROGRAMA PRINCIPAL///////////////////////
void main()
{
   set_tris_b(0b11110001);       //configuro el puerto b
   set_tris_c(0b11111111);       //configuro el puerto c
   enable_interrupts(INT_RB);    //habilito la interrupcion por cambio de nibble alto
   ext_int_edge(H_TO_L);         //habilito la interrupcion externa por cambio de flanco
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);    //habilito las interrupciones
  
   lcd_init();                   //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
  
   while(TRUE)
   {
      lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
      delay_ms(1000);
      if(flag_teclado==1)           //Si se ha pulsado una tecla
      {
         flag_teclado=0;
         menu_principal();          //voy al menu principal
      
      }
      if(bandera==1)                //Si se ha producido una interrupcion externa
      {
         bandera=0;
         alarma_general();          //activo la sirena
         regreso_menu();
      }
   }
  
}  


/*********************************
Esta Rutina permite rastrear el teclado
y devuelve el valor de la tecla que se
ha presionado
************************************/
void captura(void)               //funcion que captura la clave tecleada
{
int const teclado[4][4] = {{0,'1','2','3'},
                           {0,'4','5','6'},
                           {0,'7','8','9'},
                           {0,'*','0','#'}};
int lectura,i;
for(i=0;i<4;i++)
{
output_b(0);
bit_set(port_b,i);
lectura = port_b & 0b11110000;
switch(lectura)
{
case 0b00010000: fila=0;
 columna=i;
 break;
case 0b00100000: fila=1;
 columna=i;
 break;
case 0b01000000: fila=2;
 columna=i;
 break;
case 0b10000000: fila=3;
 columna=i;
 break;
}
}
tecla = teclado[fila][columna];
}


///////FUNCION MENU PRINCIPAL  
void menu_principal (void)             //funcion que muestra el menu principal
{
d=0;
     switch (tecla)
         {
         case '0':         //si '0' va a activar la alarma
            activar_alarma();
         break;
         case '1':         //si '1' va a comprobar clave para despues cambiar la clave
            cambiar_clave();
         break;
         }
}


//////////FUNCION CAMBIAR CLAVE
void cambiar_clave(void)             //funcion que cambia clave administrativa
{
int p;
tecla=0;
d=0;
int aux=0;

   leer_clave_en_eeprom(d);
   limpiar_clave();
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                          
   while(tecla==0 && bandera==0);
   {
     flag_teclado=0;
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          alarm_cont = 0;
          limpiar_clave();                   //pongo a '0' la variable clave
          nueva_clave_admin();               //introduzco la nueva clave
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////FUNCION COMPARAR CLAVES
int comparar_claves(int)                  //funcion que compara la clave administrativa y la introducida

{
d=0;
int s=0;
   for (d=0;d<3;d++)    //comparo caracter a caracter las claves
   {
      if (clave[d]==clave_eeprom_admin[d])   //si el caracter es igual en las dos claves
         s++;                                             //paso al siguiente caracter
      else                                               //si es distinto la contraseña es incorrecta
        {s=0;
         lcd_putc("\fClave Incorrecta\n");
         break;
        }
   }
   if (s==3)                           //si todos los tres caracteres son iguales
      return 0;                        //devuelvo un '0'
}


//////////LIMPIAR CLAVE
void limpiar_clave()     //función que pone a '0' la variable clave
{
int k;
   for(k=0;k<3;k++)      //limpiamos uno a uno cada valor de la variable
     {
        clave[k]=0x00;
     }
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)           //funcion que añade la nueva clave administrativa
{
tecla=0;                               //limpio las variables
int aux=0;
d=0;

   lcd_putc("\fNueva clave:\n");       //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
      while(tecla==0 && bandera==0);
      {
         flag_teclado=0;
         lcd_putc("*");
         clave[d]=tecla;
         if(d<3)
         {
            escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
            tecla=0;
            d++;
         }
         else
         {
            d=0;
            limpiar_clave();
         }
      }  
   }
}


//////////ACTIVAR ALARMA
void activar_alarma(void)           //funcion que activa la alarma
{
int p;
tecla=0;
d=0;
int aux=0;
   leer_clave_en_eeprom(d);
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                          
   while(tecla==0 && bandera==0);
   {
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma Activada\n");
          delay_ms(2000);
          alarm_cont = 0;
          limpiar_clave();                   //pongo a '0' la variable clave
          desactivar_alarma();            //vamos a la rutina para desactivar la alarma
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////DESACTIVAR ALARMA
void desactivar_alarma(void)           //funcion que desactiva la alarma
{
int p;
tecla=0;
d=0;
int aux=0;
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                          
   while(tecla==0 && bandera==0);
   {
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma\nDesactivada");
          delay_ms(2000);
          alarm_cont = 0;
          limpiar_clave();                   //pongo a '0' la variable clave
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int d)     //función que escribe las claves en la memoria eeprom
{
   write_eeprom (d,tecla);               //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                         //en la direccion d + 0 (para no pisar datos) de la eeprom
   d++;                                  //en una palabra escribe de la posicion 0 a la 2 (3 lugares)
}


//////////LEER_CLAVE_EN_EEPROM
void leer_clave_en_eeprom(int d)       //función que lee las claves y las guarda en su correspondiente variable
{
    for (d=0;d<3;d++)
    {
      clave_eeprom_admin[d] = read_eeprom(d);      //guardamos cada valor de la direccion i + 0 (para no pisar datos)
      delay_ms(20);                                //de la eeprom en la variable global correspondiente
    }
}


////////////FUNCION CONTEO INTENTOS
void conteo_intentos(void)             //funcion que cuenta el numero de intentos de ingreso de contraseña
{
   if (alarm_cont==2)
   {
      alarm_cont = 0;            //pongo a cero el contador de errores
      alarma_general();
   }
   else
   {
      alarm_cont++;
      tecla=0;                               //limpio las variables
      d=0;
      lcd_putc("\fEscribir clave:\n");
   }
}


//////////FUNCION ALARMA GENERAL
void alarma_general (void)       //funcion que enciende la sirena
{
    set_tris_c(0b11111110);      //pin C0 como salida                            
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje
    lcd_putc("\fALARMA\n");          
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    alarm_cont = 0;
}


//////////FUNCION REGRESO MENU
void regreso_menu(void)
{
int p;
tecla=0;
d=0;
int aux=0;

   limpiar_clave();
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                          
   while(tecla==0 && bandera==0);
   {
     flag_teclado=0;
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          nueva_clave_admin();               //introduzco la nueva clave
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          alarma_general();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}

Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 12 de Abril de 2013, 13:13:59
Hola compañero, ya veo que has logrado avanzar bastante eso me gusto,he estado algo ausente por el trabajo pero te comento:

Lo del DS1307 no es complicado,solo requieres esencialmente de dos pines libres de PIC que idealmente te recomendaría fuesen los destinados al protocolo I2C,que es el que usa el RTC DS1307, así se haría todo con el hardware integrado del pic (que si no me equivoco si cuenta con I2C),pero,en caso de no contar con I2C por hardware,no hay problema una de las bondades del CCS es que puede emular el protocolo tan solo con indicarselo en la directiva de configuracion del mismo (checa la ayuda en el apartado #use i2c).

El comunicarse y configurar el DS1307 no implica nada dificil hay muchos post que hablan de ello y por supuesto puedo ayudarte en lo que pueda si lo requieres.

suerte y saludo.
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 16 de Abril de 2013, 07:43:50
Hola! Pues he estado mirando lo del ds1307 y para lo que quiero hacer yo ,que es, que a una hora determinada se encienda un led y que a otra se apague y que esto ocurra todos los dias, no parece muy complicado ni laborioso. Así que me he animado a hacerlo.

Adjunto el nuevo archivo en proteus y el programa y los archivos necesarios. Consigo que trabaje el ds1307 pero no me compara con las horas que le digo.

Ya iré informando de mis avances y si se os ocurre alguna idea o sugerencia será bienvenida y estudiada

Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 17 de Abril de 2013, 14:55:53
hola compañero

 :? esta medio raro como haces la comparacion, mira te comento eso mismo lo hice yo de manera sencilla y al comienzo me dio ese mismo problema,funcionaba y contaba pero no se actibaba la alarma, el problema era el formato con el cual yo comparaba,recuerda que los datos en el DS1307 estan en formato BCD asi que si comparas debe ser en ese mismo formato, no deberia haber problema alguno con eso

Por ahi el compañero RedPic si no me equivoco hizo unas muy utiles funciones de conversion entre binario y BCD y viceversa,podrias checarlas funcionan muy bien.

Tu código esta algo raro jeje, me explico,tienes un while infinito inicialmente justo después del bienvenido y después tienes otro ciclo do-while infinito para revisar el DS1307 pero....no se si me equivoque pero como yo lo veo nunca entraria al segundo ciclo infinito que tienes formado por do-while,ya me corregiran los que saben


Saludos desde Morelia.
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 18 de Abril de 2013, 05:28:49
Hola compañeros de fatigas!

Aquí sigo con mis pruebas. Por lo que respecta a la conversión a BCD, yo pensaba que mi librería del ds1307 me convertía los datos a BCD. La saqué de este foro y a la persona que la utilizaba le funcionaba. La copio por si acaso por si me podeis sacar de la duda.
Código: [Seleccionar]
////////////////////////////////////////////////////////////////////////////////
///                               DS1307.C                                   ///
///                     Driver for Real Time Clock                           ///
///                                                                          ///
/// ds1307_init() - Enable oscillator without clearing the seconds register -///
///                 used when PIC loses power and DS1307 run from 3V BAT     ///
///               - Disable squarewave output                                ///
///                                                                          ///
/// ds1307_set_date_time(day,mth,year,dow,hour,min,sec)  Set the date/time   ///
///                                                                          ///
/// ds1307_get_date(day,mth,year,dow)               Get the date             ///
///                                                                          ///
/// ds1307_get_time(hr,min,sec)                     Get the time             ///
///                                                                          ///
////////////////////////////////////////////////////////////////////////////////

#ifndef RTC_SDA
   #define RTC_SDA  PIN_C4 //4
   #define RTC_SCL  PIN_C3 //3
#endif

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL)

BYTE bin2bcd(BYTE binary_value);
BYTE bcd2bin(BYTE bcd_value);

void ds1307_init(void)
{
   BYTE seconds = 0;

   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x00);      // REG 0
   i2c_start();
   i2c_write(0xD1);      // RD from RTC
   seconds = bcd2bin(i2c_read(0)); // Read current "seconds" in DS1307
   i2c_stop();
   seconds &= 0x7F;

   delay_us(3);

   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x00);      // REG 0
   i2c_write(bin2bcd(seconds));     // Start oscillator with current "seconds value
   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x07);      // Control Register
   i2c_write(0x80);     // Disable squarewave output pin
   i2c_stop();

}

void ds1307_set_date_time(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min, BYTE sec)
{
  sec &= 0x7F;
  hr &= 0x3F;

  i2c_start();
  i2c_write(0xD0);            // I2C write address
  i2c_write(0x00);            // Start at REG 0 - Seconds
  i2c_write(bin2bcd(sec));      // REG 0
  i2c_write(bin2bcd(min));      // REG 1
  i2c_write(bin2bcd(hr));      // REG 2
  i2c_write(bin2bcd(dow));      // REG 3
  i2c_write(bin2bcd(day));      // REG 4
  i2c_write(bin2bcd(mth));      // REG 5
  i2c_write(bin2bcd(year));      // REG 6
  i2c_write(0x80);            // REG 7 - Disable squarewave output pin
  i2c_stop();
}

void ds1307_get_date(BYTE &day, BYTE &mth, BYTE &year, BYTE &dow)
{
  i2c_start();
  i2c_write(0xD0);
  i2c_write(0x03);            // Start at REG 3 - Day of week
  i2c_start();
  i2c_write(0xD1);
  dow  = bcd2bin(i2c_read() & 0x7f);   // REG 3
  day  = bcd2bin(i2c_read() & 0x3f);   // REG 4
  mth  = bcd2bin(i2c_read() & 0x1f);   // REG 5
  year = bcd2bin(i2c_read(0));            // REG 6
  i2c_stop();
}

void ds1307_get_time(BYTE &hr, BYTE &min, BYTE &sec)
{
  i2c_start();
  i2c_write(0xD0);
  i2c_write(0x00);            // Start at REG 0 - Seconds
  i2c_start();
  i2c_write(0xD1);
  sec = bcd2bin(i2c_read() & 0x7f);
  min = bcd2bin(i2c_read() & 0x7f);
  hr  = bcd2bin(i2c_read(0) & 0x3f);
  i2c_stop();

}

BYTE bin2bcd(BYTE binary_value)
{
  BYTE temp;
  BYTE retval;

  temp = binary_value;
  retval = 0;

  while(1)
  {
    // Get the tens digit by doing multiple subtraction
    // of 10 from the binary value.
    if(temp >= 10)
    {
      temp -= 10;
      retval += 0x10;
    }
    else // Get the ones digit by adding the remainder.
    {
      retval += temp;
      break;
    }
  }

  return(retval);
}


// Input range - 00 to 99.
BYTE bcd2bin(BYTE bcd_value)
{
  BYTE temp;

  temp = bcd_value;
  // Shifting upper digit right by 1 is same as multiplying by 8.
  temp >>= 1;
  // Isolate the bits for the upper digit.
  temp &= 0x78;

  // Now return: (Tens * Cool + (Tens * 2) + Ones

  return(temp + (temp >> 2) + (bcd_value & 0x0f));
}

Lo de los ciclos infinitos creo que es un problema más gordo. Lo hice de esa manera porque si lo ponía todo en el while que ya tenía no me funcionaba ni el teclado ni la interrupción, solo el ds1307 y yo quiero que me funcione todo a la vez. No se si porque lo que yo quiero no se puede hacer o porque tengo que modificar alguna parte mas del código que ya tenía. En el código que tengo, en las funciones que necesito pulsar alguna tecla, tengo esto: while(tecla==0 && bandera==0), ¿puede ser este while la razon de que no me funcione todo a la vez?

Un saludo y muchas gracias por todo
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 25 de Abril de 2013, 15:16:31
Hola de nuevo! Despues de una semana peleandome con el ds1307 y mi alarma he conseguido avanzar. Consigo que funcione el reloj y el simulador de presencia (que a una hora que fijo se encienda el led y que a otra se apague). Pero como no todo va a ser perfecto y, como siempre en mi andadura, tengo un pero. El problema es el de siempre en este proyecto, las interrupciones. Lo que yo quiero es que funcione todo a la vez, es decir, que si dejo la alarma activada o si quiero cambiar la clave, el simulador de presencia funcione. No consigo hacerlo ya que el led no se enciende o no se apaga si activamos la alarma o cambiamos la clave justo en las horas fijadas porque se queda en el bucle de esa función y no se produce la comparacion de las horas del simulador de presencia. Espero haberme explicado bien.

Os copio el programa y adjunto los archivos necesarios por si me podeis ayudar. Solucionar esto es lo último que creo que me queda.

Código: [Seleccionar]
#fuses HS            //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#fuses NOWDT         //Deshabilita el Watch Dog Timer
#fuses NOPROTECT     //Deshabilita la proteccion del codigo del pic
#fuses NOLVP         //No Low Voltage Programming on B3(PIC16) or B5(PIC18,no habilita la programacion en bajo voltaje)
#fuses PUT           //Habilita le reseteo de power up timer
#fuses NOBROWNOUT    //No brownout reset

#use delay (CLOCK=4000000)
#use fast_io(A)
#use fast_io(B)
#byte port_b = 0x06
#byte tris_b = 0xff

#include <LCD4.c>             //libreria manejo lcd 8 bits
#include <string.h>           //libreria manejo cadenas
#include <_DS1307.c>

#rom 0x2100={'1','2','3',0,0,0,0}   //la EEPROM se carga con los valores 00h desde la direccion 00h hasta 06h


////////////////DEFINICION DE FUNCIONES////////////////////////////

void captura(void);                    //funcion que captura la clave tecleada
void nueva_clave_admin(void);          //funcion que añade la nueva clave administrativa
void limpiar_clave(void);              //funcion que pone a '0' la variable clave
void escribir_clave_en_eeprom(int d);  //función que escribe las claves en la memoria eeprom
void menu_principal(void);             //funcion que muestra el menu principal
void cambiar_clave(void);              //funcion que cambia clave admin
int comparar_claves(int);              //función que compara las claves
void activar_alarma(void);             //funcion que activa la alarma
void desactivar_alarma(void);          //funcion que desactiva la alarma
void leer_clave_en_eeprom(int);        //función que lee las claves y las guarda en su correspondiente variable
void conteo_intentos(void);            //funcion que cuenta el numero de intentos de ingreso de contraseña
void alarma_general(void);             //funcion que enciende la sirena
void regreso_menu(void);               //funcion que despues de una intrusion recupera la alarma

void write_string_eeprom(int address,char *data);     //funcion que graba en la eeprom las horas fijadas
void read_string_eeprom(int address,char *sl);        //funcion que lee de la eeprom las horas fijadas

////////////////VARIABLES GLOBALES///////////////////////////

int flag_teclado=0;                       //flag que señala que una tecla ha sido pulsada
char bandera=0;                           //flag que señala que se ha producido una interrupcion externa
int tecla;                                //variable que recoge la tecla pulsada
int fila,columna;                         //variables que recogen la fila y columna de la tecla pulsada
char clave[3]={};                         //variable usada para recoger la clave tecleada                        
int d=0;                                  //variable usada para movernos por las posiciones de la memoria
char clave_eeprom_admin[3];               //variable usada para comparar los datos de la eeprom contra los datos ingresados
int alarm_cont=0;                         //variable global que cuenta los fallos

//////////////////////////variables del ds1307

 int hr;
 int min;
 int sec;
 char ValoresLeidos[15];


/***************************************
Rutina de Interrupcion.
- Antirebote.
- Llama a rutina "captura" para saber
  la tecla presionada.
- Activa la bandera "flag_teclado"
  a usar en el main o en otra parte
  del programa.
***************************************/
#INT_RB
void tecla_presionada()
{
   int lectura_1,lectura_2;                  //variables locales para detectar la tecla pulsada
   lectura_1 = port_b & 0b11110000;          //lee portb4:7 y lo guarda en lectura_1
   delay_ms(10);                             //Funcion AntiRebotes: Espero 10ms.
   lectura_2 = port_b & 0b11110000;          //Vuelvo a leer el puerto.
   if(lectura_1==lectura_2 && lectura_1!=0)  //Si el valor es igual y distinto de 0 es porque en realidad se presiono una tecla.
   {                                    
     flag_teclado=1;                         //marcamos que se ha pulsado una tecla
     captura();                              //capturamos dicha tecla
   }
   set_tris_b(0b11110000);
   output_b(0b00001111);
   clear_interrupt(INT_RB);
   set_tris_b(0b11110001);
}


//////////////INTERRUPCION EXTERNA/////////////////
#INT_EXT
void externa(void)
{
   bandera=1;                    //marcamos que se ha producido una interrupcion externa
}


//////////////PROGRAMA PRINCIPAL///////////////////////
void main()
{

char alarmas[14];
char alarma1[]="221415";         //hora fijada para que se encienda el led
char alarma2[]="221430";         //hora fijada para que se apague el led
char *leido=alarmas;

write_string_eeprom(0x04,alarma1);  //escribo las horas fijadas en la eeprom
write_string_eeprom(0x10,alarma2);

   set_tris_b(0b11110001);       //configuro el puerto b
   set_tris_c(0b11111111);       //configuro el puerto c
   enable_interrupts(INT_RB);    //habilito la interrupcion por cambio de nibble alto
   ext_int_edge(H_TO_L);         //habilito la interrupcion externa por cambio de flanco
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);    //habilito las interrupciones
  
   lcd_init();                   //inicializa lcd
   delay_ms(1000);
   lcd_putc ("   Bienvenido   ");
   delay_ms(1000);
  
  
   ds1307_init(DS1307_ALL_DISABLED);
                   //Set date for -> 2-Abril-2010 Viernes
                   //Set time for -> 17:32:00
   ds1307_set_date_time(21,4,10,1,22,14,00);       //hora que le fijo al reloj
  
  
   while(TRUE)
   {
      lcd_putc("\f0-Activa Alarma\n1-Cambia Clave");
      delay_ms(1000);
      if(flag_teclado==1)           //Si se ha pulsado una tecla
      {
         flag_teclado=0;
         menu_principal();          //voy al menu principal
      
      }
      if(bandera==1)                //Si se ha producido una interrupcion externa
      {
         bandera=0;
         alarma_general();          //activo la sirena
         regreso_menu();
      }
      else
      {
         ds1307_get_time(hr,min,sec);
  
         read_string_eeprom(0x04,leido);                    //leo y comparo la primera hora fijada
         sprintf(ValoresLeidos,"%02u%02u%02u",hr,min,sec);
         if(strcmp(ValoresLeidos,leido)==0)
            output_high(pin_C5);
        
         read_string_eeprom(0x10,leido);                    //leo y comparo la segunda hora fijada
         sprintf(ValoresLeidos,"%02u%02u%02u",hr,min,sec);
         if(strcmp(ValoresLeidos,leido)==0)
            output_low(PIN_C5);
        
      }
   }
  
}  


/*********************************
Esta Rutina permite rastrear el teclado
y devuelve el valor de la tecla que se
ha presionado
************************************/
void captura(void)               //funcion que captura la clave tecleada
{
int const teclado[4][4] = {{0,'1','2','3'},
                           {0,'4','5','6'},
                           {0,'7','8','9'},
                           {0,'*','0','#'}};
int lectura,i;
for(i=0;i<4;i++)
{
output_b(0);
bit_set(port_b,i);
lectura = port_b & 0b11110000;
switch(lectura)
{
case 0b00010000: fila=0;
 columna=i;
 break;
case 0b00100000: fila=1;
 columna=i;
 break;
case 0b01000000: fila=2;
 columna=i;
 break;
case 0b10000000: fila=3;
 columna=i;
 break;
}
}
tecla = teclado[fila][columna];
}


///////FUNCION MENU PRINCIPAL  
void menu_principal (void)             //funcion que muestra el menu principal
{
d=0;
     switch (tecla)
         {
         case '0':         //si '0' va a activar la alarma
            activar_alarma();
         break;
         case '1':         //si '1' va a comprobar clave para despues cambiar la clave
            cambiar_clave();
         break;
         }
}


//////////FUNCION CAMBIAR CLAVE
void cambiar_clave(void)             //funcion que cambia clave administrativa
{
int p;
tecla=0;
d=0;
int aux=0;

   leer_clave_en_eeprom(d);
   limpiar_clave();
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                          
   while(tecla==0 && bandera==0);
   {
     flag_teclado=0;
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
    
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          alarm_cont = 0;
          limpiar_clave();                   //pongo a '0' la variable clave
          nueva_clave_admin();               //introduzco la nueva clave
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////FUNCION COMPARAR CLAVES
int comparar_claves(int)                  //funcion que compara la clave administrativa y la introducida

{
d=0;
int s=0;
   for (d=0;d<3;d++)    //comparo caracter a caracter las claves
   {
      if (clave[d]==clave_eeprom_admin[d])   //si el caracter es igual en las dos claves
         s++;                                             //paso al siguiente caracter
      else                                               //si es distinto la contraseña es incorrecta
        {s=0;
         lcd_putc("\fClave Incorrecta\n");
         break;
        }
   }
   if (s==3)                           //si todos los tres caracteres son iguales
      return 0;                        //devuelvo un '0'
}


//////////LIMPIAR CLAVE
void limpiar_clave()     //función que pone a '0' la variable clave
{
int k;
   for(k=0;k<3;k++)      //limpiamos uno a uno cada valor de la variable
     {
        clave[k]=0x00;
     }
}


//////////FUNCION NUEVA CLAVE
void nueva_clave_admin(void)           //funcion que añade la nueva clave administrativa
{
tecla=0;                               //limpio las variables
int aux=0;
d=0;

   lcd_putc("\fNueva clave:\n");       //presentacion
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {
      while(tecla==0 && bandera==0);
      {
         flag_teclado=0;
         lcd_putc("*");
         clave[d]=tecla;
         if(d<3)
         {
            escribir_clave_en_eeprom(d);   //guardamos la nueva clave en la memoria EEPROM
            tecla=0;
            d++;
         }
         else
         {
            d=0;
            limpiar_clave();
         }
      }  
   }
}


//////////ACTIVAR ALARMA
void activar_alarma(void)           //funcion que activa la alarma
{
int p;
tecla=0;
d=0;
int aux=0;
   leer_clave_en_eeprom(d);
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                          
   while(tecla==0 && bandera==0);
   {
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma Activada\n");
          delay_ms(2000);
          alarm_cont = 0;
          limpiar_clave();                   //pongo a '0' la variable clave
          desactivar_alarma();            //vamos a la rutina para desactivar la alarma
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////DESACTIVAR ALARMA
void desactivar_alarma(void)           //funcion que desactiva la alarma
{
int p;
tecla=0;
d=0;
int aux=0;
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                          
   while(tecla==0 && bandera==0);
   {
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      leer_clave_en_eeprom(d);               //lee la contraseña que antes hemos cambiado
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fAlarma\nDesactivada");
          delay_ms(2000);
          alarm_cont = 0;
          limpiar_clave();                   //pongo a '0' la variable clave
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          conteo_intentos();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}


//////////ESCRIBIR_CLAVE_EN_EEPROM
void escribir_clave_en_eeprom(int d)     //función que escribe las claves en la memoria eeprom
{
   write_eeprom (d,tecla);               //guardamos cada valor de la variable global correspondiente
   delay_ms(20);                         //en la direccion d + 0 (para no pisar datos) de la eeprom
   d++;                                  //en una palabra escribe de la posicion 0 a la 2 (3 lugares)
}


//////////LEER_CLAVE_EN_EEPROM
void leer_clave_en_eeprom(int d)       //función que lee las claves y las guarda en su correspondiente variable
{
    for (d=0;d<3;d++)
    {
      clave_eeprom_admin[d] = read_eeprom(d);      //guardamos cada valor de la direccion i + 0 (para no pisar datos)
      delay_ms(20);                                //de la eeprom en la variable global correspondiente
    }
}


/*******************************************************************************
                 FUNCIONES ESCRITURA Y LECTURA EEPROM INTERNA
*******************************************************************************/                
void write_string_eeprom(int address,char *data)
{
   while(*data!=0)
   {
      write_eeprom(address++,*data);
      data++;
   }
   write_eeprom(address,0);
}

void read_string_eeprom(int address,char *sl)
{
   sl--;
   do{
      sl++;
      *sl=read_eeprom(address++);
      }while(*sl!=0);
}



////////////FUNCION CONTEO INTENTOS
void conteo_intentos(void)             //funcion que cuenta el numero de intentos de ingreso de contraseña
{
   if (alarm_cont==2)
   {
      alarm_cont = 0;            //pongo a cero el contador de errores
      alarma_general();
   }
   else
   {
      alarm_cont++;
      tecla=0;                               //limpio las variables
      d=0;
      lcd_putc("\fEscribir clave:\n");
   }
}


//////////FUNCION ALARMA GENERAL
void alarma_general (void)       //funcion que enciende la sirena
{
    set_tris_c(0b11111110);      //pin C0 como salida                            
    output_high(pin_C0);         //enciende la sirena durante 2 seg y muestra mensaje
    lcd_putc("\fALARMA\n");          
    delay_ms(2000);
    output_low(pin_C0);          //apaga la sirena
    alarm_cont = 0;
}


//////////FUNCION REGRESO MENU
void regreso_menu(void)
{
int p;
tecla=0;
d=0;
int aux=0;

   limpiar_clave();
   lcd_putc("\fEscribir clave:\n");
   delay_ms(500);
   for(aux=0;aux<3;aux++)
   {                          
   while(tecla==0 && bandera==0);
   {
     flag_teclado=0;
     lcd_putc("*");
     clave[d]=tecla;
     d++;
     if (d==3)                                 //Si ya se han introducido todos los valores de la clave
     {
      //leer_clave_en_eeprom(d);
      p=comparar_claves(d);                  //compara ambas claves
      if (p==0)                              //si son iguales...
         {lcd_putc("\fClave Correcta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          nueva_clave_admin();               //introduzco la nueva clave
         }
      if (p!=0)                              //si son distintas...
         {lcd_putc("\fClave Incorrecta\n");
          delay_ms(2000);
          limpiar_clave();                   //pongo a '0' la variable clave
          alarma_general();
         }
     }
     else
     {
         tecla=0;
     }
   }
   }
}
Título: Re: Problema con interrupcion externa y teclado
Publicado por: thegame en 07 de Mayo de 2013, 20:02:42
Que fin tubo?? aun con problemas??
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 08 de Mayo de 2013, 04:44:17
Hola compañero!

Pues la alarma tiene el problema que ya comente y es que si estamos haciendo algo (activar o desactivar la alarma, cambiar la clave,..) y justo pasamos por las horas de encendido o apagado del simulador de presencia, el led no se enciende o no se apaga porque estamos en otra rutina. No se como solucionarlo si tiene solución.

Ultimamente lo tenía un poco apartado porque he conseguido una demoboard easypic v7 para probar el programa y estoy teniendo problemas con ella porque justo hay que conectar el display en los pines del puerto b donde estan las interrupciones que utilizo. Lo estoy intentando pasar a otro puerto pero no lo consigo. Estoy probando con la misma librería que en las simulacion de proteus y con la flex_lcd que hay en el foro y no hay manera.

Agradecería cualquier tipo de ayuda y de todas formas muchas gracias thegame por toda tu ayda y a AngleGris por sus comentarios.
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 16 de Mayo de 2013, 07:20:49
Hola de nuevo! Debido a los problemas que comenté en el ultimo post con la demoboard que conseguí, decidí probar el lcd con un mensaje simple como es "HOLA". Consegui mostrarlo en el lcd, pero el potenciometro que controla el contraste del display no funciona correctamente. Por lo tanto he decidido montarlo en placa blanca y partir desde cero. Conseguí encender leds y hacer juegos con ellos, pero no consigo que funcione el lcd. En Proteus lo he probado y si que me funciona. Y en mi montaje las tensiones son las mismas que las de Proteus.
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 05 de Junio de 2013, 06:14:35
Hola de nuevo!

Solucioné el problema del anterior post, y era que el display no hacía buena conexión. Me he puesto a probar el programa por partes montándolo en placa blanca y consigo que el ds1307, el lcd y la interrupción externa vayan bien. También he probado a juntar estas partes y funciona.
Ahora tengo un problema con el teclado. Y es que cuando el programa llega a la parte de la lectura del teclado empiezan a salir simbolos raros en la pantalla aunque no pulse ninguna tecla. Recuerdo que el teclado lo gestiono por la interrupcion portb4-7. No se si puede ser por ruido, falta de algun delay o algo porque en proteus si que funciona.

Os agradecería mucho vuestra ayuda y sabios consejos. Un saludo
Título: Re: Problema con interrupcion externa y teclado
Publicado por: escarrillense en 10 de Junio de 2013, 04:52:43
Problema solucionado! La solución pasaba por conectar unas resistencias de 4k7 entre los pines de las columnas del teclado y masa. Ahora todo funciona perfectamente por lo que puedo dar este proyecto por acabado salvo que se me ocurra mejorarlo de alguna forma.