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.
#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;
}
}
}
}