This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

A cookie will be stored in your browser regardless of choice to prevent you being asked this question again. You will be able to change your cookie settings at any time using the link in the footer.

  • 1 voto(s) - 4 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Estacion Meteorologica
Ha quedado genial :aplauso: :aplauso: :aplauso:
  Responder
Bueno, como este proyecto ha sido entregado para concursar en el proyecto biicode, espero que tengais suerte y os lleveis un premio hoy.

http://web.biicode.com/blog/spainlabs-ma...met-online
  Responder
Gracias, veremos aver que pasa

Enviado desde mi Nexus 4 mediante Tapatalk
  Responder
Hasta soñé esta noche con esto, pero sigue sin salir nada... ya tardan!!!
  Responder
Bueno, al menos habeis ganado el premio al mejor 3d impreso. https://www.biicode.com/biicontest2014-es
  Responder
sistemasorp escribió:Bueno, al menos habeis ganado el premio al mejor 3d impreso. https://www.biicode.com/biicontest2014-es

Asi es, menos es nada :dale2: :dale2:

A mi el primer premio me gusta bastante
  Responder
Así es. El watchduino está curioso. Ahora bien, el segundo y el tercero, si analizamos los puntos que iban a tener en cuenta para la valoración del proyecto...

Pero bueno, Spainlabs ha ganado un premio!!! xD
  Responder
Felicidades, este es el primer paso, para la proxima, a por esos premios molones Gran sonrisa
-> Mi CNC de escritorio CNCDesktop 500 -> https://www.spainlabs.com/foros/tema-Fresadora-Desktop-CNC-500
-> Laboratorio de Fabricación Digital Maker www.lowpower.io 
--> Twitter: https://twitter.com/Grafisoft_ES  | IG: https://www.instagram.com/lowpowerio/
  Responder
Hola shurs, estoy haciendo un ciclo superior y para el proyecto final quería hacer una estación meteorológica que consta de dos partes como la del OP, tengo en camino el mismo reloj, el dht22, sensor de flama, bmp180 y uno de gas. Usaré también una lcd 20x4.

La parte del exterior estará alimentada por una pila de 6000mAh a 3.7V que se recargará mediante un panel solar a 5.5V que da unos 290mAh. (La probé y da buenos resultados, con esa pila de 6A no me tendré que preocupar).

El tema es que desconozco todo el tema de programación tan extremos como este (A mí parecer) y quisiera aprender viendo el hilo.

Pero el tema es que no sé si con un Arduino Nano y un Uno será suficiente o no...

Además el tema de los pcb no tengo ni idea como se hacen y se diseñan pero bueno primero a hacer lo otro (esperando los módulos me hallo).

Acabo de pedir los sensores y eso y espero que para Junio el proyecto esté terminado. (Ahora tengo para manipular un dh11, sensor de lluvia, los arduinos, el lcd con su módulo y el bmp180.

¿Con qué empiezo?


Agradecería alguna guía
  Responder
para la alarma que buzzer usas?

los condensadores qie hacen alli?

puedo hacer el montaje en una pcb prototyping de esas de 9-15cm que esta llena de agujeros?

cuanto te ha costado las pcbs?

cuanto valen que te las fabriquen?

el bmp180, encoder i pic podrías pasar link para comprarlos?
  Responder
Estoy intentando hacer funcionar la lcd 20x4 con i2c, la azul, y nada no funciona con ninguna librería (ya llevo 12...)

¿Alguna idea? ¿Que versión de IDE usaste, Trigger?


Salu2
  Responder
¿Nadie tiene alguna idea?....
  Responder
(16-02-2016, 06:53 PM)Majid escribió: ¿Nadie tiene alguna idea?....

Lo primero que tienes que hacer es verificar que direccion tiene tu lcd,si buscas en google encontraras sin problemas un sketch que escanea los dispositivos I2c y te dice la direccion (con el lcd conectado a sus pines sda,scl y alimentacion claro) suele ser la 0x27 pero a veces cambia.comprueba tambien que el contraste este bien ajustado y que se active la luz de fondo (suele ser algo como .backlaight() )
  Responder
(17-02-2016, 09:14 PM)Bayaz escribió:
(16-02-2016, 06:53 PM)Majid escribió: ¿Nadie tiene alguna idea?....

Lo primero que tienes que hacer es verificar que direccion tiene tu lcd,si buscas en google encontraras sin problemas un sketch que escanea los dispositivos I2c y te dice la direccion (con el lcd conectado a sus pines sda,scl y alimentacion claro) suele ser la 0x27 pero a veces cambia.comprueba tambien que el contraste este bien ajustado y que se active la luz de fondo (suele ser algo como .backlaight() )

Ya lo hice pero nada, mi dirección es 0x3F y probé cientos de librerías y nada...
  Responder
(18-02-2016, 07:58 PM)Majid escribió:
(17-02-2016, 09:14 PM)Bayaz escribió:
(16-02-2016, 06:53 PM)Majid escribió: ¿Nadie tiene alguna idea?....

Lo primero que tienes que hacer es verificar que direccion tiene tu lcd,si buscas en google encontraras sin problemas un sketch que escanea los dispositivos I2c y te dice la direccion (con el lcd conectado a sus pines sda,scl y alimentacion claro) suele ser la 0x27 pero a veces cambia.comprueba tambien que el contraste este bien ajustado y que se active la luz de fondo (suele ser algo como .backlaight() )

Ya lo hice pero nada, mi dirección es 0x3F y probé cientos de librerías y nada...
Seria mejor que abrieras un nuevo post al respecto ,para no desvirtualizar este post.
  Responder
(30-04-2014, 02:22 PM)Triggerr escribió:
sistemasorp escribió:Bueno, al menos habeis ganado el premio al mejor 3d impreso. https://www.biicode.com/biicontest2014-es

Asi es, menos es nada  :dale2:  :dale2:

A mi el primer premio me gusta bastante

Oye en el código de sketch al compilar me sale

C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:4:22: error: WProgram.h: No such file or directory
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In constructor 'Bounce::Bounce(uint8_t, long unsigned int)':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:11: error: 'millis' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:12: error: 'digitalRead' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'void Bounce::write(int)':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:20: error: 'digitalWrite' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'int Bounce::update()':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:46: error: 'millis' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'long unsigned int Bounce::duration()':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:58: error: 'millis' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'int Bounce::debounce()':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:71: error: 'digitalRead' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:73: error: 'millis' was not declared in this scope


sabes porque?


Podrias pasarme los links de las librerias que usaste?

uso arduino 1.0.5

gracias
  Responder
(03-04-2016, 02:47 PM)Majid escribió:
(30-04-2014, 02:22 PM)Triggerr escribió:
sistemasorp escribió:Bueno, al menos habeis ganado el premio al mejor 3d impreso. https://www.biicode.com/biicontest2014-es

Asi es, menos es nada  :dale2:  :dale2:

A mi el primer premio me gusta bastante

Oye en el código de sketch al compilar me sale

C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:4:22: error: WProgram.h: No such file or directory
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In constructor 'Bounce::Bounce(uint8_t, long unsigned int)':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:11: error: 'millis' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:12: error: 'digitalRead' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'void Bounce::write(int)':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:20: error: 'digitalWrite' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'int Bounce::update()':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:46: error: 'millis' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'long unsigned int Bounce::duration()':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:58: error: 'millis' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'int Bounce::debounce()':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:71: error: 'digitalRead' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:73: error: 'millis' was not declared in this scope


sabes porque?


Podrias pasarme los links de las librerias que usaste?

uso arduino 1.0.5

gracias



Necesitas la liberia Debounce, actualmente en mi PC no tengo las librerias que tenia antaño.

http://playground.arduino.cc/Code/Bounce

Un saludo
  Responder
(07-04-2016, 07:49 PM)Triggerr escribió:
(03-04-2016, 02:47 PM)Majid escribió:
(30-04-2014, 02:22 PM)Triggerr escribió: Asi es, menos es nada  :dale2:  :dale2:

A mi el primer premio me gusta bastante

Oye en el código de sketch al compilar me sale

C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:4:22: error: WProgram.h: No such file or directory
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In constructor 'Bounce::Bounce(uint8_t, long unsigned int)':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:11: error: 'millis' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:12: error: 'digitalRead' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'void Bounce::write(int)':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:20: error: 'digitalWrite' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'int Bounce::update()':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:46: error: 'millis' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'long unsigned int Bounce::duration()':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:58: error: 'millis' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp: In member function 'int Bounce::debounce()':
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:71: error: 'digitalRead' was not declared in this scope
C:\Program Files (x86)\Arduino\Arduino ERW 1.0.5\libraries\Bounce\Bounce.cpp:73: error: 'millis' was not declared in this scope


sabes porque?


Podrias pasarme los links de las librerias que usaste?

uso arduino 1.0.5

gracias



Necesitas la liberia Debounce, actualmente en mi PC no tengo las librerias que tenia antaño.

http://playground.arduino.cc/Code/Bounce

Un saludo


Gracias, ya está arreglado 


Por cierto la caja que usaste donde la imprimiste?

Es que no tengo impresora 3D y quisiera una como esa...

Gracias, ya está arreglado 


Por cierto la caja que usaste donde la imprimiste?

Es que no tengo impresora 3D y quisiera una como esa...
  Responder
(31-12-2013, 03:19 PM)Triggerr escribió: Vamos con el codigo, por ahora quedan muchas cosas por hacer y frentes abiertos que luego expondre:
[spoiler]
Código:
//Libreriaswgw
#include <Wire.h>
#include <EEPROM.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <Bounce.h>


//INICIALIZACION
LiquidCrystal_I2C lcd(0x20,20,4);  // set the LCD address to 0x20 for a 20 chars and 4 line display
RTC_DS1307 RTC; //Establecemos el tipo de RTC

//CARACTERES
byte flecha_dech[8] = { 0x0,0x8,0xc,0xe,0xc,0x8,0x0,0x0 };        //Flecha derecha
byte alarma[8] = { 0x4,0xe,0xe,0xe,0x1f,0x0,0x4,0x0 };            //Señal Alarma
byte barradech[8] = { 0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3 };          //Barra a la derecha
byte linea_inf[8] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f };         //Linea Inferior

//ASIGNACION DE PINES ENCODER
enum PinAssignments {
 encoderPinA = 2,   // right (DT)
 encoderPinB = 3,   // left (CLK)
};
//ASIGNACION DE PINES AUXILIAREs
const int encoderSW = 8;                  //Pin 8 para pulsador del encoder
const int buzz = 5;
const int pulsador = 4;
Bounce encoderSW_bounce = Bounce(8,10);  //Asignamos el debounce
Bounce pulsador_bounce = Bounce(4,10);  //Asignamos el debounce

//VARIABLES ENCODER
volatile int menu = 1;              //Contador para el encoder
int lastmenu = 0;                   //Ultima posicion del encoder
static boolean rotating=false;      //Debounce
boolean A_set = false;              //Variables de seteo
boolean B_set = false;  


//VARIABLES
//Variables temporales para ajuste de hora
int fut_hora = 0;
int fut_min = 0;
int fut_seg = 0;
//Variables temporales para ajuste de fecha
int fut_ano = 0;
int fut_mes = 0;
int fut_dia = 0;
//Variables alarma
int fut_hora_alarma = 0;
int fut_min_alarma = 0;
int fut_seg_alarma = 0;  
int alarma_on = 0;        //Variable de activacion
int vol = 20;             //Volumen de la alarma
long temp = 0;            //Variable para melodia
boolean ok_alarma = false;  //Si llegamos a la hora activamos esta variable
boolean sonido = false;     //Variable para la melodia
int i = 0;                  //Variable para la melodia
//Variables para los menus
boolean menu_ajustes =false;
boolean salir = false;    
//Variables
int dia_semana = 0;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void setup() {
    lcd.init();                //Iniciamos el LCD
 lcd.backlight();                      //Iniciamos la retroiluminacion
 lcd.setCursor(6,0);                 //Situamos el cursor al inicio
 lcd.print("Estacion");         //Imprimimos mensaje inicial
 lcd.setCursor(3,1);
 lcd.print("Meteorologica");
 lcd.setCursor(7,3);                
 lcd.print("L1llo5");            
 delay(2000);                           //Esperamos 2 segundos con el mensaje
 lcd.clear();                           //Limpiamos la pantalla
    //ASIGNACION DE TIPO DE PINES
 pinMode(encoderPinA, INPUT_PULLUP);
 pinMode(encoderPinB, INPUT_PULLUP);
 pinMode(encoderSW, INPUT_PULLUP);
 pinMode(buzz, OUTPUT);
 pinMode(pulsador, INPUT);
 //ASIGNACION DE INTERRUPCIONES
 attachInterrupt(0, doEncoderA, CHANGE); //Interrupcion 0 para el pin 2
 attachInterrupt(1, doEncoderB, CHANGE); //Interrupcion 1 para el pin 3
 //CREACION CARACTERES
 lcd.createChar(1,flecha_dech);  // 1 -> Flecha Derecha
 lcd.createChar(2,alarma);       // 2 -> Alarma
 lcd.createChar(3,barradech);    // 3 -> Barra Derecha
 lcd.createChar(4,linea_inf);    // 4 -> Linea Inferior
 //Leemos valores de la alarma
 fut_hora_alarma=EEPROM.read(1);
 fut_min_alarma=EEPROM.read(2);
 fut_seg_alarma=EEPROM.read(3);
 alarma_on=EEPROM.read(4);
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void loop() {
    rotating = true;       //Seteamos el debounce
    if(menu != lastmenu){  //Si la variable menu cambia
        lastmenu=menu;       //Igualamos situamos lastmenu como actual
   menu = menu > 4 ? 1 : menu ;         //Si menu es mayor que 4, volvemos a la posicion 1      
   menu = menu < 1 ? 4 : menu ;         //Si menu es menor que 1, volvemos a la posicion 4
   lcd.clear();         //Limpiamos pantalla
   print_margen();      //Dibujamos el margen superior
    }
    switch (menu) {         //Switch para mostrar menus
        case 1:               //Opcion 1 RELOJ
         lcd.setCursor(7,0);  
         lcd.print("Reloj");
     fun_alarma();           //Comprobamos alarma
     if (RTC.isrunning()) {  //Si no recibimos datos del RTC mostramos error
     printhour();            //Imprimimos la hora
     }else{
       lcd.setCursor(0,1);
       lcd.print("Error Reloj");
     }
          break;    
        case 2:               //Opcion 2 TIEMPO
         lcd.setCursor(6,0);
         lcd.print("Tiempo");
         break;
        case 3:               //Opcion 3 OPCIONES
         lcd.setCursor(6,0);
         lcd.print("Opciones");
     lcd.setCursor(1,1);
     lcd.print("Ajustar Hora");
     lcd.setCursor(1,2);
     lcd.print("Ajustar Fecha");
     lcd.setCursor(1,3);
     lcd.print("Ajustar Alarma");
     encoderSW_bounce.update();    //Actualizamos situacion del pulsador
     if (encoderSW_bounce.fallingEdge()){ //Si pulsamos entramos en opciones
       salir = false ;                     //Seteamos la variable de salida a false
       menu= 1 ;                           //Reinicializamos las variables del encoder
       lastmenu = 1;
     while ( salir == false ){             //Mientras salir sea FALSE, mantenemos el menu
       rotating = true;                    //Establecemos el debounce
       if(menu != lastmenu){               //Si menu ha cambiado
         menu=constrain(menu,1,5);         //Establecemos los limites del menu
         delete_cursor(lastmenu);          //Borramos el cursor anterior al cambiar el valor de menu
         lastmenu=menu;                    //Seteamos como actual lastmenu
       }
       if (menu > 3 && !menu_ajustes){   //Si sobrepasamos por debajo
         menu_ajustes=!menu_ajustes;     //Seteamos que ya hemos limpiado pantalla
         lcd.clear();
         lcd.setCursor(1,0);              
         lcd.print("Ajustes");
         lcd.setCursor(1,1);
         lcd.print("Salir");
       }
       if (menu < 4 && menu_ajustes){    //Si volvemos al menu anterior
         menu_ajustes=!menu_ajustes;     //Seteamos que ya hemos limpiado pantalla
         lcd.clear();      
         print_margen();                 //Dibujamos el margen superior              
         lcd.setCursor(6,0);
         lcd.print("Opciones");
         lcd.setCursor(1,1);
         lcd.print("Ajustar Hora");
         lcd.setCursor(1,2);
         lcd.print("Ajustar Fecha");
         lcd.setCursor(1,3);
         lcd.print("Ajustar Alarma");
       }
       switch (menu) {           //Switch para el menu de ajustes
         case 1:                 //Ajuste de HORA
           lcd.setCursor(0,1);   //Situamos el indicador en la linea 1
           lcd.write(1);
           encoderSW_bounce.update();              //Actualizamos pulsador
           if (encoderSW_bounce.fallingEdge()){    //Si pulsamos entramos a ajustar la hora
           set_hour();                             //Funcion ajustar hora
           salir = true ;                          //Una vez ajustada salimos
           lcd.clear();
           menu=1;                                 //Volvemos al menu RELOJ
           lastmenu = 0;
           }
           break;
         case 2:                 //Ajuste de FECHA
           lcd.setCursor(0,2);   //Situamos el indicador en la linea 2
           lcd.write(1);
           encoderSW_bounce.update();              //Actualizamos pulsador
           if (encoderSW_bounce.fallingEdge()){    //Si pulsamos entramos a ajustar la hora
           set_date();                             //Funcion para ajustar la fecha
           salir = true ;                          //Una vez ajustada salimos del menu
           lcd.clear();  
           menu=1;                                 //Volvemos al menu reloj
           lastmenu = 0;
           }
           break;
         case 3:                 //Ajuste ALARMA
           lcd.setCursor(0,3);   //Situamos el indicador en la linea 3
           lcd.write(1);
           encoderSW_bounce.update();              //Actualizamos pulsador
           if (encoderSW_bounce.fallingEdge()){    //Si pulsamos entramos a ajustar la hora
             set_alarma();                         //Funcion de ajuste de alarma
             salir = true ;                        //Una vez ajustada salimos del menu
             lcd.clear();
             menu=1;                               //Volvemos al menu RELOJ
             lastmenu = 0;
           }
           break;
         case 4:                 //(PROVISIONAL)
           lcd.setCursor(0,0);   //Situamos el indicador en la linea 0
           lcd.write(1);
           break;
         case 5:                 //SALIR
           lcd.setCursor(0,1);   //Situamos el indicador en la linea 1
           lcd.write(1);
           encoderSW_bounce.update();            //Actualizamos pulsador
           if (encoderSW_bounce.risingEdge()){   //Si pulsamos salimos de los menus
             salir = true;     //Seteamos variable salir a TRUE (Salimos del while)
             lcd.clear();      //Limpiamos pantalla
             menu=1;           //Seteamos menu a 1 (Volvemos a la pantalla reloj)
             lastmenu = 0;
           }
       }
     }
     }
          break;
        case 4:                   //Opcion 4 ALARMAS (POSIBLE MODIFICACION POR TIEMPO EXTERIOR)
         lcd.setCursor(6,0);
         lcd.print("Alarmas");
         break;
    }
}

//FUNCIONES++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//Interrupcion al cambio de A
void doEncoderA(){
 // debounce
 if ( rotating ) delay (1);
 //Comprobamos que haya cambiado
   if( digitalRead(encoderPinA) != A_set ) {  
   A_set = !A_set;
   // adjust counter + if A leads B
   if ( A_set && !B_set )
     menu ++;
   rotating = false;  // no more debouncing until loop() hits again
 }
}

//Interrupcion al cambio de B
void doEncoderB(){
 if ( rotating ) delay (1);
 if( digitalRead(encoderPinB) != B_set ) {
   B_set = !B_set;
   //  adjust counter - 1 if B leads A
   if( B_set && !A_set )
     menu --;
   rotating = false; // no more debouncing until loop() hits again
 }
}
//Impresion de menu RELOJ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void printhour(){
 DateTime now = RTC.now();
 //Establecemos la hora
 lcd.setCursor(6,1);
 if(now.hour() >= 0 && now.hour() < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
   lcd.print('0');
 }
 lcd.print(now.hour());
 lcd.print(':');
 if(now.minute() >= 0 && now.minute() < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
   lcd.print('0');
 }
 lcd.print(now.minute());
 lcd.print(':');
 if(now.second() >= 0 && now.second() < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
   lcd.print('0');
 }
 lcd.print(now.second());
 //Establecemos la fecha
 if (dia_semana != now.dayOfWeek()){
   lcd.clear();
   print_margen();
   dia_semana = now.dayOfWeek();
 }
 switch (now.dayOfWeek()){ //Seleccionamos el dia de la semana
 case 0:
   lcd.setCursor(0,2);
   lcd.print("Domingo");
   break;
 case 1:
   lcd.setCursor(0,2);
   lcd.print("Lunes");
   break;
 case 2:
   lcd.setCursor(0,2);
   lcd.print("Martes");
   break;
 case 3:
   lcd.setCursor(0,2);
   lcd.print("Miercoles");
   break;
 case 4:
   lcd.setCursor(0,2);
   lcd.print("Jueves");
   break;
 case 5:
   lcd.setCursor(0,2);
   lcd.print("Viernes");
   break;
 case 6:
   lcd.setCursor(0,2);
   lcd.print("Sabado");
   break;
 }
 //Imprimimos la fecha
 lcd.setCursor(10,2);
 lcd.print(now.day());
 lcd.print('/');
 lcd.print(now.month());
 lcd.print('/');
 lcd.print(now.year());
 if (ok_alarma){         //Si tenemos sonando la alarma mostramos un icono
   lcd.setCursor(19,0);
   lcd.write(2);
   }else{                  //Sino dibujamos el guion
     lcd.setCursor(19,0);
     lcd.write(4);
 }
 if (alarma_on == 1){    //Si tenemos la alarma activa mostramos un icono
   lcd.setCursor(18,0);
   lcd.write(2);
   }else{                  //Sino dibujamos el guion
     lcd.setCursor(18,0);
     lcd.write(4);
 }
 //Mostramos la posicion de la alarma
 lcd.setCursor(0,3);
 lcd.print("Alarma: ");
 if(fut_hora_alarma >= 0 && fut_hora_alarma < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
   lcd.print('0');
 }
 lcd.print(fut_hora_alarma);
 lcd.print(':');
 if(fut_min_alarma >= 0 && fut_min_alarma < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
   lcd.print('0');
 }
 lcd.print(fut_min_alarma);
 lcd.print(':');
 if(fut_seg_alarma >= 0 && fut_seg_alarma < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
   lcd.print('0');
 }
 lcd.print(fut_seg_alarma);
}

//Imprimir hora al ajustarla++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void adj_print_hora(int fut_hora,int fut_min, int fut_seg){
 lcd.setCursor(0,3);
 if(fut_hora >= 0 && fut_hora  < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
   lcd.print('0');
 }
 lcd.print(fut_hora);
 lcd.print(':');
 if(fut_min >= 0 && fut_min  < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
   lcd.print('0');
 }
 lcd.print(fut_min);
 lcd.print(':');
 if(fut_seg >= 0 && fut_seg  < 10){ //Si es mayor o igual que cero, y menor de 10, escribimos un cero a la izquierda
   lcd.print('0');
 }
 lcd.print(fut_seg);
}

//Imprimir fecha al ajustarla+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void adj_print_date(int fut_dia, int fut_mes, int fut_ano){
 lcd.setCursor(0,3);
 if(fut_dia < 10){   //Si el dia es menor que 10, ponemos 0 a la izquierda
   lcd.print('0');
 }
 lcd.print(fut_dia);
 lcd.print('/');
 if(fut_mes < 10){   //Si el mes es menor que 10 ponemos 0 a la izquierda
   lcd.print('0');
 }
 lcd.print(fut_mes);
 lcd.print('/');
 lcd.print(fut_ano);
}

//Establecer la hora+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void set_hour(){
 DateTime now = RTC.now();
 //Variables para los menus
 boolean set_hora = false;
 boolean set_min = false;
 boolean set_seg = false;
 //Variables de seteo
 fut_hora = now.hour();
 fut_min = now.minute();
 fut_seg = now.second();
 //Menu ajustes de hora
 lcd.clear();
 lcd.setCursor(0,1);
 lcd.print("Establecer Hora:");
 adj_print_hora(fut_hora,fut_min,fut_seg); //Dibujamos la hora
 menu= 0 ;                                 //Inicializamos variables para ENCODER
 lastmenu = 0;
 while (set_hora == false){                //Mientras no pulsemos ajustamos la hora
   if(menu > lastmenu){                    //Si menu es mayor que last menu sumamos valor
     fut_hora++;
     fut_hora=constrain(fut_hora,0,23);    //Limite de variable 0-23
     lastmenu=menu;
     }else if (menu < lastmenu){             //Si menu es menor que last menu restamos valor
       fut_hora--;
       fut_hora=constrain(fut_hora,0,23);    //Limite de variable 0-23
       lastmenu=menu;
     }else if (menu == lastmenu){            //Si nada cambia mantenemos
       fut_hora=fut_hora;
   }
   adj_print_hora(fut_hora,fut_min,fut_seg); //Dibujamos nuevo valor de hora
   encoderSW_bounce.update();                //Consultamos si hemos pulsado
   if (encoderSW_bounce.fallingEdge()){      //Si pulsamos el boton salimos de ajustar hora y pasamos a minutos
     set_hora = true ;
   }
 }
 menu= 0 ;                                   //Inicializamos variables ENCODER
 lastmenu = 0;
 while (set_min == false){                   //Mientras no pulsemos mantenemos en menu minutos
   if(menu > lastmenu){                      //Si menu es mayor que lastmenu sumamos valor
     fut_min++;
     fut_min=constrain(fut_min,0,59);        //Limite variable 0-59
     lastmenu=menu;
     }else if (menu < lastmenu){             //Si menu es menor que lastmenu restamos valor
       fut_min--;
       fut_min=constrain(fut_min,0,59);      //Limite variable 0-59
       lastmenu=menu;                        
     }else if (menu == lastmenu){            //Si nada cambia mantenemos
       fut_min=fut_min;
   }
   adj_print_hora(fut_hora,fut_min,fut_seg); //Dibujamos nuevo valor de minutos
   encoderSW_bounce.update();                //Consultamos si hemos pulsado
   if (encoderSW_bounce.fallingEdge()){      //Si pulsamos el boton salimos de ajustar minutos y pasamos a segundos
     set_min = true ;
   }
 }
 menu= 0 ;                                   //Inicializamos variables ENCODER
 lastmenu = 0;
 while (set_seg == false){                   //Mientras no pulsemos mantenemos en menu segundos
   if(menu > lastmenu){                      //Si menu es mayor que lastmenu sumamos valor
     fut_seg++;
     fut_seg=constrain(fut_seg,0,59);        //Limite variable 0-59
     lastmenu=menu;                          
     }else if (menu < lastmenu){             //Si menu es menor que lastmenu restamos valor
       fut_seg--;          
       fut_seg=constrain(fut_seg,0,59);      //Limite variable 0-59
       lastmenu=menu;
     }else if (menu == lastmenu){            //Si nada cambia mantenemos
       fut_seg=fut_seg;
   }
   adj_print_hora(fut_hora,fut_min,fut_seg); //Dibujamos nuevo valor de segundos
   encoderSW_bounce.update();                //Consultamos si hemos pulsado
   if (encoderSW_bounce.fallingEdge()){      //Si pulsamos el boton salimos de ajustar segundos
     set_seg = true ;
   }
 }
 RTC.adjust(DateTime(now.year(),now.month(), now.day(), fut_hora, fut_min, fut_seg));  //Introducimos la hora en el DS1307
}

//Funcion Ajustar Fecha+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void set_date(){
 DateTime now = RTC.now();
 //Variables para los menus
 boolean set_ano = false;
 boolean set_mes = false;
 boolean set_dia = false;
 //Variables de seteo
 fut_ano = now.year();
 fut_mes = now.month();
 fut_dia = now.day();
 //Menu ajustes de hora
 lcd.clear();
 lcd.setCursor(0,1);
 lcd.print("Establecer Fecha:");
 adj_print_date(fut_dia,fut_mes,fut_ano);    //Dibujamos la fecha
 menu= 0 ;                                   //Inicializamos variables para ENCODER
 lastmenu = 0;
 while (set_dia == false){                   //Mientras no pulsemos mantenemos en menu ajustar dia
   if(menu > lastmenu){                      //Si menu es mayor que lastmenu sumamos valor
       fut_dia++;
       fut_dia=constrain(fut_dia,1,31);        //Limite variable 1-31
       lastmenu=menu;
     }else if (menu < lastmenu){               //Si menu es menor que lastmenu restamos valor
       fut_dia--;
       fut_dia=constrain(fut_dia,1,31);        //Limite variable 1-31
       lastmenu=menu;
     }else if (menu == lastmenu){              //Si nada cambia mantenemos
       fut_dia=fut_dia;
   }
   adj_print_date(fut_dia,fut_mes,fut_ano);  //Dibujamos nuevo valor de dia
   encoderSW_bounce.update();                //Consultamos si hemos pulsado
   if (encoderSW_bounce.fallingEdge()){      //Si pulsamos pasamos a ajustar los meses
     set_dia = true;
   }
 }
 menu= 0 ;                                   //Inicializamos variables para encoder
 lastmenu = 0;        
 while (set_mes == false){                   //Mientras no pulsemos mantenemos ajustando mes
   if(menu > lastmenu){                      //Si menu es mayor que lastmenu sumamos valor
     fut_mes++;
     fut_mes=constrain(fut_mes,1,12);        //Limite variable 1-12
     lastmenu=menu;            
     }else if (menu < lastmenu){               //Si menu es menor que lastmenu restamos valor
       fut_mes--;
       fut_mes=constrain(fut_mes,1,12);        //Limite variable 1-12
       lastmenu=menu;
     }else if (menu == lastmenu){              //Si nada cambia mantenemos
       fut_mes=fut_mes;
   }
   adj_print_date(fut_dia,fut_mes,fut_ano);  //Imprimos nuevo valor de mes
   encoderSW_bounce.update();                //Consultamos si hemos pulsado
   if (encoderSW_bounce.fallingEdge()){      //Si pulsamos pasamos a ajustar el año
     set_mes = true ;
   }
 }
 menu= 0 ;                                   //Incializamos variables para encoder
 lastmenu = 0;                      
 while (set_ano == false){                   //Mientras no pulsemos mantenemos ajustando año
   if(menu > lastmenu){                      //Si menu es mayor que lastmenu sumamos valor
     fut_ano++;
     fut_ano=constrain(fut_ano,2000,2099);   //Limitamos variable 2000-2099
     lastmenu=menu;                                
   }else if (menu < lastmenu){               //Si menu es menor que lastmenu restamos valor
     fut_ano--;                            
     fut_ano=constrain(fut_ano,2000,2099);   //Limitamos variable 2000-2099
     lastmenu=menu;              
   }else if (menu == lastmenu){              //Si nada cambia mantenemos
     fut_ano=fut_ano;
   }
   adj_print_date(fut_dia,fut_mes,fut_ano);  //Imprimimos nuevo valor de año
   encoderSW_bounce.update();                //Consultamos si hemos pulsado
   if (encoderSW_bounce.fallingEdge()){      //Si hemos pulsado salirmos de ajustar año
     set_ano = true;
   }
 }
 RTC.adjust(DateTime(fut_ano, fut_mes, fut_dia, now.hour(), now.minute(), now.second()));  //Introducimos fecha en DS1307
}
//Funcion Guardar Alarma (EEPROM)+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void save_alarma(int fut_hora_alarma,int fut_min_alarma,int fut_seg_alarma, int alarma_on){
 //Leemos los valores guardados
 int savehora=EEPROM.read(1);
 int savemin=EEPROM.read(2);
 int saveseg=EEPROM.read(3);
 int saveseton=EEPROM.read(4);
 if (savehora!=fut_hora_alarma)  //Si las horas guardadas no coinciden con las nuevas volvemos a guardar
 {
   EEPROM.write(1,fut_hora_alarma); //Guardamos
 }
 if (savemin!=fut_min_alarma)  //Si los minutos guardados no coinciden con los nuevos volvemos a guardar
 {
   EEPROM.write(2,fut_min_alarma); //Guardamos
 }
 if (saveseg!=fut_seg_alarma)  //Si los segundos guardados no coinciden con los nuevos volvemos a guardar
 {
   EEPROM.write(3,fut_seg_alarma); //Guardamos
 }
 if (saveseton!=alarma_on)     //SI cambia el estado de la alarma guardamos
 {
   EEPROM.write(4,alarma_on);  //Guardamos
 }
}
//Funcion Setear Alarma+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void set_alarma(){
 //Variables para los menus
 boolean set_hora_alarma = false;
 boolean set_min_alarma = false;
 boolean set_seg_alarma = false;
 boolean set_alarma_on = false;
 //Variables de seteo
 //Menu ajustes de hora
 lcd.clear();
 lcd.setCursor(0,1);
 lcd.print("Establecer Alarma:");
 adj_print_hora(fut_hora_alarma,fut_min_alarma,fut_seg_alarma);  //Dibujamos los valores que tengamos guardados
 if (alarma_on == 1){      //Dibujamos el estado actual de la alarma, ACTIVADA
   lcd.setCursor(15,3);
   lcd.print("ON ");      
   }else{                  //DESACTIVADA
     lcd.setCursor(15,3);
     lcd.print("OFF");
 }
 menu= 0 ;                             //Inicializamos variables ENCODER
 lastmenu = 0;
 while (set_hora_alarma == false){     //Mientras no pulsemos mantenemos en ajustar hora
   if(menu > lastmenu){                //Si menu es mayor que lastmenu sumamos valor a la variable
     fut_hora_alarma++;                                
     fut_hora_alarma=constrain(fut_hora_alarma,0,23);  //Limite variable 0-23
     lastmenu=menu;
   }else if (menu < lastmenu){         //Si menu es menor que lastmenu restamos valor a la variable
     fut_hora_alarma--;                                
     fut_hora_alarma=constrain(fut_hora_alarma,0,23);  //Limite variable 0-23
     lastmenu=menu;
   }else if (menu == lastmenu){        //Si nada cambia mantenemos
     fut_hora_alarma=fut_hora_alarma;                                
   }
   adj_print_hora(fut_hora_alarma,fut_min_alarma,fut_seg_alarma);  //Dibujamos el nuevo valor de la hora
   encoderSW_bounce.update();                                      //Consultamos si hemos pulsado
   if (encoderSW_bounce.fallingEdge()){                            //Si hemos pulsado pasamos a menu ajuste minutos
     set_hora_alarma = true ;
   }
 }
 menu= 0 ;                             //Inicializamos variables ENCODER
 lastmenu = 0;
 while (set_min_alarma == false){      //Mientras no pulsemos mantenemos en ajustar hora
   if(menu > lastmenu){                //Si menu es mayor que lastmenu sumamos valor
     fut_min_alarma++;  
     fut_min_alarma=constrain(fut_min_alarma,0,59);  //Limite varianle 0-59
     lastmenu=menu;
     }else if (menu < lastmenu){         //Si menu es menor que lastmenu restamos valor
       fut_min_alarma--;
       fut_min_alarma=constrain(fut_min_alarma,0,59);  //Limite variable 0-59
       lastmenu=menu;
     }else if (menu == lastmenu){        //Si nada cambia mantenemos
       fut_min_alarma=fut_min_alarma;
   }
   adj_print_hora(fut_hora_alarma,fut_min_alarma,fut_seg_alarma);  //Dibujamos nuevo valor de minutos
   encoderSW_bounce.update();                                      //Consultamos si hemos pulsado
   if (encoderSW_bounce.fallingEdge()){                            //Si hemos pulsado pasamos a menu ajuste segundos
     set_min_alarma = true ;
   }
 }
 menu= 0 ;                             //Inicializamos variables ENCODER
 lastmenu = 0;
 while (set_seg_alarma == false){      //Mientras no pulsemos mantenemos en ajustar segundos
   if(menu > lastmenu){                //Si menu es mayor que lastmenu sumamos valor
     fut_seg_alarma++;
     fut_seg_alarma=constrain(fut_seg_alarma,0,59);  //Limite variable 0-59
     lastmenu=menu;
     }else if (menu < lastmenu){        //Si menu es menor que lastmenu restamos valor
       fut_seg_alarma--;
       fut_seg_alarma=constrain(fut_seg_alarma,0,59);  //Limite variable 0-59
       lastmenu=menu;
     }else if (menu == lastmenu){       //Si nada cambia mantenemos
       fut_seg_alarma=fut_seg_alarma;
   }
   adj_print_hora(fut_hora_alarma,fut_min_alarma,fut_seg_alarma);  //Dibujamos nuevo valor de segundos
   encoderSW_bounce.update();                                      //COnsultamos si hemos pulsado
   if (encoderSW_bounce.fallingEdge()){                            //Si hemos pulsado, pasamos a menu activar/descativar alarma
     set_seg_alarma = true ;
   }
 }
 menu= 0 ;                              //Inicializamos variables ENCODER
 lastmenu = 0;
 while ( set_alarma_on == false){      //Mientras no pulsemos mantenemos en el menu de activacion
 if(menu > lastmenu){                  //Si menu mayor que lastmenu sumamos valor
     alarma_on++;
     alarma_on=constrain(alarma_on,0,1); //Limite 0-1
     lastmenu=menu;
     }else if (menu < lastmenu){         //Si menu es menor que lastmenu restamos valor
       alarma_on--;
       alarma_on=constrain(alarma_on,0,1); //Limite 0-1
       lastmenu=menu;
     }else if (menu == lastmenu){        //Si nada cambia mantenemos
       alarma_on=alarma_on;
   }
 //Si alarma_ON es 1 dibujamos ON, de lo contrario dibujamos OFF
 if (alarma_on == 1){
   lcd.setCursor(15,3);
   lcd.print("ON ");
   }else{
     lcd.setCursor(15,3);
     lcd.print("OFF");
   }
   encoderSW_bounce.update();
   if (encoderSW_bounce.fallingEdge()){
     set_alarma_on = true ;
   }
 }
 save_alarma(fut_hora_alarma,fut_min_alarma,fut_seg_alarma,alarma_on); //Llamamos a la funcion para guardar en la EEPROM
}

//Borrar cursores++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Cada vez que cambia el cursor de posicion en el menu de opciones, limpiamos el anterior
void delete_cursor(int posicion){
 if (posicion < 3){
   lcd.setCursor(0,posicion);
   lcd.print(" ");
 }else{
   lcd.setCursor(0,posicion-4);
   lcd.print(" ");
 }
}
//Dibujar margen menu++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Cada vez que cambiamos de menu, volvemos a dibujar la linea de margen superior
void print_margen(){
 lcd.setCursor(0,0);
 for (int x = 0; x<=19; x++){
   lcd.write(4);
 }
}

//Funcion para alarma++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void fun_alarma(){
 DateTime now = RTC.now();
 //Si coinciden horas minutos y segundos, a su vez que alarma_on esta TRUE, activamos la alarma
 if (fut_hora_alarma == now.hour() && fut_min_alarma == now.minute() && fut_seg_alarma == now.second() && alarma_on){  
   ok_alarma = true;   //Alarma encendida
   temp=0;
 }
 //Rutina para generar el sonido sin delay(), cuatro pitidos cortos, un espacio de 300ms y repetimos
 if (ok_alarma == true){
   if (millis() < temp && sonido){
     analogWrite(buzz,vol);
   }else if (millis() > temp){
     digitalWrite(buzz,LOW);
     temp=millis()+90;
     sonido=!sonido;
     i++;
     if (i>8){
       temp=millis()+300;
       sonido=!sonido;
       i=0;
     }
   }
 }
 pulsador_bounce.update();             //Comprobamos si hemos pulsado el boton
 if (pulsador_bounce.risingEdge()){    //Si hemos pulsado paramos la alarma
   ok_alarma = false;                
   digitalWrite(buzz,LOW);              
 }
}
[/spoiler]
Bien, todo funciona correctamente, a falta de probar con mas rigurosidad todo.

Estoy teniendo problemas a la hora de ejecutar la funcion alarma, ya que empleo la funcion millis(), para hacer el sonido, que son cuatro pitidos de 80ms cada uno, en repeticion y separacion de unos 250ms, el problema esta que al no querer molestar a las demas funciones con el funcionamiento de la alarma, no funciona correctamente, pasan mas de 80ms en la ejecucion de muestreo por pantalla de la hora al parecer y no suena, el codigo no se ejecuta como debe..., soluciones que me planteo para esto, no dejar todo en manos del NANO, y recurrir a un ATiny o un 12F de Microchip, para el volumen, tono y melodia de la alarma, mandando del NANO unicamente una señal de activacion.

Otra cosa que me planteo es reducir el tiempo de ejecucion de imprimir la hora, no actualizando siempre la fecha, ya que solo cambia una vez al dia, lo que ahorraria tiempo de ejecucion, pero no estoy del todo seguro que no siga teniendo problemas con el tiempo y la funcion de sonar la alarma la verdad...., es un tema que tengo que revisar a fondo...

Por lo demas la alarma es totalmente funcional, y desactivable con un pulsador, por ahora esta solo sonaria si nos situamos en el menu RELOJ, pero en un futuro sonara independiente en el menu que nos situemos, por eso me planteo el usan un micro pequeño para que realice la funcion de la alarma. Pense en basar la misma en NE555 pero me parece bastante arcaico....

Cosas pendientes, poder seleccionar el volumen de la alarma, seguramente quite la libreria BOUNCE, y ponga antirebote por HW para aligerar el codigo.

Poder seleccionar un rango de horas para el cual se apague la retroiluminacion, o estando en el menu reloj al pulsar el boton del encoder apagar la misma...por ejemplo.

Y con esto creo que tendria todo lo que es el bloque de reloj operativo para poder pasar a otros menus.

Se me queda algo? jajajajaja

Podrias indicarnos como configuraste el PIC12F508 para que haga eso?

lo tengo comprado y ni idea como cargaste el programa al PIC
  Responder
Hola, me parece un proyecto explendido, pero el enlace al código de la primera página no funciona.

Podrías subirlo por ejemplo a GitHub?

Gracias y enhorabuena.
  Responder


Posibles temas similares…
Tema Autor Respuestas Vistas Último mensaje
  Estación meteorológica v2 - giltesa giltesa 69 18,880 25-01-2024, 08:31 PM
Último mensaje: sermosderendert