[Risolto] Gestire il rollover di Millis()

Salve a tutti,
In un applicazione ho una funzione che fa girare un motore stepper per un tot di tempo.

previousMillis = millis();
delay(10);
while (millis() - previousMillis <= tempo) {
    digitalWrite(StepperStepPins[i], HIGH);
    delay(velocity);
    digitalWrite(StepperStepPins[i], LOW);
    delay(velocity);
  }

Funziona tutto a meraviglia, ma questo approccio non mi tutela in caso di rollover di millis(). La mia preoccupazione è che, nel caso millis() si riazzeri dopo la riga previousMillis = millis() la condizione nel while si trovi verificata per molto più tempo, con conseguente loop che, se ho ben capito, può durare fino a diversi giorni.

Son in cerco di una soluzione che mi permetta di evitare il problema senza comportare un errore nel conteggio del tempo, ovvero di muovere il motore per un tempo diverso da quello programmato.

Avevo pensato di gestire la cosa con una condizione ad inizio while:

if (millis < previousMillis){
     previousMillis = millis - ( 4294967296 - previousMillis;
}

Che però potrebbe restituire valori di previousMillis negativi, e quindi comunque eseguire il while per più tempo del previsto (Anche se non per giorni interi, che mi pare già un miglioramento xD).

A questo punto sono discretamente confuso, spero possiate indirizzarmi verso una soluzione :slight_smile:

Grazie a tutti,
Marco

Buongiorno,
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione il su citato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

P.S.: Se fai un po' di ricerche qui sul forum Italiano se ne è parlato solo ... qualche migliaio di volte :smiley: :smiley: :smiley:

Mi spiace circa la violazione del regolamente in merito alla presentazione: Ero un utente anni fa, ma non ho postato per qualche anno. Ieri sera mi ha stupito il dovermi registrare di nuovo per accedere e non ho pensato che avrei dovuto riespletare tali formalità. Rimedio subito.

Circa la mia domanda: Comprendo perfettamente la disponibilità di soluzioni attualmente in circolo, ma fatico a trovarne una attinente alla mia implementazione, o forse è più giuso dire che fatico a capire come trasformare quelle soluzioni nella forma a me necessaria:

Il mio codice lavora sul concetto del "finché non è passato il tempo richiesto, esegui queste azioni", mentre l'implementazione "rollover-proof" che trovo in rete è sostanzialmente di questo tipo:

unsigned long currentMillis = millis();
 
  if (currentMillis - previousMillis >= interval) {
  previousMillis = currentMillis;
//Fai cose
}

Questo tipo di codice esegue l'if solo quando l'intervallo è trascorso, e non nel mentre.

Se trasformassi quell' if in un while

unsigned long currentMillis = millis();
 
  while (millis()- previousMillis >= interval) {

  //Fai cose

}

Il mio codice sarebbe eseguito sempre, da qui l'idea di cambiare la logica in

unsigned long currentMillis = millis();
 
  while (millis()- previousMillis <= interval) {

  //Fai cose

}

Che, appunto, apre al problema del rollover.

Capisco che il mio quesito si origini da un problema di comprensione della logica delle cose, ed immagino sia davvero molto sciocco, ma non riesco sinceramente a congiungere i puntini mancanti per la sua risoluzione.

Usa la forma canonica e invece di fare cose gli dici di smettere di farle, del tipo:

setup
{
  eseguicose = true;
  previousMillis = millis();
}
loop
{
  if(eseguicose)
  {
    ...fai cose...
   }
   if (millis() - previousMillis >= interval)
   {
      eseguicose=false;
   }
   
}

in realtà l'if non serve neppure potresti assegnare il not dell'espressione alla variabile eseguicose ma per rendere il codcie comprensibile ho scritto per esteso

Biska:

previousMillis = millis();

while (millis() - previousMillis <= tempo) {
  ...
 }



Funziona tutto a meraviglia, ma questo approccio non mi tutela in caso di rollover di millis().

Al contrario. Usando variabili unsigned long il tempo trascorso calcolato con quella sottrazione viene sempre giusto anche in caso di rollover.
Esempio: previousMillis vale il massimo (4294967295), dopo due millisecondi millis restituisce il valore 1
Sono trascorsi 1 - 4294967295 = 2 millisecondi

infatti, è tutelato a prescindere dato che ha impostato l'utilizzo di millis() correttamente.
Poi il fatto di salvare millis() in una variabile (currentMillis) e poi interrogarla al momento del bisogno facendo riferimento a QUEL momento (mi riferisco al momento dell'assegnazione del valore di millis alla variabile) piuttosto che utilizzare direttamente millis() al momento in cui esegue la funzione è questione di gestione personale del programma.
Nel caso di specie (dovendo pilotare uno stepper) NON utilizzerei currentMillis, ma lascerei il codice come postato al post #1.

Grazie a tutti per i suggerimenti :slight_smile:

Il mio cervello si è fatto un facepalm da solo e dall' interno xD