Forma corretta di millis()

Ciao a tutti, mi domandavo se questa sia la forma corretta di usare la funzione millis()

if ((millis() - tempo_precedente) > intervallo) { 
tempo_precedente = millis();
// Eseguo qualcosa 
}

Oppure è meglio usare questa forma?
Potete spiegarmi perchè la seguente forma risulta essere migliore rispetto alla precedente e perchè non è indicata nemmeno negli esempi di Arduino?

if ((millis() - tempo_precedente) > intervallo) { 
tempo_precedente += intervallo;
// Eseguo qualcosa 
}

In realtà è più sicura la prima forma perché in questo modo non risente dell'overflow di millis() a patto che le variabili in questione siano dichiarate del tipo giusto ovvero unsigned long

Le due forme sono uguali per quanto riguarda l'overflow e sono corrette.
La differenza, invece, sta nel fatto che la seconda non risente dei tempi di esecuzione, perciò è più precisa:

if ((millis() - t_prec) > intervallo) { 
t_prec = millis();
// Eseguo qualcosa 
}

if ((millis() - t_prec) > intervallo) { 
t_prec += intervallo;
// Eseguo qualcosa 
}

Nel primo caso, t_prec viene aggiornato a millis(), che ha un istante di ritardo, tanto più se non viene messa come prima operazione da eseguire; nel secondo caso, invece, viene sommato sempre l'intervallo indipendentemente da eventuali ritardi. Considera che
millis() = t_prec+intervallo
infatti nel primo caso si ha:
t_prec = millis()
e nel secondo:
t_prec = t_prec+intervallo

@cotestatnt
Ti ringrazio , mentre queste due forme sono identiche?

if ((millis() - tempo_precedente) > intervallo) { 
tempo_precedente = millis();
// Eseguo qualcosa 
}

//ho solo tolto le parentesi

if (millis() - tempo_precedente > intervallo) { 
tempo_precedente = millis();
// Eseguo qualcosa 
}

Sì.

Grazie mille, @Datman
solo un altra delucidazione riguardo millis().
Se io volessi accendere un led rosso subito e non dopo trascorso del tempo e mantenerlo acceso per 10 secondi, successivamente spegnere questo led ed accenderne uno di colore verde per 30 secondi e mantenere questo "loop" finché una variabile non cambia di stato, come potrei fare?
Ho bisogno di 3 costrutti if con millis() separati?

Devi usare due variabili

@Datman Ok, ma per far si che io possa accendere il led rosso immediatamente per poi spengerlo dopo 10s se uso un digitalWrite all'interno del loop o di una funzione, il led rosso non si spegnerà mai...

Puoi anche fare così:

if(millis()-t0<=10000) {// Rosso acceso}
else {// Verde acceso}
if(millis()-t0>=30000) t0=millis();

Giusto, ho scritto una boiata :sweat_smile:

@Datman Funziona grazie, il fatto che ci sia il segno <= nel primo if comporta qualcosa per quanto riguarda l'overflow? Volendo il tempo di accensione del led verde può diventare di circa due ore?

#define  ledrosso 7
#define  ledverde 6
unsigned long t0 = 0;
void setup()
{
  pinMode(ledverde, OUTPUT);
  pinMode(ledrosso, OUTPUT);
}

void loop()
{
blink();
}

void blink() {
if(millis()-t0<=5000) {// Rosso acceso
digitalWrite(ledrosso,HIGH);
digitalWrite(ledverde,LOW);
}
else {
digitalWrite(ledrosso,LOW);
digitalWrite(ledverde,HIGH); 
}
if(millis()-t0>=20000) {
t0=millis();
}
}

Tra < e <= c'è solo la differenza di ciò che deve accadere in quel millisecondo in cui sono uguali.
Aggiusta l'indentazione nel blink!

@Datman No intendevo dire se scrivo <= invece di >= nel if che contiene millis() questo creerà problemi con l'overflow di quest'ultimo?

Se volevi che alla chiusura di un interruttore, la funzione blink() riparta sempre dal led rosso posso fare una cosa del genere ponendo t0 = millis()? Posso far rimanere acceso il led verde anche per 2 ore senza incorrere a problematiche?

Cosi:


#define  ledrosso 7
#define  ledverde 6
#define  slidersw 8
unsigned long t0 = 0;
bool switch_sw;
void setup()
{
  pinMode(ledverde, OUTPUT);
  pinMode(ledrosso, OUTPUT);
  pinMode(slidersw, INPUT_PULLUP);

}

void loop()
{
switch_sw = digitalRead(slidersw);
  if (switch_sw == true) {
  blink();
  }
  else {
  t0 = millis();
  digitalWrite(ledrosso,LOW);
  digitalWrite(ledverde,LOW); 
  }
}

void blink() {
if(millis()-t0<=5000) {
  digitalWrite(ledrosso,HIGH);
  digitalWrite(ledverde,LOW);
}
  else {
   digitalWrite(ledrosso,LOW);
   digitalWrite(ledverde,HIGH); 
}
  if(millis()-t0>=20000) {
  t0=millis();
 }
}

No (purché la condizione abbia senso).

Il tempo gestibile con millis "in un colpo solo" è di circa 1192 ore (con un errore di circa 5 secondi all'ora).

Si, però è meglio tenere tutta la logica del lampeggio dentro la stessa funzione:

void loop() {
  switch_sw = digitalRead(slidersw);
  blink(switch_sw == HIGH);
}

void blink(bool x) {
  if (!x) {
    t0 = millis();
    digitalWrite(ledrosso, LOW);
    digitalWrite(ledverde, LOW);
  } else {
    if (millis() - t0 <= 5000) {
      digitalWrite(ledrosso, HIGH);
      digitalWrite(ledverde, LOW);
    } else {
      digitalWrite(ledrosso, LOW);
      digitalWrite(ledverde, HIGH);
    }
    if (millis() - t0 >= 20000)
      t0 = millis();
  }
}

@Claudio_FF non capisco la sintassi if(!x). Cioè passi il risultato del digitalRead alla variabile x della funzione blink() , ma se x non è inizializzato a 0 come fa a funzionare? Potresti spiegarmelo? :grinning:

if(x) equivale a if(x!=0), cioè se ha un valore non nullo;
if(!x) equivale a if(x==0)

Passo il risultato del confronto tra switch_sw e HIGH (o 1 o true che è la stessa cosa). Il confronto può risultare vero (1) o falso (0), e questo è il valore assegnato a 'x'.

L'espressione !x vuol dire il contrario logico di x, quindi se x è 0 il contrario è 1 e quindi vero. Il significato finale dell' if è: "se x è zero".

Che vuoi dire?... in blink è dichiarata bool x:

void blink(bool x) {

E comunque non è una variabile qualsiasi
È un parametro della funzione
È garantito che sia sempre valorizzata, altrimenti lo senti il compilatore: ti picchia con la catena (toolchain)

1 Like

:joy: :joy: :joy:

Guglielmo