Autor Tema: Cambio automático horario verano e invierno.  (Leído 1474 veces)

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

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Cambio automático horario verano e invierno.
« en: 04 de Octubre de 2017, 06:18:50 »
Algunos países cambian la hora según Verano o invierno.  En España por ejemplo, El horario de verano empieza a las 02:00 Am del ultimo domingo de Marzo y finaliza a las 03:00 horas del ultimo domingo del mes de octubre.  Eso significa, que el ultimo domingo de octubre a las 03:00 tenemos que restar una hora al reloj, mientras que el ultimo domingo de Marzo a las 02:00 tenemos que sumarla.

  He querido implementar una función que sea capaz de hacer esto con un rtc y la quiero compartir por si a alguien le interesa, aparte de para mejorarla  si alguien ve mejores formas "y las habrá" de hacer determinadas cosas.  El código está comentado. Utilizo un rtc DS1307. Es necesario utilizar el byte del registro día de la semana del rtc y ajustarlo cuando se ajusta la fecha y la hora ya que el rtc no calcula automáticamente el día de la semana (Lunes---Domingo) a partir de la fecha, que también se podría hacer.

 Lo que hago fundamentalmente es grabar una bandera en la eeprom interna (también se podría grabar en una posición de ram de uso libre del rtc) , la bandera la llamo "Sunset", si vale 1 es por que estamos en horario de verano. Si vale cero, es horario invierno.

   Al arrancar el programa se lee esta bandera y se pasa por la función que lo que hará será preguntar primero si estamos en los meses (Noviembre, diciembre, enero o febrero), en tal caso es fácil, si estamos en esos meses y la bandera SUNSET está a 1, tenemos que cambiar la hora. La cambiamos y grabamos la bandera sunset a cero.

  Si Sunset estaba a cero pues no pasará nada.

  La complicación viene en los meses de Octubre y Marzo. Son dos operaciones:

     Si es octubre, primero pregunto si estamos en la ultima semana del mes, de ser así, pregunto si es domingo, de ser así pregunto si son mas de las 03:00 am y de ser así activo horario de invierno, resto la hora, la ajusto en el rtc, pongo SUNSET a cero y lo grabo en eeprom interna.

    Si lo anterior no se cumple, por ejemplo, por que el domingo ya ha pasado, vuelvo a preguntar lo mismo, si es octubre, si estamos en la ultima semana del mes y determino mediante una diferencia y una suma si a lo largo de esa semana ha transcurrido el domingo. De ser así pues lo mismo, activo horario invierno.

   Luego para Marzo se hace exactamente lo mismo, con la diferencia de que hay que preguntar cuando sean las 02:00 para sumarle la hora.

  Un folloncete en verdad.  Ahí os dejo el código..

Código: C
  1. void sunsett() {
  2.        
  3.        
  4.        int i = 0;
  5.        // sunset              (cambio automático horario de verano e invierno)
  6.                            // ( desde ultimo domingo de marzo a ultimo domingo de octubre es horario de verano sunset = 1)
  7.        
  8.        // para determinar si estamos en horario de verano o invierno, inicialmente creamos variable local "localsunset" y la inicializo con el valor de sunset que está grabado en la eeprom interna.
  9.  
  10.        int8 localsunset = sunset;     // cargamos el horario actual.
  11.        
  12.        if ((mes == 1) || (mes == 2) || (mes == 11) || (mes == 12)) localsunset = 0;  // si estamos en algunos de estos meses, marcamos horario de invierno. (localsunset = 0)
  13.        
  14.        if ((mes == 10) && ((dia>=25) && (dia <=31))) {           // si es octubre y además estamos en la ultima semana del mismo mes
  15.            if ((weekday == 6) && (horas >= 3)) localsunset = 0;    // si es domingo y son mas de las 3 de la mañana ponemos horario de invierno.
  16.                                                                   // si no es domingo tenemos que averiguar si ya lo ha sido
  17.            else {
  18.               int8 dif = 31 - dia;                                     // hallamos los dias que restan hasta final de mes.  
  19.               int8 suma = dif + weekday;                         // sumo el valor del dia de la semana a los dias que restan hasta fin de mes
  20.                                                                              // el domingo en weekday sería el 6.
  21.               if (suma <=6) localsunset = 0;                   // si da 6 o menos de 6 es por que ya ha sido domingo, por lo que activamos horario de invierno.
  22.                 }
  23.            
  24.            
  25.            
  26.        }
  27.        
  28.        if ((mes == 3) && ((dia>=25) && (dia <=31))) {                 // si es Marzo y además estamos en la ultima semana del mismo mes
  29.            localsunset = 0;                                                            // en Marzo continuamos en horario de invierno salvo.....
  30.            if ((weekday == 6) && (horas >= 2)) localsunset = 1;    // si es domingo y son mas de las 3 de la mañana ponemos horario de verano.
  31.                                                                                             // si no es domingo tenemos que averiguar si ya lo ha sido
  32.            else {
  33.               int8 dif = 31 - dia;                                                 // hallamos los dias que restan hasta final de mes.  
  34.               int8 suma = dif + weekday;                                 // sumo el valor del dia de la semana a los dias que restan hasta fin de mes
  35.                                                                                       // el domingo en weekday sería el 6.
  36.               if (suma <=6) localsunset = 1;                         // si da 6 o menos de 6 es por que ya ha sido domingo, por lo que activamos horario de verano
  37.                 }
  38.        }
  39.        // activamos y grabamos la bandera sunset que corresponda
  40.            
  41.        posi (40,40);
  42.        printf("TT Ls:%u \r\n          ss:%u \r\n ",localsunset,sunset);
  43.        putc(0);
  44.        delay_ms(500);
  45.        
  46.        
  47.        
  48.            if (sunset != localsunset) {                   // si localsunset no coincide con sunset es por que ha cambiado....
  49.                if (sunset == 1) {                     // si estabamos en horario de verano
  50.                    horas = horas - 1;                   // restamos una hora al reloj
  51.                    setrtc();                           // grabamos en el rtc
  52.                    sunset = 0;                         // indicamos que estamos ahora en horario de invierno.
  53.                    write_eeprom(25,sunset);           // grabamos en la eeprom interna.
  54.                }
  55.        
  56.                else {                                  // si estabamos en horario de invierno
  57.                    horas = horas + 1;                 // sumamos una hora al reloj
  58.                    setrtc();                         // grabamos en el rtc
  59.                    sunset = 1;                      // activamos horario de verano.
  60.                    write_eeprom(25,sunset);           // grabamos en la eeprom interna.
  61.                }
  62.  
  63. }




Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Cambio automático horario verano e invierno.
« Respuesta #1 en: 04 de Octubre de 2017, 11:34:28 »
Y probaste ya algunos de codigos que hay dando vuelta por la red ? Como este:

https://hackaday.com/2012/07/16/automatic-daylight-savings-time-compensation-for-your-clock-projects/

El codigo te detecta el numero de dia para el N domingo, como bien dice la mayor parte del proceso y mas consumidor es detectar los años que son bisiestos.

Asi que lo que deberias, a mi parecer hacer es:
- Tener una tabla con las fechas de inicio - fin de cada zona. Es decir para la entrada de España tendrias el 3er domingo de marzo, 02:00 hs y luego el fin que seria 3er domingo Octubre 03:00hs.
- Utilizar el codigo para detectar el numero de dia.
- Guardar en la EEPROM la fecha establecida, de inicio y fin (Numero de dia,mes,hora).
- Cuando se pida la fecha, se verifica si esta dentro de ese rango de lo que se encuentra en la EEPROM, si esta, se procede a cambiar la hora a mostrar, la hora del RTC no se modifica. Si tenes una estructura con el tiempo, podes agregar ahi el flag de daylight saving time para devolver como resultado de la funcion, junto con la hora/fecha.

Código: C
  1. typedef struct timertc_t {
  2.                 uint8_t year;
  3.                 uint8_t month;
  4.                 uint8_t dayOfWeek;
  5.                 uint8_t day;
  6.                 uint8_t hour;
  7.                 uint8_t minute;
  8.                 uint8_t second;
  9.                 uint8_t daylight;
  10.         } timertc_t;

- El unico momento que deberias cambiar los limites dados por la EEPROM seria cuando alguien modifique la configuracion al estar en otra region, la cual va a ser soportada por la tabla que tengas cargada en el PIC, creo que esta dado por el IANA https://www.iana.org/time-zones

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re:Cambio automático horario verano e invierno.
« Respuesta #2 en: 05 de Octubre de 2017, 03:29:23 »
Creo que lo mejor es no cambiar la hora del rtc. Este se mantiene siempre con la hora solar (UTC) y otra función la transforma en hora local, dependiendo del desfase por región y por horario de verano.

Saludos.

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Cambio automático horario verano e invierno.
« Respuesta #3 en: 05 de Octubre de 2017, 03:47:04 »
Gracias por las respuestas. Entonces, hora Utc en el rtc y ya dependiendo de la zona horaria elegida y el horario de verano, sumamos o quitamos..   

  Pues a usar unas tablas.... 

  Saludos

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re:Cambio automático horario verano e invierno.
« Respuesta #4 en: 05 de Octubre de 2017, 11:11:05 »
Solo una aclaración. La hora solar y UTC son casi iguales, pero no del todo. De ahí los leap seconds que a veces se añaden a la hora UTC.
Si se aprueba una proposición será todavía más difícil, porque la hora UTC se podrá desfasar hasta media hora con la solar. Menos mal que por ahora no está aprobado.

Saludos.


 

anything