sábado, 29 de diciembre de 2018

Arduino desbordamiento con millis()

millis(); devuelve el número de milisegundos (ms) desde que la placa Arduino empezó a ejecutar el sketch y tenindo en cuanta esto podemos tener un problema de desbordamiento a la hora de sumar dos variables unsigned long para compararlas.

Una variable  unsigned long no puede superar los 4.294.967.295. Por eso aproximadamente cada 50 días el reloj internos que nos entrega el valor de millis al llegar a 4.294.967.295 se reinicia y nuevamente empieza a contar desde 0.

Imaginemos que nuestro sketch se empezó a ejecutar hace 10 minutos que son 600.000 ms y justo en ese instante le pedimos que encienda un led durante 2 segundos, no tendríamos ningún problema, puesto que cuando millis llegue a 602.000 ms lo apagara.

Entonces que pasaría si nuestro sketch se empezó a ejecutar hace 4.294.967.000 ms pues que 4.294.967.000 + 2.000 son 4.294.969.000 ms,  y como hemos dicho una variable unsigned long solo puede almacenar hasta 4.294.967.295 ms. Esto nos provocaría un desbordamiento y el sketch fallaría.

Para proteger nuestro sketch de un desbordamiento, antes de sumarle al valor obtenido por millis (4.294.967.000ms) los 2 segundos que queremos que mantenga el led encendido (2000ms), tenemos que saber si a esa variable es capad de almacenar esa cifra para no provocar un desbordamiento. Para ello, al valor máximo que puede almacenar un unsigned long 4.294.967.295 le tenemos que restar el valor que nos ha entregado millis(); y el resultado obtenido es el numero máximo de ms que podemos sumarle a los millis(); obtenidos sin que se produzca un desbordamiento.

[valor máximo de un unsigned long] - [valor entregado por millis();] = [Es el numero máximo de ms que podemos sumar]

4.294.967.295 - 4.294.967.000ms = 295ms

Entonces deberíamos de utilizar algún if o algo para asegurarnos de que no se nos va a producir un desbordamiento al usar millis:



unsigned long nUnsignedLong = 4294967295; //Cifra máxima almacenable en un unsigned long
unsigned long Lectura = millis();//valor obtenido desde millis
unsigned long tiempo = 2000; //Cuanto tiempo queremos esperar o lo que sea


if ( (nUnsignedLong - Lectura) > tienpo ){
  
 //No producirá un desbordamiento 
 
}
else {
  //produce un desbordamiento
}



Incluso si ya sabemos que se nos va a desbordar, podemos anticiparnos y calcular cuando se tiene que apagar el led del que halábamos incluso evitando el desbordamiento:

4.294.967.295 - 4.294.967.000ms = 295ms

2000 (tiempo encendido) - 295 = 1705ms

Nuestro led se tendría que apagar cuando millis llegue a los 1705ms

Con lo cual tendría que utilizar algo similar a esto para compensar  el resultado:


unsigned long nUnsignedLong = 4294967295; //Cifra maxima almacenable en un unsigned long
unsigned long Lectura = millis();//valor obtenido desde millis
unsigned long tiempo = 2000; //Cuanto tiempo queremos esperar o lo que sea
unsigned long ApagaLed = 0; //Cuado apagara el led...

if ( (nUnsignedLong - Lectura) > tienpo ){
  
 //No producira un desbordamiento 
 ApagaLed = Lectura + tiempo;
 
 
}
else {
  //Compensamos el desbordamiento
  
  ApagaLed = tiempo - (nUnsignedLong - Lectura);
}



No hay comentarios:

Publicar un comentario