Timer método very naive

Hola a todos, lo denominé así porque según Luis Llamas en una manera sofisticada de decir "hecho a mano"..ja
lo que estoy intentando hacer, hecho ya en realidad, es un timer para mis relés, pero bien hecho a mano jaja sin nada de código sofisticado...lo que hice fue crear mi variable timer:

byte timer = 30; // 30 seg

ese es el tiempo que puse por defecto.. despues tengo una funcion que cuando mando un texto con #Txx me guarda el tiempo (xx) en la variable:

String char13 = mensaje;
    uint8_t startPos, endPos;
    startPos = char13.indexOf("#T") + 2;
    endPos = char13.indexOf("#T", startPos);
    TiempoNvo = char13.substring(startPos, endPos);
    timer = TiempoNvo .toInt();

y despues solo aplico un delay así:

      int tiempo = timer * 1000;
      delay(tiempo);

consulto, seguro no es la mejor forma, pero hay alguna manera mas sencilla y que use menos recursos o esta es aceptable?
porque lo que pasa es que los segundos que dice la variable, por ejemplo 30 no son 30, cuando se ejecuta son 35/36 segundos, siempre tengo como 5 o 6 segundos mas...
esto es por los tipos de datos usados o por algún otro motivo?

Muy interesante. Gracias por compartir.

hola alejoho37 gracias, pero no se a que te réferis, ojo porque no soy experta para nada, al contrario, estoy aprendiendo...si te sirve genial, hay q compartir es la manera de aprender, todos compartimos algo, acá los chicos del foro comparten su conocimiento por ejemplo, de ahí tiene que salir algo bueno jaja...un saludito y esperemos que los q saben me corrijan jajaja, espero no haber errado por mucho..
creo q lo mejor seria haber usado millis, pero se me hace difícil usarla, y a parte no se si detiene el código yo necesito hacer tipo delay que se frene y luego de ese tiempo continúe...

Estoy seguro que yo soy más nuevo que tú aquí. Imagínate que aún no tengo un arduino. Estoy aprovechando el tiempo en aprender lo más que pueda hasta poder conseguirme mi arduino uno.
Tu código no lo entiendo del todo pero me parece interesante. Es una lástima no poder ayudarte a resolver eso segundos de más que tienes.
Por cierto hoy, casualmente antes de leer tu publicación, me encontré otra que explicaba la función Millis. Esta es la dirección:
https://forum.arduino.cc/t/entender-millis-y-no-morir-en-el-intento/626976
Espero te sirva. Saludos.

¿Has comprobado que la transformacion es correcta?. coloca un seral.print por algun lado y compruebalo. Lo normal es que se pierdan unos 500 microsegundos por minuto pero 5 o 6segundos me parece demasiado. Sube un codigo completo a ver que esta pasando.
Saludos

Sin ver el código es difícil decir algo, pero el uso de Delay puede ser la causa. Porque lo que estas pidiendo es que se detenga durante 30 segundos, pero a esto hay que sumarle el tiempo de ejecución del código restante, que puede ser mucho si hay otros delays de por medio.

Hola a todos no estoy en casa para poder postear el código, igual esta en otro post mío, pero si creo 100% que PeterKantTropus tiene razón, hay otros delays exactamente de la diferencia q estoy teniendo..
así que llego y lo reviso, pero si eso se suma ya esta resulto, es eso el problema..

@AnyPopins ya te hemos aconsejado que como estas en etapa de aprendizaje abandona YA EL DELAY y reemplázalo por millis(). Se que no es un cambio muy fácil y en principio no es nada intuitivo pero luego verás que cosas como la que mencionas no te van a ocurrir ya que tu código no tendrá esos retardoss innecesarios que ni si quiera sabías que tenias. Ejemplo: cuando le pides algo al SIM900 y le pone delay(2000) te quedas de brazos cruzados x esos 2 segundos.
No digo que con millis() no demore algo, seguramente la respuesta del SIM no es inmediata pero no serán 2 segundos.
Vi que en el caso anterior seguiste a pesar de mi sugerencia y claramente implicaba un cambio total a tu código.
Cosas como estas prueban que cada vez tendrás mas y mas problemas siguiendo por el camino que sigues.
Te aclaro la solución no es quitar 5 segundos a tu delay() recibido por SMS, x si se te cruza por la cabeza.

Hola Surbyte como estas, si ya se que me dijiste que use librerías pero estuve intentando y realmente me resulta bastante mas difícil, lo intente con sim800l master y con la que me pasaste vos pero imaginate que si así hago consultas a cada rato, con librerías me darían de baja la cuenta jaja...estoy intentando pero de verdad me resulta mas difícil las librerías..
me darías un ejemplo sencillo y que pueda aplicar a mi código de millis() ?

¿Por qué usar librerías para un Timer? ¿Por qué cuesta tanto de entender?

UN TIMER ES UNA RESTA ENTRE TIEMPOS Y UNA COMPARATIVA CON EL INTERVALO QUE QUEREMOS. Ya está, no es complicado. Es restar.

¿Dónde está el problema con la función millis()?
El problema radica en que personas que no saben programar empezaron usando delay().
¿Por qué?
Por que decidieron copiar ejemplos de internet. El propio libro de proyectos de Arduino explica en el pie de página (pag 93) que para medir duraciones de tiempo entre eventos hay que usar millis()-
¿Qué es delay() y por qué no sirve cómo timer?
Delay, cómo indica su nombre, es un PARO para todo nuestro Arduino durante el tiempo que establezcamos cómo parámetro , no un contador de tiempo. No se ejecutará nada más hasta que no termina el intervalo, dando problemas obvios en el loop al entender mal la función.

Explicación de las partes de un Timer
El tiempo total que viene dado de la función nativa millis() (Vamos a llamarlo Tiempo_actual)
El tiempo desde donde empiezas a contar (Vamos a llamarlo Tiempo_previo)
El intervalo de tiempo que queremos calcular (Vamos a llamarlo Intervalo).

Condición resultante
Si Tiempo_actual - Tiempo_previo >= Intervalo Entonces -> Acción.

Ejemplo:
Tiempo_actual = 6000 //6 seg
Tiempo_previo = 5000 //5 seg
Intervalo = 2000 //2 seg

6 segundos - 5 segundos ¿Es mayor o igual a 2 segundos? NO, el timer todavía no se ha cumplido.

Opciones de un timer

  1. Se ejecuta a partir de ese intervalo por cada ciclo loop desde que se llegue a ese intervalo.
  2. Se ejecuta sólo cuando pase repetidamente el intervalo
  3. Se ejecuta una sola vez

Para la opción 1:
Sólo debemos poner Si Tiempo_actual - Tiempo_previo >= Intervalo Entonces -> Acción.

Para la opción 2:
actualizamos Tiempo_previo tras entrar en la condición.
Tiempo_previo = millis();

Para la opción 3:
Usamos un flag (variable) Que controle que sólo se ejecuta 1 vez.

¿Por qué se usa una resta y no una suma? ¿Por qué se usa unsigned int y unsigned long?
Podríamos extendernos aquí sobre millis() y micros() para explicar los por qué, pero lo dejo resumido en que de debe a la posibilidad de desbordamiento de las variables si nuestro proyecto necesitase que estuviese muchos días o permanentemente funcionando.
Así que sí, la forma correcta es restando y declarando correctamente las variables, sobre todo porque además sabemos que no vamos a tener tiempos de millis y micros con signo negativos.

Espero que esto pueda servirle a alguien. Especialmente a quienes empiezan.

1 Like

Mi respuesta estándar:

Mi recomendación es siempre la de usar millis() y máquinas de estados para cualquier programa. Por muy sencillo que sea. La función delay() sólo la usaría excepcionalmente en el setup(), si tuviera la necesidad de realizar una minúscula pausa al inicializar algo al arrancar el Arduino. Y nunca, repito, nunca usar goto, bajo ninguna circunstancia.

La ventaja de usar millis() y máquinas de estados es que siempre será más fácil "juntar" varios programas, que tengamos funcionando por separado, en uno solo. Además de que se pueden añadir nuevas "tareas" al programa, sin que interfieran en lo que ya hace. Todo esto es gracias a que no hay ningún delay() que detenga la ejecución del programa.

Eso sí, al igual que hay que evitar el uso del delay(), hay que procurar no tener bucles que lleven mucho tiempo de ejecución. Porque la idea es que el programa se demore lo mínimo en atender cada una de las diferentes cosas que ha de hacer. Dando así la sensación de que las está haciendo todas a la vez. Y si se "entretiene" demasiado en alguna cosa, puede que "se pierdan eventos" que ha de controlar de otras.

Además, recomiendo el uso de un buen estilo de programación. Cosas como poner nombres "adecuados" a las variables. Así como la definición y uso de constantes con #define, cons o enum. Siendo lo ideal conocer y hacer uso de las herramientas de programación que nos proporciona la programación orientada a objetos del C++. Porque, después de todo, este entorno de Arduino es C++.

Programar con millis() y máquinas de estados es mucho más enrevesado que usar delay(). Pero hay cosas que son imposibles de realizar si usamos delay(). Sobre todo si se quiere realizar varias cosas a la vez.

Para ver cómo se trabaja y tener una idea del uso de millis() y máquinas de estados recomiendo ciertos hilos de este mismo foro. Algunos de ellos se publicaron directamente como tutoriales. Mientras que otros son consultas que se hicieron y en las que yo he aportado mi granito de arena, tratando de explicar cómo hacer algunas cosas. Esto son los enlaces a los hilos:

Nota: con la migración del foro de Arduino a la nueva plataforma, se ha perdido el formato en algunas ocasiones y esto hace que se vean algunas cosas mal o "raras".

En cuanto al planteamiento de las consultas. Nunca está de más aportar la máxima información posible. Nada de decir sólo «utilizo un sensor de temperatura»; lo mejor es poner la referencia del sensor o un enlace donde se obtenga información detallada de él. Si se utilizan librerías, siempre viene bien decir de dónde se descargaron. Porque muchas veces hay diferentes versiones de la misma librería y no siempre se comportan igual. También es muy útil un diagrama de conexiones de las cosas. Aunque sean cuatro garabatos mal hechos.

Muchas veces, aunque el problema aparece en una parte del código, el origen del problema está en el extremo opuesto de dónde se está mirando. Por eso es muy importante, a veces, el aportar todo el código y no una parte de él. En infinidad de ocasiones el problema ha estado en la definición de una variable al principio del código.

Lo más importante de todo es explicar, lo más detallado posible, qué es lo que se quiere hacer y cómo se quiere que se comporte el Arduino. Es habitual la consulta en la que dicen que quieren que se encienda un led al pulsar un botón, y diez comentarios después aclaran que lo que se quiere es que se encienda al pulsar dos veces seguidas. Pues si es así, se comenta desde el principio y se especifica claramente qué es lo que se considera "dos veces seguidas". Que entre otras cosas se especifique cuánto es el máximo tiempo que ha de transcurrir entre cada pulsación, para considerarlo "seguidas". Lo dicho, cuanto más detalles se den, mejor.

Mi respuesta para este caso en particular:

Por lo que he leído de varias consultas que has hecho, tengo la impresión de que todas van alrededor de un mismo proyecto y que llevas mucho tiempo con este proyecto. Y que tal vez no sea tan pequeño como aparenta. No sé si lo que te interesa en sí es el proyecto porque es algo de utilidad para ti; o si lo usas como excusa para aprender a programar; o si es una mezcla de ambas cosas a partes iguales.

Yo te recomiendo informarte sobre las máquinas de estados y el uso de millis(). Pero si en tu código hay un delay() y no es en setup(), me plantearía rehacer el proyecto de “casi cero”. Digo “casi cero” porque hay muchas cosas que has aprendido en todo este tiempo, que cuando empezaste no sabías, todo eso es un trabajo muy importante que ya has hecho. No des por perdido todo lo que hasta ahora has hecho y que tal vez tengas que “descartar”. Te ha servido para no empezar desde cero.

Yo más de una vez he “apartado” todo lo que tenía hecho y empezado desde “casi cero”. Tomando partes de lo que hasta entonces había hecho, para integrarlo con modificaciones en un nuevo código.

Ten en cuenta que un programa hecho a base de delay() no se parece en nada a un programa hecho con máquinas de estados y millis().

Si nos planteas y detallas todo lo que tienes en mente, y compartes tu conocimiento adquirido, tal vez nos sea mucho más fácil ayudarte. De hecho, con sólo tratar de explicar tus ideas, problemas y posibles soluciones, puede que veas el problema y encuentres la solución sin más.

Hola chicos gracias a los 2, ahora a leer y ver que entiendo y que cambio en mi código, saluditos..

Any.