El RTC DS3231 es uno de los más populares por su precisión, compensada con la temperatura, y los módulos que lo incluyen son de los más utilizados con Arduino por su precio y su sencillez de uso, entre otras cosas, por comunicarse por medio del bus I2C.
El año pasado publiqué una librería para gestionar el DS3231 por I2C desde Arduino, más para describir su funcionamiento que para explotarla, que tenía una gestión básica de la fecha y la hora. Hace unos meses, y a petición popular, modifiqué la gestión de la fecha y la hora del DS3231 separándola de la gestión genérica de Arduino de la fecha y la hora.
Cuando el reloj en tiempo real DS3231 se utiliza para ubicar en el tiempo los datos monitorizados, por ejemplo, almacenándolos en un servicio en la nube para Internet de las cosas, la operación de ajuste de la hora (sincronización) se suele hacer de manera más o menos automática con ayuda del servidor. Para ajustar de forma manual RTC DS3231 se pueden utilizar también recursos locales, estableciendo la fecha y la hora como si fuera un reloj convencional, por ejemplo con pulsadores, un encoder…
En este artículo propongo algunos recursos para poner en hora un reloj con Arduino, en concreto, cómo modificar la fecha y la hora actuales, que se pueden estar mostrando en una pantalla, incrementando o decrementando un elemento de la fecha o la hora previamente seleccionado: segundo, minuto, hora, día… El resultado es una versión ampliada de la librería para gestionar la fecha y la hora con Arduino con un método para aumentar y otro para disminuir un valor de la fecha y la hora, que puede utilizarse para gestionar el tiempo con cualquier reloj e incluso con ninguno, solamente con Arduino.
Antes de explicar cómo hacerlo, es interesante recordar que hace falta un pequeño algoritmo para adelantar o retrasar un elemento de la fecha y la hora, no basta con sumar o restar una unidad y acumular o detraer del siguiente nivel porque existen unos límites muy diferentes entre ellos y porque los límites de unos pueden depender de los valores de otros: el límite de los días depende del valor del mes y del año.
El algoritmo para incrementar la fecha y la hora consistiría en sumar una unidad a cierto elemento solamente si no ha alcanzado el límite superior, por ejemplo, añadir una hora a la actual si no son las 23 (el último valor posible de la hora). Si se ha alcanzado el límite superior hay que pasar al inferior (la hora cero, en el ejemplo anterior) e incrementar una unidad al siguiente nivel (el día, en el ejemplo) siempre no haya alcanzado su límite superior, en cuyo caso se procedería de la misma forma hasta recorrer todos los niveles desde el que se desea cambiar.
El método para retrasar el valor del objeto tiempo sería el contrario, pero se plantea además el inconveniente de que el límite superior del día (del número del día del mes) depende del valor del mes y del año (incluyendo el siglo) por lo que habría que aplazar ese cambio hasta conocer los valores definitivos de los niveles superiores.
Por último, hay que recordar que en el momento de establecer la hora se cambian todos los valores, por ejemplo los segundos aunque se cambien los minutos, así que habrá que confirmar el cambio (pulsar un hipotético botón «grabar», por ejemplo) en el instante adecuado, de forma sincronizada.
En el siguiente código se pueden ver las nuevas funciones para incrementar o decrementar los elementos del objeto tiempo (fecha y hora). Para utilizarlas, se puede pasar como argumento un objeto tiempo y el número de elemento que se adelanta o se retrasa (que puede hacerse usando las constantes INDICE_SEGUNDO
, INDICE_MINUTO
, INDICE_HORA
…) o simplemente el número de elemento, de forma que utilizará el valor de la fecha que almacena el objeto. Más adelante, también se incluyen algunos ejemplos de cómo usar estos nuevos métodos.
Con estos nuevos métodos ya no tiene sentido mantener el código de los antiguos adelantar_hora() y retrasar_hora(), que se pueden sustituir (manteniendo la compatibilidad con la versión anterior) por wrappers a adelantar_tiempo() y a retrasar_tiempo(), pasando como argumento INDICE_HORA
Para usar un bucle que recorra los elementos de la fecha y la hora, se define una matriz con los límites superiores e inferiores de cada elemento y un par de métodos que se invocarán al definir la fecha y la hora. El primer índice corresponde con el número de elemento (siguiendo la nomenclatura de la versión anterior) y el segundo hace referencia al límite inferior (índice cero) y al superior (índice uno).
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
void tiempo::establecer_limites_hora() { limite_componente[INDICE_SEGUNDO][0]=0; limite_componente[INDICE_SEGUNDO][1]=59; limite_componente[INDICE_MINUTO][0]=0; limite_componente[INDICE_MINUTO][1]=59; limite_componente[INDICE_HORA][0]=0; limite_componente[INDICE_HORA][1]=23; } void tiempo::establecer_limites_fecha() { limite_componente[INDICE_DIA][0]=1; limite_componente[INDICE_DIA][1]=dias_mes(); // El límite superior depende del mes y del año limite_componente[INDICE_MES][0]=1; limite_componente[INDICE_MES][1]=12; limite_componente[INDICE_ANO][0]=0; limite_componente[INDICE_ANO][1]=99; limite_componente[INDICE_SIGLO][0]=0; limite_componente[INDICE_SIGLO][1]=99; } void tiempo::adelantar_tiempo(char *fecha, char elemento) // Adelantar una unidad de tiempo (correspondiente al nivel «elemento») al valor actual de la fecha { while(elemento<=INDICE_SIGLO) { if(fecha[elemento]<limite_componente[elemento][1]) // Si el elemento que se cambia es menor que el margen superior (se le puede añadir sin superarlo)… { fecha[elemento]++; // …incrementar el elemento if(elemento==INDICE_MES) // Si se ha modificado el mes hay que cambiar el límite superior del elemento día (el nuevo mes puede tener más o menos días) { limite_componente[INDICE_DIA][1]=dias_mes(); // El límite superior depende del mes y del año } elemento=INDICE_SIGLO+1; // Ya se ha adelantado el tiempo, no seguir iterando } else // Si el elemento ya está en el nivel superior hay que pasar al inferior e incrementar el elemento del siguiente nivel { fecha[elemento]=limite_componente[elemento][0]; // Establecer el elemento al nivel inferior elemento++; // Modificar el elemento del nivel superior (si existe), es decir, seguir iterando los elementos de la fecha } } } void tiempo::retrasar_tiempo(char *fecha, char elemento) // Restar una unidad de tiempo (correspondiente al nivel «elemento») al valor actual de la fecha { bool ajustar_dia=false; // En principio no hay que establecer el día al último del mes while(elemento<=INDICE_SIGLO) // Iterar desde el nivel de tiempo actual (hora, día, mes…) hasta el último (siglo) si es necesario { if(fecha[elemento]==limite_componente[elemento][0]) // Si el elemento que se cambia está en su límite inferior (por ejemplo, día 1) hay que pasar al último (por ejemplo, día 30) del del siguiente nivel (mes, en el ejemplo) y retrasar también el nivel siguiente { if(elemento==INDICE_DIA) // Si el elemento que ha llegado al límite inferior es el día… { ajustar_dia=true; // …será necesario ajustar el día pero todavía no se sabe al último de qué mes } else // Si el elemento que ha llegado al límite inferior NO es el día… { fecha[elemento]=limite_componente[elemento][1]; // establecer el nivel actual al límite superior y… } elemento++; // …modificar el elemento del nivel superior (si existe), es decir, seguir iterando los elementos de la fecha } else // Si no se ha alcanzado el límite inferior del elemento solamente hay que disminuirlo… { fecha[elemento]--; // …restando uno al valor actual if(elemento==INDICE_MES) // Si se ha modificado el mes hay que cambiar el límite superior del elemento día (el nuevo mes puede tener más o menos días) { limite_componente[INDICE_DIA][1]=dias_mes(); // El límite superior depende del mes y del año } elemento=INDICE_SIGLO+1; // Ya se ha retrasado el tiempo, no seguir iterando } } if(ajustar_dia) // Si se había aplazado el establecimiento del día al último del mes anterior… { fecha[INDICE_DIA]=dias_mes(); // …asignar el último día del mes } } void tiempo::adelantar_tiempo(char elemento) // Adelantar una unidad de tiempo (correspondiente al nivel «elemento») al valor actual de la fecha { adelantar_tiempo(valor_tiempo,elemento); } void tiempo::retrasar_tiempo(char elemento) // Restar una unidad de tiempo (correspondiente al nivel «elemento») al valor actual de la fecha { retrasar_tiempo(valor_tiempo,elemento); } void tiempo::adelantar_hora(char *fecha) { adelantar_tiempo(fecha,INDICE_HORA); } void tiempo::retrasar_hora(char *fecha) { retrasar_tiempo(fecha,INDICE_HORA); } |
Para configurar los límites de los elementos de la fecha y la hora habrá que añadir una llamada a los métodos correspondientes en las funciones que sirven para establecer la hora. Como todos son wrappers de establecer_hora()
o de establecer_fecha_siglo()
en sus diferentes formatos, solo hará falta cambiar estos dos métodos como en las líneas resaltadas del siguiente código.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
tiempo::tiempo(char *fecha_DS3231) // Constructor desde un puntero al valor de los registros del DS3231 { cargar_DS3231(fecha_DS3231); } tiempo::~tiempo() // Destructor { } void tiempo::establecer_hora(char segundo, char minuto, char hora) { valor_tiempo[INDICE_SEGUNDO]=segundo; valor_tiempo[INDICE_MINUTO]=minuto; valor_tiempo[INDICE_HORA]=hora; asignar_hora_intervalo_estacional(); en_horario_estacional=horario_estacional(valor_tiempo); establecer_limites_hora(); } void tiempo::establecer_fecha(char dia, char mes, char ano) { establecer_fecha_siglo(dia,mes,ano,SIGLO_XXI); } void tiempo::establecer_fecha_siglo(char dia, char mes, char ano, char siglo) { valor_tiempo[INDICE_DIA]=dia; valor_tiempo[INDICE_MES]=mes; valor_tiempo[INDICE_ANO]=ano; valor_tiempo[INDICE_SIGLO]=siglo; numero_dia_semana=dia_semana(dia,mes,ano,siglo); asignar_fecha_intervalo_estacional(); en_horario_estacional=horario_estacional(valor_tiempo); establecer_limites_fecha(); } |
También será necesario añadir a la cabecera los nuevos métodos. En las líneas resaltadas del siguiente código se pueden ver los cambios a la cabecera de la versión anterior.
75 76 77 78 79 80 81 82 |
void adelantar_hora(char *fecha); // Cambia el vector fecha para adelantar una hora void retrasar_hora(char *fecha); // Cambia el vector fecha para retrasar una hora void adelantar_tiempo(char *fecha, char elemento); // Cambia el vector fecha para adelantar cierto componente void retrasar_tiempo(char *fecha, char elemento); // Cambia el vector fecha para retrasar cierto componente void adelantar_tiempo(char elemento); // Cambia el vector fecha para adelantar cierto componente void retrasar_tiempo(char elemento); // Cambia el vector fecha para retrasar cierto componente void establecer_limites_hora(); // Establecer los valores menor y mayor que puede tomar cada elemento que forma la hora void establecer_limites_fecha(); // Establecer los valores menor y mayor que puede tomar cada elemento que forma la fecha |
Desde este enlace puedes descargar la librería para gestionar la fecha y la hora con Arduino completa para no tener que modificar la versión anterior.
El uso de las nuevas funciones es muy sencillo: para incrementar un elemento se llama al método adelantar_tiempo() y se incluye como argumento el índice del elemento que se desea adelantar. Por ejemplo, para adelantar la hora almacenada por una variable reloj
que apuntara a un objeto tiempo
declarado como tiempo reloj;
, se escribiría reloj.adelantar_tiempo(INDICE_HORA);
. De manera similar, si lo que se quiere es retrasar los minutos de la misma variable reloj
de tipo tiempo
, se escribiría reloj.retrasar_tiempo(INDICE_MINUTO);
.
Para poder hacer pruebas solamente con el software, sin tener que montar el hardware que ajusta el valor de los elementos de la fecha y la hora e incluso sin tener que usar un RTC DS3231, he utilizado esta pequeña función que asigna un valor inicial a la fecha y a la hora leyéndolo desde el puerto serie con el formato {ssmmhhDDMMAASS} en el que ss representa los segundos, mm los minutos, hh las horas, DD los días del mes, MM el número de mes, AA los dos últimos dígitos del año y SS los dos primeros a los que, por simplificar, se les llama siglo aunque sea una unidad menos que el valor real del siglo.
En la siguiente captura de pantalla se muestra como ejemplo la entrada {10152005061620} que produce la fecha 5 de junio de 2016 y la hora 20:15:10, conforme al formato que explicaba antes.
La función de prueba primero adelanta todos los elementos de la fecha y la hora y va mostrando los valores que toman, y luego los retrasa y nuevamente va mostrando los resultados de las operaciones como puede verse en la captura de pantalla de la imagen de abajo.
El siguiente es código el de ejemplo que carga una fecha desde el puerto serie (se puede utilizar desde la consola de Arduino como en las capturas de arriba y la modifica con los nuevos métodos en las líneas resaltadas. Para hacerlo más legible he usado una función llamada mostrar_fecha_hora()
, que presenta la fecha y que he utilizado para mostrarla, primero tal como se ha cargado (línea 36) y a cada adelanto (línea 41) y retraso (línea 47) después.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
#define TOTAL_ELEMENTOS_FECHA 7 // Número de elementos de la fecha: segundo, minuto, hora, día, mes, año y siglo = 7 #include "tiempo.h" #include "leer_fecha_serie.h" tiempo fecha_hora; // Objeto que contiene la fecha y la hora bool nueva_fecha=false; // ¿Se ha leído una nueva fecha y hora desde el puerto serie? char buffer_serie; // letra leída desde el puerto serie char buffer_fecha[TOTAL_ELEMENTOS_FECHA]; // ={0,0,0,0,0,0,0}; // {segundo,minuto,hora,día,mes,año,siglo}; String nombre_elemento[TOTAL_ELEMENTOS_FECHA]={"segundo","minuto","hora","día","mes","año","siglo"}; char numero_elemento; // índice para los bucles void setup() { Serial.begin(9600); } void loop() { if(Serial.available()>0) // Si hay datos disponibles en el puerto serie cargarlos y tratar de formar una fecha con ellos { buffer_serie=Serial.read(); nueva_fecha=leer_fecha_serie(buffer_serie,buffer_fecha); } if(nueva_fecha) // Si se ha cargado una nueva fecha por el puerto serie { fecha_hora.establecer_fecha_hora_siglo // Asignar la fecha cargada al objeto ( buffer_fecha[INDICE_SEGUNDO], buffer_fecha[INDICE_MINUTO], buffer_fecha[INDICE_HORA], buffer_fecha[INDICE_DIA], buffer_fecha[INDICE_MES], buffer_fecha[INDICE_ANO], buffer_fecha[INDICE_SIGLO] ); mostrar_fecha_hora(fecha_hora,"cargada",-1); // Mostrar la fecha cargada (-1 es para indicar que no se ha transformado ningún elemento) Serial.println(); for(numero_elemento=0;numero_elemento<TOTAL_ELEMENTOS_FECHA;numero_elemento++) { fecha_hora.adelantar_tiempo(numero_elemento); // Adelantar cada elemento… mostrar_fecha_hora(fecha_hora,"adelantada",numero_elemento); // …y mostrarlo } Serial.println(); for(numero_elemento=0;numero_elemento<TOTAL_ELEMENTOS_FECHA;numero_elemento++) { fecha_hora.retrasar_tiempo(numero_elemento); // Retrasar cada elemento… mostrar_fecha_hora(fecha_hora,"retrasada",numero_elemento); // …y mostrarlo } Serial.println("\n"); nueva_fecha=false; // Esperar otra fecha para probar } |
El código de la función, programado ad hoc, está incluido al final del programa de prueba, no se carga desde otro documento. La única característica reseñable es que utiliza un número de elemento especial (negativo) para no mostrar el elemento que se transforma y así poder utilizarla tanto con la fecha y hora recién cargada como con la fecha y hora modificada. Por lo demás solo se encarga de presentar en la consola serie con Serial.print()
o Serial.println()
los distintos resultados.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
void mostrar_fecha_hora(tiempo fecha_hora, String operacion, char numero_elemento) { Serial.print("Fecha/hora "); Serial.print(operacion); if(numero_elemento>-1) { Serial.print(" en un"); if(numero_elemento==INDICE_HORA) { Serial.print("a"); } Serial.print(" "); Serial.print(nombre_elemento[numero_elemento]); } Serial.print(": "); Serial.print(fecha_hora.fecha_humana()); Serial.print(" "); Serial.println(fecha_hora.hora_humana()); } |
La función con la que se carga la fecha desde el puerto serie, que sí puede utilizarse para otras operaciones aunque está muy vinculada a su formato, la he separado en un documento que se carga desde el programa de ejemplo igual que en la versión anterior de la librería de gestión de fecha y hora con Arduino. El código de esta función auxiliar es diferente al de la original, que servía para poner en hora el DS3231, ya que en este caso sirve para establecer los valores del objeto tiempo
de la nueva librería.
1 2 3 4 5 6 7 |
// leer_fecha_serie.h #define INICIO_DATOS '{' // caracter arbitrario para indicar el inicio de la fecha y la hora enviada por el puerto serie #define FIN_DATOS '}' // caracter arbitrario para indicar el final de la fecha y la hora enviada por el puerto serie #define LONGITUD_FECHA 15 // Último caracter de la fecha, incluyendo los de inicio y fin, en el formato {ssmmhhDDMMAASS} Cada elemento está formado por dos dígitos (que pueden ser cero) y ss representa los segundos, mm los minutos, hh las horas (en formato de 24 al día), DD el día del mes, AA los dos últimos dígitos del año y SS los dos primeros dígitos del año a los que se llama siglo por simplificar aunque es una unidad menos que el siglo bool leer_fecha_serie(char buffer_serie,char *buffer_fecha); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
// leer_fecha_serie.cpp #include "leer_fecha_serie.h" bool leer_fecha_serie(char buffer_serie,char *buffer_fecha) // buffer_fecha necesita 7 bytes (segundo, minuto, hora, día, mes, año y siglo) { static unsigned char puntero_serie=0; bool nueva_fecha=false; if(puntero_serie>0&&puntero_serie<LONGITUD_FECHA&&buffer_serie>='0'&&buffer_serie<='9') { buffer_fecha[(puntero_serie-1)/2]*=(puntero_serie-1)%2; // Si es el primer dígito, asegurarse de que empieza valiendo cero buffer_fecha[(puntero_serie-1)/2]+=(buffer_serie-'0')*(puntero_serie%2?10:1); // Cargar el dígito con su peso (multiplicando por 10 si es el primero de los dos) puntero_serie++; // Preparar la lectura del siguiente dígito } else { if(puntero_serie==LONGITUD_FECHA&&buffer_serie==FIN_DATOS) // Si se ha leído toda la fecha { puntero_serie=0; // Preparar la lectura de una nueva fecha/hora completa nueva_fecha=true; // Avisar de que la lectura ha sido correcta } else { if(puntero_serie==0&&buffer_serie==INICIO_DATOS) // Si se lee el código de inicio del formato de la fecha { puntero_serie++; // Preparar la lectura del primer dígito } else // El formato está mal. Volver a empezar. { puntero_serie=0; } } } return nueva_fecha; // Avisar del estado de la lectura de la fecha/hora } |
Si quieres usarlo para hacer pruebas, puedes descargar el código completo del ejemplo, la función para leer por el puerto serie la fecha y la hora y la nueva versión de la librería para gestionarla. También puedes descargar la librería para gestionar la fecha y la hora con Arduino por separado.
Chorrocntos
Excelente trabajo Víctor,
He probado el codigo y por algún motivo no devuelve nada por el puerto de serie, si uso ejemplos anteriores devuelve fecha y hora sin problemas.
Un saludo
Víctor Ventura
Hola, Chorrocntos.
Siento que no te funcione. Así, sin más datos, no se me ocurre cómo ayudarte.
Supongo que te habrás fijado que este código de prueba devuelve la fecha solamente cuando se introduce un valor por el puerto serie, no está mostrando la fecha cada rato (no hay RTC). Por otra parte, el formato de la fecha que espera que se introduzca es {ssmmhhDDMMAASS} es decir, necesita todos los dígitos del año (no solo los últimos) aunque los dos últimos se escriben primero.
Gracias por participar en polaridad.es
Chorrocntos
Ya funciona, realice la siguiente modificación en el void setup:
void setup()
{
Serial.begin(9600);
}
Espero que sirva si alguien más experimenta problemas con la comunicación del puerto.
Un saludo Víctor
Víctor Ventura
🙂
Jorge Vallejos
Hola Víctor, si quiero ajustar la fecha y la hora por medio de pulsadores cómo podría hacerlo? Puedes darme una idea?
Víctor Ventura
Hola, Jorge.
Puedes usar tres pulsadores, uno para ir cambiando de elemento que se comportara de forma circular (del último pase otra vez al primero) y otros dos para aumentar y disminuir.
En el código de ejemplo se explica cómo adelantar y retrasar el valor de un elemento con las funciones
adelantar_tiempo()
yretrasar_tiempo()
(solo hay que pasarles como argumento el número de elemento que se modifica)Con respecto a cómo reaccionar a la pulsación, puedes usar interrupciones (si tienes disponibles, dependerá del resto del código) o a cada ciclo del programa revisar si el pin al que se conecta está a nivel alto o bajo y elegir entonces el elemento o cambiar su valor (dependiendo de qué esté pulsado en ese momento)
Si tienes un display LED de 7 segmentos para marcar la hora (no dices nada de tu montaje ni de tu código, tengo que imaginar) puedes apagar los elementos que NO se estén modificando (muy sencillo) o hacer parpadear el SÍ que se está modificando (más código para encender y apagar cada cierto intervalo)
Espero que eso te ayude. Suerte con tu proyecto.
Jorge Vallejos
Hola Víctor, gracias por responder. Voy a intentar entonces hacerlo de esa forma, para la visualización por el momento voy a utilizar un LCD 16×2. Un cordial saludo
Marco Zañudo
Bro, será posible ajustar la fecha y hora mediante bluetooth?
Madarle la fecha y la hora actual que tiene mi celular, y que arduino lo reciba por el Serial2.
Víctor Ventura
Hola, Marco.
Sí, sería posible, pero tendrás que preparar un programa que funcione en Android (o en el sistema operativo que tenga tu teléfono), que seguramente dispondrá de Bluetooth y otro en Arduino para controlar un módulo Bluetooth que tendrás que añadir.
Un sistema genérico para comunicar Android (por ser el más utilizado) con Arduino parece que puede ser interesante para los lectores del blog. Tomo nota para un próximo artículo.
Gracias por participar en polaridad.es
Miguel
Hola Victor,
llevo unos cuantos días intentando adaptar el ejemplo del código completo que pones, pero que en vez de te tome la lectura que le metes por el puerto serie que la coja del RTC que tengo montado(DS3231) en una placa de pruebas, conectado al arduino por I2C. Tu ejemplo me funciona perfectamente y lo veo tanto en el monitor serial como en un display de 20X4 que tengo montado. Pero como te digo el problema viene cuando intento que me lea la fecha y hora del RTC para despues modificarla con tres pulsadores como explicas más arriba.
Podrías explicarme como se hace esto?
Si utilizo el ejemplo de solo lectura del RTC me funciona perfectamente
y veo la fecha y hora.
No se si me he explicado bien.
Gracias por enseñarnos a los que estamos empezando sobretodo
Víctor Ventura
Hola, Miguel.
Intento explicarlo otra vez, pero lo hago un poco a ciegas porque no sé qué es exactamente lo que te da problemas o no te ha quedado claro.
En primer lugar necesitas establecer el modo de cambio de la hora. Partiendo de que tienes pocas interrupciones libres (que sería la mejor forma de detectar una pulsación) puedes usar una variable booleana que indique este modo y que se establezca con la detección, en el bucle principal, de una pulsación. Como es lógico, además tendrás que resolver por hardware o software el tema de los rebotes de la pulsación en este y los otros casos.
Una vez en el modo de cambio de hora debes poder elegir el dato que se cambia (horas, minutos…) y marcarlo, por ejemplo parpadeando o apagando los otros valores. Puedes utilizar el mismo método, detectar una (otra) pulsación mientras está activo el modo de cambio de hora.
Cuando se ha elegido el parámetro que se cambia (horas, minutos…), otra vez con una pulsación, se aumenta o disminuye. Supongo que aquí viene la parte importante, para aumentar el valor del parámetro se utiliza el método
adelantar_tiempo
pasando como parámetro el índice del elemento que se cambia. Igualmente, conretrasar_tiempo
se puede disminuir el valor.Para terminar, seguramente utilizando el mismo pulsador del modo, se graba en el DS3231 el cambio de la hora, que hasta ahora estaba en memoria. Si utilizas la librería de gestión de fecha y hora para el módulo RTC DS3231 y Arduino puedes usar el método
grabar_registro_DS3231
para hacerlo.Como no conozco muy bien tu perfil (qué experiencia tienes en programación o electrónica) puede que te esté explicando esto a un nivel muy diferente al que necesitas (mucho más alto o mucho más bajo), espero que lo entiendas; por eso es más práctico consultar en el blog cosas concretas. En cualquier caso, espero que esto te ayude un poco.
Gracias por participar en polaridad.es y suerte con tu proyecto.
Miguel
Hola Victor.
mi experiencia en programación es muy muy básica pues estoy empezando ahora mismo.
No podrías poner un ejemplo, leyendo la fecha_hora del RTC y cambiar la hora por ejemplo?
Lo de los pulsadores lo tengo claro.
Gracias
Víctor Ventura
Hola, Miguel.
El código de ejemplo del artículo incluye precisamente el cambio de hora (adelanta y retrasa cada elemento una unidad) y leer la hora desde el DS3231 se explica en otro artículo (el del enlace) y usando la librería propuesta es tan sencillo como invocar el método
cargar_fecha_hora
.Se me ocurre que estás confundiendo la gestión de la fecha y la hora con el DS3231, de la que no trata este post, con las operaciones sobre datos de fecha y hora, que es el objetivo de este artículo ¿Puede ser? Te recomiendo que consultes el otro texto a ver si estoy en lo cierto y en tal caso te sirve de ayuda.
Saludos.
cristian diaz
hola victo.
necesito realizar un proyecto en donde pueda programar hora y fecha mediante botones, y a su vez programar una hora de encendido y apagado para prender un foco, todo esto mediante botones, tambien lo quiero visualizar a travez de la red con un modulo esp8266-12e, espero me puedas ayudar y gracias por tu valiosa ayuda muy buen post.