Temporizzatore con millis per tempi lunghi

Come da oggetto dovrei fare una specie di temporizzatore per luci scale. Ogni volta che la luce si accende salvo il valore millis() in time_uscita_attivata. Poi se il tempo (differenza tra time attuale e time di quando avevo acceso la luce) supera 1 minuto forzo il reset dell'uscita.

... Dopo aver mandato alta l'uscita ...
time_uscita_attivata = millis();
...
if (millis()-time_uscita_attivata[13] >=60000) resetta_uscita(13);
La domanda è questa: può creare problemi un tempo così lungo ? Vorrei evitare di aggiungere un RTC !
Seconda domanda: cosa succede se millis arriva al valore max e ritorna a zero ? Secondo me non si resetta più l'uscita perchè otterei un valore negativo che è sicuramente minore di 60000! Come posso risolvere ? GRAZIE

se non si tratta di tempi troppo lunghi (giorni o settimane) il millis va più che bene.
la funzione millis() restituisce un long int quindi un tipo di dato a 32 bit che può contenre quindi numeri che vanno da -2147483648 a 2147483647.
Approssimativamente 2 miliardi di ms sono 2 milioni di sec quindi 555 ore.

Io l'ho dichiarato come unsigned long quindi dovrebbero essere anche 4 milioni di secondi praticamente ogni 50 giorni si azzera ... il problema è che se io accendo la luce proprio quel giorno quando mancano 10 o 20 secondi (per esempio) all'azzeramento, la luce non si spegne più perchè avrei qualcosa del tipo:

20000mS - 3900000000mS = -3899980000mS che è sicuramente minore di 60000mS !!! :frowning:

si questo è vero!

puoi verificare che il valore di millis cresca sempre. perchè nel caso diminuisce anzi è pari a zero dovrai fare un paio di calcoli per modificare la tua time_uscita_attivata[13]

per ora faccio così:

if ((millis()-time_uscita_attivata[13] >=60000)||(millis()-time_uscita_attivata[13] <=0)) resetta_uscita(13);

non è il massimo perchè comunque nel caso di azzeramento del millis resetto l’uscita prima dello scadere dei 60 sec … meglio di niente

Se avete altre idee fatevi avanti ! Grazie !

Ciao Ambrogio,
non so se hai già risolto il problema ma potresti fare una cosa.
Il millis sarà sempre più grande della tua variabile almeno che non si azzeri: in tal caso diventerà minore…
A questo punto metterei un if prima della istruzione da te scritta.
In altre parole qualcosa del genere:

void setup(){
   ....
   tmp=0;
   ....
}

void loop(){
   tempo_trascorso= millis()-time_uscita_attivata[13];
   if(tempo_trascorso<0){
      tmp=tempo_trascorso-2*tempo_trascorso;
      time_uscita_attivata[13]=0;
   }
   if(tempo_trascorso+tmp>60000){
      resetta_uscita[13];
      eventualmente_riazzera_tmp_a_seconda_del_tuo_programma;
   }
}

Tieni conto che è da testare ma con qualche accorgimento dovrebbe funzionare.
Facci sapere ok?

Mi sembra strano … non capisco perchè hai moltiplicato per 2 … Forse ho trovato la soluzione, dimmi se secondo te può andare … con la calcolatrice funziona !

void setup(){
   ....
   ....
}

void loop(){
   tempo_trascorso= millis() - time_uscita_attivata[13];
   if(tempo_trascorso < 0) tempo_trascorso = tempo_trascorso + 4294967295;
   if(tempo_trascorso > 60000) resetta_uscita[13];
}

Facciamo due esempi:
Caso normale (time_uscita_attivata[13] = 1000 e millis() = 1500)
tempo_trascorso = 1500 - 1000 = 500

Caso limite (time_uscita_attivata[13] = 4294967095 e millis() = 300)
tempo_trascorso = 300 - 4294967095 = -4294966795 <— Siccome è negativo aggiungo 4294967295
tempo trascorso = -4294966795 + 4294967295 = 500 !!!

4294967295 non è un numero a caso ma è il numero massimo che può raggiungere millis()

Ora però mi rimane un dubbio: dichiarando le variabili come unsigned long l’Arduino riesce a fare quella somma ?

Ma sai che forse mi sono fatto un sacco di problemi per niente !!! Ho provato ad eseguire questo codice e il serial monitor mi restituisce 501 !!! Non so perchè 501 e non 500 ... però probamilmente va già bene così ! L'unsigned long non può restituire valori negativi, quindi se ho un valore basso e continuo a decrementare, otterrò una cosa di questo tipo:

...
3
2
1
0
4294967095
4294967094
4294967093
...

   unsigned long tempo_trascorso;
   unsigned long toff = 300;
   unsigned long ton = 4294967095;
   
void setup(){
   Serial.begin(9600);
}

void loop(){
   tempo_trascorso = toff - ton;
   Serial.println (tempo_trascorso);
   delay (2000);
}

EDIT:

ok, ti confermo che è così perchè se eseguo il seguente codice ottengo dal serial monitor:

10
9
8
7
6
5
4
3
2
1
0
4294967295
4294967294
4294967293
4294967292

   unsigned long contatore = 10;
   
void setup(){
   Serial.begin(9600);
}

void loop(){
   Serial.println (contatore);
   contatore = contatore - 1;
   delay (2000);
}

Grazie a tutti ! Spero che possa essere utile a qualcuno !

Ottimo.
Il realtà ciò che era negativo non era tanto millis quanto la differenza tra millis e la variabile.
Cmq molto utilequello che hai scritto.
Thanks!