paso por cero funcion millis (solucionado)

Hola grupo, aprovecho para presentarme, soy Jose María desde Barcelona.
Estoy comenzando a desarrollar en Arduino, y mi primera aplicación trata de comunicar un pc con un Arduino.
Utilizo la funcion millis() para generar una alarma si pasado un tiempo no recibo ninguna trama, pero me preocupa el tema del paso por 0 de la función; para no esperar los 50 dias aprox que puede tardar en generarse el caso os presento mi solución para ver si la veis correcta y puede servir para todo el mundo.
La idea es esperar a que la funcion millis sobrepase el valor del timeout, mientras esta devuelva un valor menor que el timeout no hacemos nada, solamente registramos el valor actual.
Os pego el código y a ver que opinais.
Gracias por adelantado.

unsigned long ulTimeout = 5000; //variable de control timeout (5 segundos)
unsigned long ulActual = 0;  //auxiliar control timeout



void setup() {  

  Serial.begin(115200); //velocidad comunicacion puerto serie  
  
  ulActual = millis();  
  
  
}



void loop() {
  
  
  //control llegada de tramas, si en 5 seg. no llega trama completa activar led
  if (millis() <= ulTimeout){ 
    ulActual = millis();
  }
  else{
    if (millis() - ulActual >= ulTimeout){
      digitalWrite(iPinAlarmaTimeout,HIGH); //activar pin
    }  
    else{
      digitalWrite(iPinAlarmaTimeout,LOW);  //desactivar pin       
    }
    
  }

Hola jmaria bienvenido.

mírate este post en el cual encontraras varias soluciones a tu inquietud del desborde de millis()

http://forum.arduino.cc/index.php?PHPSESSID=6hvp1mu4ktkpnqo3fssd1pldf5&topic=236010.msg1706229#msg1706229

Saludos

Hola,

Ya me sabrás perdonar, pero no veo que el programa que mandas haga otra cosa que encender un pin a los 5 s de puesto en marcha. ¿A qué te refieres con las "tramas"?. ¿Y con su "llegada"?.

Saludos

una idea por si te vale.

unsigned long ulTimeout = 5000; //variable de control timeout (5 segundos)
unsigned long ulActual = 0;  //auxiliar control timeout
unsigned long ulMillis = 0;  //auxiliar control timeout


void setup() {  

  Serial.begin(115200); //velocidad comunicacion puerto serie  

  ulActual = millis() + ulTimeout;  // Tiempo en que saltara la alarma
  
  
}



void loop() {
  
  ulMillis=millis();
  if (llego_La_trama) {ulActual = millis() + ulTimeout;}  // Pon tu la condicion
  //control llegada de tramas, si en 5 seg. no llega trama completa activar led
  if (millis() > ulActual ){ 

      digitalWrite(iPinAlarmaTimeout,HIGH); //activar pin
    }  
    else{
      digitalWrite(iPinAlarmaTimeout,LOW);  //desactivar pin       
    }
    
   if (ulMillis>millis())            // millis ha desbordado
   {
     ulActual = ulActual - ulMillis + millis();  // Nuevo timpo para alarma
   }
  }

Se que no tiene mucho que ver y que tal vez suene hasta entrometido… pero ¿porque usar esto?:unsigned long ulTimeout = 5000;

Pudiendo usar esto que te ahorra memoria y es más correcto:const int ulTimeout = 5000;

En cuanto al código para detectar el desbordamiento… yo propondría algo muy parecido a lo que ha puesto marcial, solo cambiaría un detalle:

const int ulTimeout = 5000; //variable de control timeout (5 segundos)
unsigned long ulActual = 0;  //auxiliar control timeout



void setup() {  

  Serial.begin(115200); //velocidad comunicacion puerto serie  

  ulActual = millis() + ulTimeout;  // Tiempo en que saltara la alarma
  
  
}



void loop() {
  

  if (llego_La_trama) {ulActual = millis() + ulTimeout;}  // Pon tu la condicion
  //control llegada de tramas, si en 5 seg. no llega trama completa activar led
  if (millis() >= ulActual ){ 

      digitalWrite(iPinAlarmaTimeout,HIGH); //activar pin
    }  
    else{
      digitalWrite(iPinAlarmaTimeout,LOW);  //desactivar pin       
    }
    
   if (ulTimeout + milis() < ulActual)            // millis ha desbordado // esto ha cambiado
   {
     ulActual = ulTimeout - milis()  // creo que de esta forma es mejor porque uso una variable long menos, aunque he de decir que esto yo solo lo usaría para valores de timeout mayores a 100
   }
  }

Daklon:

Entrometido es el que se mete para incordiar, el que lo hace para optimizar y lo hace bien lo que merece es un aplauso ;) Me gusta tu solución.

Yo no tengo ahora mismo el arduino a mano, pero por si queréis comprobar los códigos, se podrían definir todas las variables de los códigos unsigned long como unsigned int, de forma que podamos tener desbordes cada 65536 milisegundos (un minuto y poco).

Y ya puestos, yo abogo por otro sistema, hala :P :grin: :grin: :grin: :grin:

const unsigned int uTimeout=5000;
unsigned int uActual=0;

void setup() {
      Serial.begin(115200);
      uActual=millis()+uTimeout;

}

void loop() {

      if(Serial.available())
            uActual=millis();
      unsigned int uTranscurridos=millis()-uActual;
      if(uTranscurridos>uTimeout){
            digitalWrite(13,HIGH);
      } 
      else {
            digitalWrite(13,LOW);
      }
}

Hola compañeros, este es el segundo post que envío, creo que el anterior se ha perdido, tenia el correo a medias antes de la comida, al volver lo he terminado, le he dado a enviar y ha desaparecido (algun timeout habra actuado, jeje).

Ante todo agradeceros el soporte , y paso a comentar las propuestas.

1.- Declaro simplemente ulTimeout como unsigned long por coincidencia con el tipo que devuelve la funcion millis(), simplemente por desconocimiento, lo encontré lógico en su momento

unsigned long ulTimeout = 5000;

2.- En cuanto al código, mi preocupación es la de cuando la función millis está cerca del final, cuando le queden menos de 5 segundos en mi caso para volver a cero.
Por lo que la instrucción:

 ulActual = millis() + ulTimeout;  // Tiempo en que saltara la alarma

provocará ya un overflow, entiendo que en el código que propongo no hay suma que lleve a este.

3.- En cuanto al numero de variables, creo que tanto Dakon cómo Marcial declaran una mas, sin acritud.

Supongo que, como es tipico en mi, me habré dejado algún caso por revisar, os posteo de nuevo el código, en este caso con la parte de lectura del puerto serie, que creo que ayuda a una mejor comprension.

unsigned long ulTimeout = 5000; //variable de control timeout (5 segundos)
unsigned long ulActual = 0;  //auxiliar control timeout



void setup() {  

  Serial.begin(115200); //velocidad comunicacion puerto serie  
  
  ulActual = millis();  
  
  
}



void loop() {
  
  
  //control llegada de tramas, si en 5 seg. no llega trama completa activar led
  if (millis() <= ulTimeout){ 
    ulActual = 0;
  }
  else{
    if (millis() - ulActual >= ulTimeout){
      digitalWrite(iPinAlarmaTimeout,HIGH); //activar pin
    }  
    else{
      digitalWrite(iPinAlarmaTimeout,LOW);  //desactivar pin       
    }
    
  }  

  if (Serial.available() > 0) {   //leer caracteres puerto serie, almacenar en mTrama
    c = (char)Serial.read();   
    mTrama[i] = c;
    i++;
    ulActual=millis();    
    
   
  }

Hola.
Yendo por partes, a mí me parece correctísimo que declares como unsigned long ulTimeout, pues los casting que hace arduino al operar con distintos tipos de datos pueden darnos algún susto. Lo qué sí es buena práctica es anteponer const si se trata de una constante, pues además de ahorro de memoria, el compilador te avisará si te despistas e intentas modificarla.
Por otro lado, no termino muy bien de comprender por qué pones al principio

if (millis() <= ulTimeout){
ulActual = 0;
}

Creo que lo que haces es que cuando detectas un overflow, comienzas a contar desde cero, descartando el tiempo parcial que transcurrió desde el último ulActual hasta ese desbordamiento, ¿no? Entonces, si no calculo mal y antes del desbordamiento ya estabas en timeout, durante los cinco primeros segundos después del desbordamiento no estarás en timeout aunque sigan sin llegar caracteres.
El código que puse en mi post anterior creo (aunque no lo parezca a primera vista) que sí se comportaría bien incluso con desbordamiento de por medio.

Cierto.. no tuve en cuenta el tema del casting...

El tema del overflow... tanto el código de marcial, como el de noter, como el mío tiene en cuenta el overflow y no solo eso sino que si el overflow ocurre a mitad de un timeout no vuelve a contar desde 0 sino solo el tiempo restante (a ojos "del mundo" no ocurre overflow)

jajaja muy bien pensado, me gusta tu solución noter xD

De todas formas para comprobar si funciona correctamente, puedes probar con micros() que tarda unos 70 minutos en desbordar y devuelve el mismo tipo de datos, vamos que es practicamente igual

Hola compañeros, gracias por el apoyo.

Siguiendo con el tema, noter me pregunta por la condición
if (millis() <= ulTimeout){
ulActual = 0;
}

y, creo que tiene toda la razón, cuando millis() haya recomenzado he de poner , a mi entender, lo siguiente:
ulActual = ulTimeout - (2 ^32 -1 -ulActual)
en lugar de ulActual=0.

Por otro lado, viendo vuestro codigo acabo de darme cuenta que un unsigned es circular, que es lo que aprovecha noter en su codigo, por lo que parece que puedo quitar mi condición
if (millis() <= ulTimeout){
ulActual = 0;
}

y todo funcionaría, estoy en lo correcto?

He hecho la suposición siguiente:
Supongamos que tenemos un entero sin signo de 10 bits, este se moverá entre 0,1,…,1023,0,1,…
Supongamos que empiezo a contar en 1020, que el timeout esta en 10 unidades y que la funcion millis() me devuelve un 3.

Por lo que si hago la operacion 3 - 1020 el resultado será 7, y la condición
if (millis() - ulActual >= ulTimeout){
será siempre válida.

Gracias por vuestros comentarios.

Perfectamente explicado ;). Puedes corroborar, si quieres, la suposición que propones, aunque no precisamente con 10 bits, porque no es un tipo de datos estándar, pero sí con unsigned long, que es el tipo que nos interesa.

unsigned long a=0xfffffff0;
unsigned long b=0xf;
unsigned long c=b-a;
Serial.println(c,HEX);

Hola grupo, solamente un último post para agradeceros el soporte, y de paso ya me quedo por aqui por si puedo ser de ayuda a alguien. (no se si debería cerrar de alguna manera este diálogo o es tema de los moderadores, podeis aclarame al respecto?)

Gracias y un saludo.

José María.

Con que cambies el título del tema y pongas al final algo como [solucionado] será suficiente xD

Solo agregá al titulo (SOLUCIONADO) para que otros lean que se llegó a algo