conversione funzione da delay a millis()

Vorrei realizzare l'equivalente di questa funzione che svolga le seguenti operazioni, usando la funzione millis() al posto di delay:

void invertiCiclo(long ritardo, boolean modalita)
 {
 digitalWrite(FAN, LOW);
 delay(ritardo);
 digitalWrite(RELE, modalita);
 delay(ritardo);
 digitalWrite(FAN, LOW);
 }

c'ho sbattuto la testa un paio di giorni senza ricavarne risultati, e sarei grato a chiunque sia in grado di darmi una dritta su come impostare la stesura di tale funzione.

Ciao Federico, non ho arduino sotto mano e quindi vado a spanne.
Se sbaglio la sintassi perdonami.
Proverei così:

unsigned long time_inverticiclo;
unsigned long time_rele;
unsigned long now;

void setup(){
  now=millis();
  time_inverticiclo=millis();
  time_rele=millis();
}

void loop(){

  now=millis();   // Ad ogni loop aggiorna il now

  //pezzi di codice...

    invertiCiclo(500,1);    // Forse va dentro un IF? Non è indispensabile

  //pezzi di codice...

}
void invertiCiclo(long ritardo, boolean modalita)
 {
  digitalWrite(FAN, LOW);
  if(time_inverticiclo+ritardo<=now){  // Se il time+ritardo è minore di now
                                                  // vuol dire che è passato il ritardo
    digitalWrite(RELE, modalita);
    time_inverticiclo=millis();            //Questo è il passo più importante:
                                                 // aggiornamento del millis();
  }
  if(time_rele+(ritardo*2)<=now){
     digitalWrite(FAN, LOW);              // Forse qui volevi scrivere HIGH? 
     time_rele=millis();
  }
 }

E' da testare ma la via dovrebbe essere quella...

Innanzitutto grazie mille, anzi millis!!! :smiley:

Purtroppo non potrò provarlo fino a lunedi, però leggendo la tua proposta a me sembra che:

"time+ritardo" sia sempre minore di "now", quindi entra nell IF e aggiorna "time" fino a che "time+ritardo" supera "now", in quel caso esce.

E' così o continuo a sbagliare a capire?

perchè usi la variabile now?
non puoi direttamente chaimando millis nell'if?
si risparmia una variabile e quindi ram

@garinius, hai ragione: l'ho fatto per rendere più leggibile il codice.

@Federico, premesso che è sicuramente da provare, dovrebbe comunque andare bene. Ragioniamoci insieme (ma è possibile che mi sbagli io).

Sto ragionando con valori fittizi....
time e now sono inizializzati nel setup e valgono 1 (appena acceso...).
Dopo un po' now=2000 (son passati 2 secondi), time ancora 1 e gli dai un ritardo di 500.
Qundi time+ritardo=501<2000, entra nel if, spegne il LED e aggiorna time
Nel prossimo ciclo
time(2000 perchè aggiornato)+500=2500 > now (2001) NON entra nel IF finchè non sono passati 500 millisecondi.

A occhio dovrebbe andare bene.
Forse bisogna riguardare i tre IF uno dietro l'altro che si pestano i piedi ma come ottica dovremmo esserci...

ho testato la funzione scritta da nathanvi con la modifica proposta da garinus e funziona "quasi" come dovrebbe (GRAZIE).

Mi sono accorto di due piccole cose:

  • La prima istruzione eseguita

digitalWrite(FAN, LOW);

praticamente venendo continuamente eseguita, quando è passato un tempo 2*ritardo, va a sovrascrivere

digitalWrite(FAN, HIGH)

  • questa condizione invece si verifica 2 volte:

if(time_inverticiclo+ritardo<=millis()){
digitalWrite(RELE, modalita);
time_inverticiclo=millis();
}

Per quanto riguarda il secondo punto ho cercato di risolvere così:

unsigned long time_rele;
unsigned long time_fan;

void invertiCiclo(long ritardo, boolean modalita)
{
  boolean hold = 0;

  //digitalWrite(FAN, LOW);
  Serial.println("Ventola spenta");


  if(time_fan+(ritardo*2) <= millis()){
    //digitalWrite(FAN, HIGH);
    Serial.println("Ventola riattivata");
    Serial.println("----------------------");
    time_fan=millis();
    hold = 1;
  }

  if(time_rele+ritardo <= millis()){  
    if(hold == 0)
      Serial.println("Rele' invertito");
    //digitalWrite(RELE, modalita);
    time_rele=millis();      
  }

}

void setup()
{
  pinMode(FAN, OUTPUT);
  pinMode(RELE, OUTPUT);

  time_fan=millis();
  time_rele=millis();

  Serial.begin(9600);

  //digitalWrite(FAN, HIGH);
  //digitalWrite(RELE, LOW);
}

void loop()
{

 //pezzi di codice

  if(condizione)
    invertiCiclo(5000, HIGH);
 
 //pezzi di codice
  
}

mentre per il primo avrei pensato di far eseguire una sola volta l'istruzione che spegne la ventola ogni volta che viene chiamata la funzione, però ho notato che se inizializzo una variabile locale, siccome la funzione viene riaggiornata ad ogni loop, la variabile in pratica continua a essere continuamente inizializzata ad ogni ciclo

Ciao Federico, allora ci stiamo avvicinando alla soluzione?
Ma quindi il problema rimane solo il fatto che la variabile si resetta ad ogni ciclo?
Se così è basta metterla globale fuori al loop oppure non ho capito :stuck_out_tongue:

Si, grazie sopratutto a te sono vicino alla soluzione ottimale.

In pratica la variabile "hold" torna a zero ad ogni ciclo, ma il problema è risolto nel codice che ho postato.

Testando la funzione con un "debug seriale" il tutto funziona, però se provo a testare le due uscite con due led, il led relativo alla ventola rimane sempre spento, adesso provo a testare meglio, se ci saranno cambiamenti li posto.

sono stato assente un po' ma questa mattina ho potuto fare ancora qualche prova...

ho notato che il problema principlale è che la ventola rimane sempre bassa, forse riceve solo un impulso alto appena entra nel ciclo che la riaccende, il resto è ok.

In pratica quello che vorrei è che quando si verifica una condizione venga eseguita questa funzione e che una volta usciti dalla funzione l'uscita della ventola sia alta.

  if(time_comp+(ritardo*2) <= millis()){
    time_comp = millis();
    digitalWrite(FAN, HIGH);
  } 
  else
    digitalWrite(FAN, LOW);

neanche con questa soluzione funziona.