El problema del Tiempo

En nuestro reciente artículo sobre el uso de una pantalla LCD con un controlador ARDUINO UNO escribimos “Hola Mundo” y mostramos la cantidad de milisegundos transcurridos desde que se ejecutó nuestro programa.

En este artículo vamos a explorar técnicas para convertir el dato de milisegundos transcurridos en un formato como horas, minutos y segundos transcurridos a fin de poner en práctica y retar nuestras capacidades de abstracción y de programación en general.

Explicando el programa inicial

En general este es un programa muy sencillo. Como todos los programas de ARDUINO este programa tiene dos funciones principales: setup() y loop().

La función setup() es llamada cada vez que el programa inicia, generalmente esto es cada vez que arranca el controlador ARUDINO UNO programado. En esta función generalmente se ubican instrucciones para preparar la ejecución del progrma. Acá vemos cosas como Serial.begin(9600) que inicializa la consola de terminal, o lcd.begin() que permite inicializar la pantalla LCD.

La función loop() es llamada constantemente, se ejecuta y cuando termina es llamada nuevamente por el controlador. En nuestro caso esta función lo único que hace es imprimir en el LCD la cantidad de segundos transcurrida.

Haz clic acá para ver el programa completo
/*
  LiquidCrystal Library - Hola Mundo

Demuestra cómo usar una pantalla LCD de 16x2. La librería LiquidCrystal trabaja con todas las pantallas LCD que sean compatibles con el controlador Hitachi HD44780 que tienen una interfaz de 16 pines.

Este sketch imprime "Hola Mundo!" en la pantalla LCD y muestra la cantidad de segundos que tiene el programa de estar ejecutándose.

  El circuito:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)

 Library originally added 18 Apr 2008
 by David A. Mellis
 library modified 5 Jul 2009
 by Limor Fried (http://www.ladyada.net)
 example added 9 Jul 2009
 by Tom Igoe
 modified 22 Nov 2010
 by Tom Igoe
 modified 7 Nov 2016
 by Arturo Guadalupi
 modified 4 Mar 2019
 by Jose Nunez

 Este ejemplo de código es de dominio público.

 http://www.arduino.cc/en/Tutorial/LiquidCrystalHelloWorld

*/

// Incluir la librería:
#include <LiquidCrystal.h>

// Inicializar la librería con los pines adecuados.
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//Esta función se ejecuta solo una vez al inicio del programa.
void setup() {
  // Configurar la cantidad de columnas y renglones a utilizar:
  lcd.begin(16, 2);

  // Enviar mensaje a la pantalla.
  lcd.print("Hola mundo!!!");
}

// Esta función se ejecuta de manera constante.
void loop() {
  // Ubicar la impresión (cursor) en la columna 0 línea 1.
  // (nota: línea 1 es equivalente al renglón 2 pues se cuenta desde cero

  lcd.setCursor(0, 1);

  // enviar la cantidad de segundos a la pantalla.
  lcd.print(millis() / 1000);
}

El Problema de los segundos

El programa descrito simplemente muestra la cantidad de segundos transcurridos desde que se inició el controlador.

La idea es mostrar el tiempo transcurrido no como un numero de segundos, sino como una expresión de horas:minutos:segundos transcurridos.

Así, cuando se tengan 130 segundos transcurridos, se muestre en el display que se tienen 00h 2min 10seg o “00:02:10”

Para resolver el problema vamos a enfocarnos primero en los segundos. ¿Cómo pasamos de 130 segundos a 10 segundos? ¿o de 65 segundos a 5 segundos?

Una vez resuelto el problema de los segundos podríamos tratar de repetir la solución para los minutos y las horas.

Aproximación #1 – Variables de ajuste acumulativo

Una forma de resolver el problema de los segundos es manteniendo tres variables:

  • seg_cuenta: Lleva cuenta de todos los segundos transcurridos desde que se inició la ejecución del programa.
  • seg_muestra: Almacena el valor equivalente de segundos de 0 a 59 para los segundos contados.
  • seg_ajuste: Acumula los segundos que se van a restar de seg_cuenta para calcular seg_muestra.

Veamos un ejemplo:

seg_cuenta = millis() / 1000; //Calculamos la cantidad de segundos transcurridos mediante la división de la cantidad de milisegundos transcurridos entre 1000.

seg_muestra = seg_cuenta - seg_ajuste; // Ajustamos los segundos a mostrar al restarles el valor de ajuste. Dicho valor de ajuste inicialmente es cero, y sube 60 cada vez que seg_muestra supera los 59 segundos.

if(seg_muestra > 59) {
   seg_ajuste = seg_ajuste + 60; 
   seg_muestra = 0;
}

Aun cuando esta solución no es óptima, puede que sea suficientemente buena para calcular los segundos que se van a mostrar.

¿Puede tratar de completar la lógica para usar variables de ajuste en minutos y horas?

Aproximación #2 – Uso de la función matemática módulo

Existe una función matemática de suma utilidad para este tipo de problema. Esta función se llama módulo matemático.

El módulo matemático permite calcular la cantidad restante de una división entera. Por ejemplo, si dividimos 5 entre 2 para un resultado entero, el resultado es 2.0. Dado que 2 * 2 = 4 la cantidad restante es 1.

EJEMPLO #1: 5 MOD 2 = ?
Dado que 5 / 2 = 2
Y que 2 * 2 = 4
Y que 5 - 4 = 1
Entonces 5 MOD 2 = 1

Qué tal el caso inverso:

EJEMPLO #2: 2 MOD 5 = ?
Dado que 2 / 5 = 0
Y que 5 * 0 = 0
Y que 2 - 0 = 2
Entonces 2 MOD 5 = 2

Vemos como cuando el divisor es mayor que el dividendo, entonces la función módulo se convierte en el valor del dividendo.

Veamos ahora un caso más elaborado. ¿Qué sucede si hacemos una función módulo para una secuencia de numeros. Digamos del 1 al 10; para un divisor = 5.

Dividendo (a) a MOD 5
11
22
33
44
50
61
72
83
94
100

(!) Si notamos la secuencia, vemos que el resultado de a MOD 5 es una secuencia de numeros que va de 0 a 4 donde el resultado cero coincide con todas las instancias de a que son divisibles entre 5.

Este fenómeno matemático se puede utilizar para obtener una función de valores (segundos) que vaya de 0 a 59 tal y como se muestra en el siguiente código:

segundos_cuenta = millis() / 1000;
segundos_mostrar = segundos_cuenta % 60; // El símbolo % se usa para invocar la operación matemática módulo.

Podemos entonces concluir que la aproximación al problema mediante la función matemática módulo (#2) es más eficiente (al menos desde la perspectiva de cantidad y complejidad del código escrito) que la aproximación con variables de ajuste acumulativo (#1).

El problema de los minutos y las horas.

Este problema de los segundos se debe resolver también para la cuenta de minutos y de horas, de forma que después de 59 minutos volvamos al minuto cero y aumentemos una hora.

En el caso de la aproximación #1, es cuestión de agregar las variables de ajuste acumulativo para minutos y para horas.

En el caso de la aproximación #2, lo que necesitamos entender es que para una cantidad de segundos dada, podemos calcular una cantidad de minutos y una cantidad de horas. Por ejemplo, 120 segundos equivale a 2 minutos; y 3601 segundos equivale a poco más de 1 hora. Partiendo de allí podemos usar la operación de módulo 60 para iterar los minutos de 0 a 59; y si fuera el caso podemos usar la misma operación pero con un divisor de 24 para iterar entre 0 y 23 horas.

segundos_cuenta = millis() / 1000;
segundos_mostrar = segundos_cuenta % 60;

minutos_mostrar = (segundos_cuenta / 60) % 60;

horas_mostrar = (segundos_cuenta / 3600); // Vamos a omitir la operación módulo en las horas para simplemente mostrar la acumulación de horas tal cual.

Reto: ¿Cómo modificarías el código del siguiente programa para implementar una cuenta adecuada de días, horas:minutos:segundos (d, hh:mm:ss)? Toma en cuenta la lógica necesaria para que los numeros menores de 10 tengan un cero a la izquierda. (01d, 00:10:15)

/*
  LiquidCrystal Library - Hola Mundo

Demuestra cómo usar una pantalla LCD de 16x2. La librería LiquidCrystal trabaja con todas las pantallas LCD que sean compatibles con el controlador Hitachi HD44780 que tienen una interfaz de 16 pines.

Este sketch imprime "Hola Mundo!" en la pantalla LCD y muestra la cantidad de segundos que tiene el programa de estar ejecutándose.

  El circuito:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)

 Library originally added 18 Apr 2008
 by David A. Mellis
 library modified 5 Jul 2009
 by Limor Fried (http://www.ladyada.net)
 example added 9 Jul 2009
 by Tom Igoe
 modified 22 Nov 2010
 by Tom Igoe
 modified 7 Nov 2016
 by Arturo Guadalupi
 modified 4 Mar 2019
 by Jose Nunez

 Este ejemplo de código es de dominio público.

 http://www.arduino.cc/en/Tutorial/LiquidCrystalHelloWorld

*/

// Incluir la librería:
#include <LiquidCrystal.h>

// Inicializar la librería con los pines adecuados.
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//Esta función se ejecuta solo una vez al inicio del programa.
void setup() {
  // Configurar la cantidad de columnas y renglones a utilizar:
  lcd.begin(16, 2);

  // Enviar mensaje a la pantalla.
  lcd.print("Hola mundo!!!");
}

// Esta función se ejecuta de manera constante.
void loop() {
  // Ubicar la impresión (cursor) en la columna 0 línea 1.
  // (nota: línea 1 es equivalente al renglón 2 pues se cuenta desde cero

  lcd.setCursor(0, 1);

  // enviar la cantidad de segundos a la pantalla.
  lcd.print(millis() / 1000);
}
Haz clic acá para ver la solución
/*
  LiquidCrystal Library - Hola Mundo

Demuestra cómo usar una pantalla LCD de 16x2. La librería LiquidCrystal trabaja con todas las pantallas LCD que sean compatibles con el controlador Hitachi HD44780 que tienen una interfaz de 16 pines.

Este sketch imprime "Hola Mundo!" en la pantalla LCD y muestra la cantidad de segundos que tiene el programa de estar ejecutándose.

  El circuito:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)

 Library originally added 18 Apr 2008
 by David A. Mellis
 library modified 5 Jul 2009
 by Limor Fried (http://www.ladyada.net)
 example added 9 Jul 2009
 by Tom Igoe
 modified 22 Nov 2010
 by Tom Igoe
 modified 7 Nov 2016
 by Arturo Guadalupi
 modified 4 Mar 2019
 by Jose Nunez

 Este ejemplo de código es de dominio público.

 http://www.arduino.cc/en/Tutorial/LiquidCrystalHelloWorld

*/

// Incluir la librería:
#include <LiquidCrystal.h>

// Inicializar la librería con los pines adecuados.
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//Esta función se ejecuta solo una vez al inicio del programa.
void setup() {
  // Configurar la cantidad de columnas y renglones a utilizar:
  lcd.begin(16, 2);

  // Enviar mensaje a la pantalla.
  lcd.print("Hola mundo!!!");
}

// Esta función se ejecuta de manera constante.
void loop() {
  // Ubicar la impresión (cursor) en la columna 0 línea 1.
  // (nota: línea 1 es equivalente al renglón 2 pues se cuenta desde cero

  lcd.setCursor(0, 1);

  // enviar la cantidad de segundos a la pantalla.
  lcd.print(formatearTiempo(millis() / 1000));
}

String formatearTiempo(segundos_cuenta) {
   int segundos_mostrar = segundos_cuenta % 60;
   int minutos_mostrar = (segundos_cuenta / 60) % 60;
   int horas_mostrar = (segundos_cuenta / 3600) % 24;
   int dias_mostrar =  (segundos_cuenta / (3600 * 24));

   String resultado  = "T: ";
   resultado = resultado + String(dias_mostrar);
   resultado = resultado + "d, ";
   resultado = resultado + String(horas_mostrar);
   resultado = resultado + ":";
   resultado = resultado + String(minutos_mostrar);
   resultado = resultado + ":";
   resultado = resultado + String(segundos_mostrar);
   resultado = resultado + "  ";
   return resultado;
}

139 total views, 1 views today

3Shares

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.