Las PreviousMillis son cosas de brujería

Pues tengo un problema personal con ellas, como un enfrentamiento en el cual ellas siempre ganan.
No, no estoy psicótico, es que no las entiendo, y no será por no utilizarlas, que ahora mismo estoy utilizando en un programita 12 delays con millis y van muy bien.

Es que cuando algo no termino de entenderlo, soy como perro con un hueso, y a veces le doy tantas vueltas, que la explicación la tengo delante de las narices y no me entero.

Cuando algo no se entiende, se teme o se respeta, y por eso, en el programa declaro al principio, antes del setup() las 12 PreviousMillis (Me gusta castellanizarlas como MillisPrevias o MillisAnteriores) y las numero, agregándoles un número al final, y les asigno el valor millis().

A lo largo del programa se van ejecutando los delays, pero resulta que hay algún delay de esos, que no se ejecuta lo mismo hasta pasado unas horas, o varios días, y entiendo que lleva el valor que le he asignado antes del setup(), lo mismo un valor en millis de días.

Por ejemplo, un evento que se ejecuta cuando el programa lee un pulsador (resistencia pull down).
Como está dentro de un loop (o un while(1) dentro de un menú) se ejecuta contínuamente, y para prevenir que lo lea más de una vez le pongo un delay con millis:

if  (digitalRead(Pulsador, HIGH))
  {
    if ((millis() - MillisAnteriores) >= 1000 )
     {  
        MillisAnteriores = millis();
        Ejecuta la acción y cuando vuelva a pasar por la lectura del pulsador estará en LOW
      }
    }

Pues en este ejemplo, como no he actualizado el valor de MillisAnteriores desde antes del setup(), tiene un valor muuuy antiguo (en millis) y cuando entra en la operación de resta, tendría que tardar un montón en superar los 1000 milisegundos para ejecutar la acción.

Evidentemente me equivoco, porque funciona aunque hayan pasado horas desde el inicio del programa, y con seguridad no estoy viendo algo elemental, pero por ahora sigo pensando que es cosa de brujería.

Evidentemente parece que te equivocas. Fíjate que cuando se realiza la operación (millis() - MillisAnteriores) lo que se está calculado es cuanto tiempo ha transcurrido desde la última vez que se actualizó la variable MillisAnteriores. Si, como tú bien dices, fue en el "inicio de los tiempos" entonces hace muchísimo tiempo que se actualizó por última vez. El if está puesto para que se cumpla si han trascurrido 1000 milisegundos o más desde esa última vez y, efectivamente, han pasado muchísimo más de 1000 milisegundos, con lo que se cumple la condición y entra dentro del if.

Hagamos un ejemplo con el trozo de código que has puesto: al arrancar el Arduino el contador de millis() se inicia a cero, con lo que si inicializamos con su valor la MillisAnteriores en el setup() seguramente tendrá un valor muy bajo, supongamos que sea 100 milisegundos. Transcurrido mucho tiempo se pulsa el botón y se llega al por primera vez al if ((millis() - MillisAnteriores) >= 1000 ). Supongamos que ese "mucho tiempo" son 3600000 milisegundos (una hora desde que arrancó el Arduino). Entonces el valor de (millis() - MillisAnteriores) será 3599900 y, como se puede ver a simple vista, ese valor es mayor que 1000 con lo que se cumple el if, "entra dentro" y ahora se le asigna el valor 3600000 a MillisAnteriores con lo que ahora habrá que esperar a que pasen al menos 1000 milisegundos antes de que se vuelva a cumplir la condición del if.

Es más: si el tiempo que transcurre desde que, en el setup(), se inicializa la variable MillisAnteriores y se llega al if es menor de 1000 milisegundos, entonces no se cumplirá la condición la primera vez que se llegue a ella y tendrá que esperar a que transcurra el tiempo que falte para "completar" los 1000 milisegundos.

No sé si con esto habré aclarado tu duda.

No termino de entender tu planteamiento; pero supongo que no has entendido del todo el funcionamiento de millis. Te intento explicar lo que ocurre en el arduino en el código que pones arriba.

  • Cuando arranca el arduino, en el setup se establece millis. Pongamos que ha tardado 100 milisegundos hasta que se ejecuta el MillisAnteriores=millis() en el setup. Entonces, MillisAnteriores tendrá como valor 100.
  • Seis horas después del arranque, pulsas el botón. Millis en ese momento vale (66060*1000)=21600000. Evidentemente se cumple la condición, puesto que millis-millisanteriores (21600000-100) es (muy) superior a 1000. Por lo tanto, ejecuta la acción, pero millisanteriores pasa a ser 21600000.
  • Si se produce un rebote y vuelve a entrar en el if transcurrido un par de milisegundos, millis va a valer 21600002, por lo que si restamos millisanteriores (21600002-21600000=2) la cuenta será inferior a 1000.
  • Ahora hay una nueva pulsación, tras cinco segundos desde el último rebote. Millis valdría 21605002 y la resta (21605002-21600002=5000) sería superior a 1000, con lo que se ejecutaría la acción y millisanterior pasaría a ser 21605002.

No sé si te habrá aclarado algo o no. Espero que sí.
Saludos.

Pd. Aunque veo que ya había contestado IgnoranteAbsoluto y en términos casi idénticos, dada la gran cantidad de preguntas que suscita el asunto del millis, decidí dejar mi post, aunque sólo sea para repetir lo dicho antes por IgnoranteAbsoluto.

Me tranquiliza, noter, que ambos coincidamos. Eso significa que ambos estamos en lo cierto o que no soy el único que se equivoca. :smiley:

Ahora en serio. Nunca biene mal explicar una misma cosa de forma diferente aunque muy parecida. Siempre hay quien entienda algo mejor con una explicación que con otra. Y creo que tu explicación es más clara que la mía.

Gracias a los dos, súper clara la explicación de ambos, y claro que me ha aclarado el panorama, ahora entiendo que si hubiese hecho alguno de los cálculos que ponen ambos, me habría dado cuenta del error, que para un delay con millis de un segundo, solo hace falta que transcurra un segundo desde la asignación del valor a la variable para que se cumpla la condición, y en el caso del pulsador, que pase un segundo entre dos pulsaciones para que vuelva a darse la condición (eso, claro, lo entendía).
Incluso ahora veo claro que la próxima vez que se active el pulsador, transcurrido más de un segundo se cumplirá la condición en la "primera pasada" por el if.

Y eso que llevaba tiempo "herrado" (de herradura, eso que se le ponen a los caballos, JAJAJA).

PD: De todas formas, las brujas no existen, pero que las hay, las hay.

Y de nuevo, no usaste el monitor Serie para saber donde estabas parado!!