Nueva libreria Temporizador (modificada)

Quiero compartir con todos vosotros mi primera libreria de Arduino.
Se trata de "Temporizador".

Nos permite crear temporizadores con el objetivo de ejecutar acciones cuando haya transcurrido el tiempo indicado, de una forma sencilla.

Buen trabajo mandragoratools!!

Agrega en la descripción que esta limitada a 5 temporizadores tal como has puesto en tu ejemplo.
Quien no mire la librería en si, no sabrá que has definido 5 variables que se actualizan.
Eso podrias mejorarlo haciendolo mas dinámico, para la próxima versión.

Igualmente excelente trabajo

surbyte:
Buen trabajo mandragoratools!!

Agrega en la descripción que esta limitada a 5 temporizadores tal como has puesto en tu ejemplo.
Quien no mire la librería en si, no sabrá que has definido 5 variables que se actualizan.
Eso podrias mejorarlo haciendolo mas dinámico, para la próxima versión.

Igualmente excelente trabajo

Gracias, estoy empezando con esto de las librerias, y la verdad es que ví bastante útil hacer algo así,cuando empecé a desarrollarla me topé con el problema de que no podia crear varias instancias de la misma clase para usar temporizaciones "ilimitadas", con lo cual decidí crear 5 funciones una para cada temporización con el objetivo de no estar limitado a una sola, pero estoy seguro de que esto es posible de algún modo.

Seguiré investigandolo, para mejorar esta herramienta. Saludos

Bueno espera a que venga Lucario o noter y ya te dirán por donde ir.
Repito, no es por buscar el pelo al huevo, es que para que tenga mas difusión debes ser mas amplia.
Pero esta sobrada para el 95% de los casos.

surbyte:
Bueno espera a que venga Lucario o noter y ya te dirán por donde ir.
Repito, no es por buscar el pelo al huevo, es que para que tenga mas difusión debes ser mas amplia.
Pero esta sobrada para el 95% de los casos.

No he tenido el privilegio de conocer todavia a Lucario o a noter, espero hacerlo pronto.
Gracias por la ayuda y la atención. Saludos

Hola mandragoratools

Buen trabajo. Este es el camino para ampliar las prestaciones de nuestros Arduinos, no obstante me surge una duda (seguramente fruto de una lectura apresurada).

Dices que:

Nos permite sustituir la función delay(); para evitar retrasos indeseados en nuestros programas.

Pero en el ejemplo que pones no consigo ver como podriamos poner un equivalente a "delay(1)", por ejemplo, para establecer un retardo de 1 mseg.

Si no es un error al escribir, ¿ podrias poner un ejemplo de como hacerlo usando "Temporizador" ?

Bueno, tras "estudiar" a fondo tu libreria, y a riesgo de ser el "malo" porque los demas comentarios son de elogio, te voy a dar mi opinion.

Antes de seguir quiero recalcar que lo que trato es de que veas que hay un camino a seguir para el desarrollo del software que deba servir para otros (es fundamental que funcione bien).
Intento explicarte las cosas para que puedas, de verdad, ahondar en el camino que has inicado y que me parece el correcto (programar, programar y programar).

Empecemos.

La libreria así como está NO funciona.

  • Las variables donde se guarda dd, hh, mm, ss deben declararse en la seccion <.H>, darles
    rango de para evitar accesos indeseados, y declararlas como
  • Sobra el constructor (no hace nada), además el compilador de C++ ya incluye uno por defecto.
  • La funcion de inicializacion no inicializa nada por lo que la ejecucion del programa es errónea ya
    que no inicializa diaAnt, horaAnt, minutoAnt ni segundoAnt.
  • Al llamar a la funcion <encender()> se asume que segundo=millis()/100, pero el valor devuelto
    por millis() puede ser de hasta 4.294.967.295 milisegundos, por lo que la toma de datos que
    hacemos puede arrojar directamente un valor de unos 50 dias !!!
  • Para que la libreria funcione adecuadamente hay que estar llamando a <temporizar()> constantemente
    durante el loop. Si aumentamos el número de temporizadores activos, el programa no es manejable.
    Lejos del proposito utópico de ".. temporizadores ilimitados,..."
  • Y además despilfarramos recursos preciosos (no todo el mundo usa el ATmega2560).

Para que veas a que me estoy refiriendo ahí va una versión simplificada pero operativa de lo que seria una libreria como esa:

Esta es la libreria en sí (Temporizador.h)

// ---------
// Codigo .H
// ---------
#include "Arduino.h"

class Temporizador
{
public:
        // ------------------------------------------------
        // Inicializa el temporizador con los valores dados
        // ------------------------------------------------
        void iniciar(int dia, int hora, int minuto, int segundo)
        {
    _tiempo=(((dia*24+hora)*60+minuto)*60+segundo)*1000;
            if(_tiempo==0) _tiempo=1000;   // Un segundo minimo
    _tiempo=_tiempo+millis();
        }
        // ----------------------------------
        // Chequea si el T/O se ha completado
        // ----------------------------------
        boolean completado()
        {
    if(millis()>=_tiempo) return(true);
    else return(false);
        }
private:
 volatile unsigned long _tiempo;
};

Y este un pequeño ejemplo ilustrativo:

//*************************
// Ejemplo
//*************************
#include "Temporizador.h"
#define pinLed  13

// Instanciamos la clase
Temporizador timer;

void setup()
{
 // Definimos pin 13 como salida
 pinMode(pinLed,OUTPUT);
 // Lo inicializamos a una condicion conocida
 digitalWrite(pinLed,LOW);
        // Instanciamos la clase
 // --------------------------------------
 // Ponemos un T/O = 15 min, 27 seg
 // Tambien podemos ponerlo en el <loop()>
 // --------------------------------------
 timer.iniciar(0,0,15,27);
}

void loop()
{
 if(timer.completado())
 {
 // Si queremos invertir la salida ...
 digitalWrite(pinLed,!digitalRead(pinLed));
 // Si queremos fijarla ...
 //digitalWrite(pinLed,HIGH);
 
 // Ejemplo de repeticion del timer con otro intervalo
 timer.iniciar(0,1,10,0);
 }
 // ... resto del programa ...
}

Y como colofon, podriamos poner en marcha cuantos temporizadores quisieramos sin mas que hacer nuevas instancias de la clase:

#include "Temporizador.h"

#define pinLed  13

// Instanciamos la clase
Temporizador timer;
Temporizador timer1;
Temporizador timer2;
Temporizador timer3;

//... y en el loop() ...
if(timer.completado()) { }
if(timer1.completado()) {}
if(timer2.completado()) {}
if(timer3.completado()) {}

Espero que mi comentario te ayude.

Es su primera versión Alfaville, por eso yo lo estimulé para que vea como seguir mejorándola.

Estimular no es la parte mas importante, sino enseñar.
Al menos así lo he vivido y así lo entiendo.

Alfaville:
Estimular no es la parte mas importante, sino enseñar.
Al menos así lo he vivido y así lo entiendo.

En primer lugar, muchisimas gracias por tu tiempo, tus consejos y por guiarme un poco más en este camino que acabo de emprender...

Nunca antes me habia dispuesto a hacer nada parecido, y me apeteció compartir esto, aunque al parecer todavía queda lejos de ayudar o servir a otros para algo...

En segundo lugar y siguiendo tus directrices según me explicas (y yo entiendo)¿ para llevar a cabo esta libreria, no haria falta para nada hacer uso de el archivo ".cpp"?

En tercer lugar me he dispuesto ha efectuar las modificaciones que me aconsejas, para optimizar y darle sentido a esto, y he borrado el archivo ".cpp" y copiado tal cual tu ejemplo de archivo ".h" pero al intentar llevar a cabo el programa me ocurre lo siguiente:

Usando como ejemplo en el pin 13 un led al transcurrir el tiempo indicado en timer.iniciar(0,0,0,10);
el led se enciende, y permanece encendido indefinidamente no vuelve a apagarse, es como si el ciclo solo se efectuase una vez y ya, ¿Que puede andar mal aquí?

Muchisimas gracias de nuevo por vuestra atención. Un saludo

surbyte:
Bueno espera a que venga Lucario o noter y ya te dirán por donde ir.

Ya llegué.

Pues de lo que hubiera dicho, es básicamente Alfaville acaba de sugerir.
No lo hubiera dicho "porque sí", sino porque para optimizar un programa sin perder la funcionalidad que ya tiene, se debe tener clara la meta de dicho programa (o librería).

Dicho esto último, se podría entender el verbo "optimizar" como la búsqueda del camino más corto posible hacia la meta. Suena metafórico, pero ese es el punto: simplificar el código; que de paso lo vuelve más eficiente.

Optimizar o simplificar código usualmente implica, en cierto modo, hacerlo más difícil de entender (o en el peor de los casos, de corregir). Por esta razón, es que va logrando con la experiencia; y por qué no, con las críticas constructivas.

Es tanto cuestión de experiencia que, por ejemplo, si algún novato me pidiera crear desde cero un código base o de ejemplo para un proyecto, es muy probable que no lo comprenda en totalidad en un principio. Por esa experiencia de la que hablaba, es que ya estoy acostumbrado a crear código "pre-optimizado" así por decirlo.

Ya que Alfaville dio la sugerencia, yo explicaré cómo llegó hasta ahí.

En primer lugar, recuerda que "optimizar" es como la búsqueda del camino más corto posible hacia la meta. Y cuál piensas tú que es la meta u objetivo de la librería? Pues crear un temporizador que se inicializa con un tiempo prestablecido (días, horas, minutos y segundos), o me equivoco?

En programación orientada a "objetos" (abrev.: POO), podemos abstraer (imaginar) un temporizador como un reloj cronómetro, un contador regresivo como el de un horno microondas, etc.
Supongamos que tienes que tomar el tiempo de cada corredor de una maratón, son solo 20. Cómo lo harías? Simple: con 20 temporizadores o cronómetros.
Si alguien que utiliza tu librería quisiera en su proyecto temporizar varios relés, LEDs y sensores, no podría porque está limitado solo a cinco de estos? Quizá en primera instancia respondas: pues que haga otra instancia y listo. Pero y si lo que necesita son 8 temporizadores y no 10? (5 * 2 instancias), entonces las 2 sobrantes estarán ocupando espacio en memoria que podría ser aprovechado para algo más útil.

Recuerdas que antes mencioné la palabra "objeto"? Pues ahí está la primera sugerencia de Alfaville: reduce tu objeto temporizador a llevar la cuenta de un solo lapso; como un cronómetro que solo puede llevar una cuenta de tiempo.
A medida que necesites más conteos, más "objetos" temporizadores querrás tener; sin que ninguno se quede sin usar (sin desperdiciar).

Para el siguiente punto, quiero que sigas recordando el objetivo o meta de tu librería: "crear un temporizador que se inicializa con un tiempo prestablecido". Como objetivos específicos tienes que se puedan especificar hasta los días, y que se pueda verificar si el plazo expiró desde el momento en que se inició. Cómo vas a cumplir esos objetivos? Realmente no interesa siempre y cuando se cumplan (aclaro que con esto no quiero decir que no importa buscar "el camino más corto posible", lo cual vendría siendo como "buscar la excelencia"; y con más razón al tratarse de un sistema de limitados recursos).

Tu librería se mueve gracias a la función millis, LA CUAL TRABAJA CON MILISEGUNDOS; NO CON DÍAS, NI HORAS, NI MINUTOS, NI SEGUNDOS.
De aquí radica la pregunta: vale la pena almacenar los días, horas, minutos y segundos asignados al temporizador; a sabiendas que el corazón de la librería solo trabaja con milisegundos?

Ahí está la razón de otra sugerencia de Alfaville: homologa (convertir a un estándar compatible) los datos ingresados de manera que sea fácil de trabajar con millis; en otras palabras, convierte el tiempo asignado a milisegundos.
De esta forma, tu objeto temporizador consumirá muy poca memoria RAM y menos recursos computacionales.

Nótese que este cambio a pesar de ser muy drástico (y mucho mejor), los objetivos se siguen cumpliendo. Por esta razón es que antes mencioné que la forma en que los vayas a cumplir, realmente no interesa.

El resto de sugerencias ya tienen que ver con limitaciones del Arduino, las validaciones y los estándares de C++ y de la POO.

Y ya para finalizar este gigantesco post (que me tomó bastante tiempo escribir), voy a dejarte estas tres preguntas que sé que mejorarán aun más la librería:

  • Qué pasa si se verificó que el lapso del temporizador expiró? Hay que reiniciarlo manualmente o se reinicia automáticamente?
  • Que tal si alguien que use tu librería también quiera precisión de tiempo hasta en milisegundos?
  • Ya tienes alguna idea de cómo lidiar con el desbordamiento (regreso a cero) de millis? Recuerda que esto ocurre aprox. cada 54 días de operación continua.

Colorín colorado, el post se ha terminado...

Lucario448:

  • Qué pasa si se verificó que el lapso del temporizador expiró? Hay que reiniciarlo manualmente o se reinicia automáticamente?
  • Que tal si alguien que use tu librería también quiera precisión de tiempo hasta en milisegundos?
  • Ya tienes alguna idea de cómo lidiar con el desbordamiento (regreso a cero) de millis? Recuerda que esto ocurre aprox. cada 54 días de operación continua.

Perdona Alfaville fuen un fallo mio =S, tu ejemplo funciona a la perfección, Muchas gracias Lucario448 por todo lo que me citas me servirá mucho para progresar, al parecer todo esto se me queda demasiado grande todavia, y aunque lo hice con una buena intención ahora me doy cuenta de que para lo unico que sirvió es para darme cuenta de lo tanto que me queda por aprender y que realmente no sirve todavia para nada mas que eso, tanto por la optimización como por los recursos que consume, y por todo en general quizas algún dia vuelva con algo que realmente merezca la pena y pueda contribuir con esta magnifica comunidad. Muchisimas gracias a todos por abrirme los ojos :wink:
Saludos.

@Lucario448 ¡ jó ! me has emocionao... :smiley: :smiley: :smiley:

Bueno por alusiones:
Voy a contestar a mandragoratools porque entiendo que las cuestiones de Lucario448 no son para mi.

En segundo lugar y siguiendo tus directrices según me explicas (y yo entiendo)¿ para llevar a cabo esta libreria, no haria falta para nada hacer uso de el archivo ".cpp"?

Ya ves que no es indispensable, pero si la libreria crece, es conveniente tener separados el <libreria.h>, que contiene las definiciones y demás, del <libreria.cpp> que contiene la implementacion de las funciones,
Al final todo se junta al compilarlos gracias a los <#include>

Usando como ejemplo en el pin 13 un led al transcurrir el tiempo indicado en timer.iniciar(0,0,0,10);
el led se enciende, y permanece encendido indefinidamente no vuelve a apagarse, es como si el ciclo solo se efectuase una vez y ya, ¿Que puede andar mal aquí?

Evidentemente si quieres que el programa haga algo lo tienes que escribir.
Lo que tu quieres se haria así:

// ... Coloco el pin 13 como quiero que esté durante la temporización
digitalWrite(pinLed,HIGH);
// Ahora coloco el temporizador y sigo con el programa...
timer.iniciar(0,0,0,10);
// ... vamos chequeando ...
if(timer.completado())
{
   digitalWrite(pinLed,LOW);
}
// ... sigue el programa ...

Por supuesto esto puede no bastar porque el loop() hará que se cargue de nuevo el timer(0,0,0,10)
y repitamos el ciclo. Para evitarlo (si fuese el caso) podemos crear un flag (un indicador) que nos diga que ese timer
y el proceso asociado ya se ejecutó y no queremos volver a ejecutarlo...
Hay muchas posibilidades y no dependen solo de la libreria, sino del uso que se hace de ella.

Añadele milisegundos (aunque es una tonteria) para que puedas practicar, y todo aquello que consideres pueda ser necesario, teniendo siempre en cuenta que es un software auxiliar para que los usuarios completen sus programas.
Tu creas la herramienta. Ellos el programa que la usa.

Hola.
Yo tal vez podría agregar algo más, pero de momento me mantengo al margen, que ya estáis dando bastante tralla sin mi ayuda ::slight_smile: ::slight_smile: .
Tal y como indicò Lucario, la POO nos abre un nuevo nivel en la programación. De hecho se trata de una forma muy diferente de plantear un programa. Primero hay que ser capaces de comprender, si no en profundidad, sí al menos la existencia y utilidad de las distintas herramientas que nos proporciona y luego aprender a desmenuzar nuestro problema a conceptos de clases, utilizando al máximo esas herramientas (encapsulamiento, abstracción, herencia, polimorfismo...).

Bienvenido noter.
El código posteado está a tu disposición para hacerle las mejoras que quieras. Al fin y al cabo es un código de prueba para mandragoratools sin mas aspiraciones que intentar ilustrar.

mandragoratools:
al parecer todo esto se me queda demasiado grande todavia, y aunque lo hice con una buena intención ahora me doy cuenta de que para lo unico que sirvió es para darme cuenta de lo tanto que me queda por aprender

Pues ahí tienes, para que no te quedes estancado con solo saber lo mínimo.

Y perdona si alguno por aquí (me incluyo) ha ido demasiado rápido; porque como había dicho antes: la experiencia es la que ayuda a comprender este asunto de la optimización (metafóricamente hablando: "saberse los atajos").

mandragoratools:
quizas algún dia vuelva con algo que realmente merezca la pena y pueda contribuir con esta magnifica comunidad.

Amen hermano, amén. :wink:

Yo les plantearía algo a los 3 expertos pero sería desvirtuar el hilo.
Asi que tal vez se los planteo por privado o hago un hilo público y a ver para donde va el nuevo debate!!
Esten atentos (Lucario, Alfaville y noter) porque el desafío será interesante aunque como puede pasar también puede tener una solución simple que yo no veo.

A mandragoratools le digo que no se desanime y todo lo contrario, motívate para seguir aprendiendo porque nunca alcanzarás el máximo si no lo haces, esto no es un fracaso, es un paso en tu crecimiento como programador.
Cuando creas saber algo, siempre viene alguien y te muestra que te puede hacer mas fácil o mas simple.

Animo mandragoratools
Por problemas de buscar algo sencillo, he probado tu librería y de momento es totalmente funcional.

Saludos!

P.D. Usa pocos recursos.

Perdonand como el tema de estos temporizadores ? sigo teniendo dudas en su comprension

¿Has leído el README de la librería?