Consulta desborde desborde de millis

Buenas noches, Mi nombre es Abel Gambini, soy nuevo en el mundo arduino, necesito encender una lampara en lapsos de 18 hs y apagarla durante 6 hs, para ello estoy utilizando millis(), mi duda es en el momento del rollover a los 49 dias. Por favor agradeceria que chequeen mi codigo para saber si es confiable. desde ya gracias por su tiempo!

les adjunto el codigo

boolean lamparaState = true; unsigned long cr1On = millis (); unsigned long cr1Off = millis ();

void setup() {

pinMode(2, INPUT); // auto pinMode(3, INPUT); // cr1

pinMode(13, OUTPUT); //ESTADO DE LAMPARA pinMode(18, OUTPUT); //LAMPARA

digitalWrite(13, lamparaState); digitalWrite(18, HIGH);

}

void loop() {

int cr1 = digitalRead(3); //// ==> cr1

if (automatico == LOW) {

if (cr1 == LOW ) { 18 x 6 hs if ((millis() - cr1On >= 64800000) && lamparaState == true) { lamparaState = false; digitalWrite(13, lamparaState); digitalWrite(18, LOW); cr1Off = millis(); } if ((millis() - cr1Off >= 21600000) && lamparaState == false) { lamparaState = true; digitalWrite(13, lamparaState); digitalWrite(18, HIGH); cr1On = millis(); } } }

Hola y bienvenido al foro. Te invito a que te leas las NORMAS y verás que has posteado mal tanto el código, como la sección.

En cuanto al código has hecho lo que se supone que se debe hacer con millis correctamente, así que no debe haber problema.

Si te preocupa, hay dos opciones, esperar los 49 dias… ejem… o usar esta función en el setup

#include <util/atomic.h>
 
void setMillis(unsigned long ms)
{
    extern unsigned long timer0_millis;
    ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {
        timer0_millis = ms;
    }
}

Esta función te permite cambiar el valor de millis de tal forma que no haya que esperar dias para comprobar si funciona o no, tan solo tienes que probar un valor de millis cercano al desbordamiento.

Si tu problema es que cuando pasan los 49 días deja de funcionar, no es un problema de desborde, la función millis vuelve a cero, pero tu comparación : millis() - cr1On >= 64800000 , no se cumple en ningún momento porque el ultimo valor que tiene cr1On es altísimo, cercano a los 49 días, y la diferencia siempre es negativa. Matemáticamente deberías utilizar la función modulo abs( millis() - cr1On )>= 64800000 de ese modo la diferencia es siempre positiva.

Saludos

Gracias por su pronta respuesta victorjam y PeterKantTropus y tratare de ser mas cuidadoso con el foro y disculpen.

PeterKantTropus voy a probar con tu segurencia. gracias!

No es por llevarte la contraria Peter, pero ¿cuando has visto que usemos abs en un timer?

La respuesta es NUNCA. Siempre se ha de usar como lo ha usado en su código y usando variables unsigned long.

¿Por qué funciona millis?

Imagina que mil segundos antes de desbordarse tomamos el valor de millis y lo guardamos en cr1On. Tenemos que millis será:

4 294 967 295 - 1 000 000 = 4 293 967 295

En hexadecimal será:

FFFFFFFF - 000F4240 = FF F0 BD BF

Desde eso momento, pongamos que pasan 2000 segundos desde que totamos el valor con lo que millis debe valer 1000 segundos (1000 que faltaban, se desborda a 0 y mil segundos que vuelven a pasar son los 2000 segundos en total).

1000000 = 000F4240

Cuando hacemos millis()-cr1On la resta es:

000F4240 - FFF0BDBF = 001E8481 (2000001)

Oh! Magia!

Se me ha colado 1 ms, y basicamente es porque no tuve en cuenta que en realidad millis valdrá 999999, el cero también cuenta.

¿Qué ha ocurrido? El resultado de la resta debe ser un número negativo, pero estamos utilizando enteros largos sin signo, con lo que el bit de signo no se tiene en cuenta.

Por eso millis funciona siempre.

En cambio si usas abs, no sé como se comportará el compilador, pero posiblemente tratará de convertir el unsigned a signed (1 bit de signo, 31 de datos), con lo que se pierde precisión ya que el se tomará el ultimo bit como bit de signo, asi que a saber lo que haga.

Por ejemplo FF F0 BD BF, es el valor que tomará variable, si la convierto a entero, y le quito es signo será 8F F0 BD BF.....

Tenes razón, cuando en un caso parecido (no con millis), me paso, había utilizado variables con signo.