Consiglio su come sostituire delay con millis

Posto il codice completo funzionante con il delay.

Ovviamente è solo una porzione di tutto lo sketch.

// funzione per la verifica dello stato di apertura della tenda
void StampaApertura()
{
  Ohm = (map(analogRead(sensore), 0, 1023, 0, 10000)); // Assegno la mappa alla variabile Ohm per la corretta lettura dello stato di apertura
  Apertura = (map((Ohm), 0, 10000, 0, 140));
}


         //Inizio apertura comandata tenda
          int char_pos_a = 0;
          int char_pos_b = 0;
          if (readString.startsWith("GET /?out=0&value="))
          {
            char_pos_a = readString.indexOf("value=");
            char_pos_b = readString.indexOf(" HTTP/1.1");
            String value = readString.substring(char_pos_a + 6, char_pos_b + 1);
            double value_int = value.toInt();
            {
              /*
                Serial.print("char_pos_a:");
                Serial.println(char_pos_a);
                Serial.print("char_pos_b:");
                Serial.println(char_pos_b);
                Serial.print("value contiene:");
                Serial.println(value);
              */
              if (value_int >= 0 && value_int <= 100)
              {
                if (value_int > Apertura)
                {
                  /*
                    Serial.print("Apro la tenda da posizione:");
                    Serial.print(Apertura);
                    Serial.print("% a posizione:");
                    Serial.print(value_int);
                    Serial.print("%");
                  */
                  digitalWrite(RCH2, LOW);
                  delay(1800); // Attendo 1,8 secondi prima di riposizionare il relè sullo stato iniziale.
                  //Operazione necessaria per simulare la pressione del tasto altrimenti la centralina non riceve correttamente il comando
                  digitalWrite(RCH2, HIGH);
                  while (value_int > Apertura)
                  {
                    StampaApertura();
                    //Serial.println(Apertura);
                  }
                  digitalWrite(RCH2, LOW);
                  delay(250); //Attendo 250 millisecondi prima di riposizionare il relè sullo stato iniziale, altrimenti la centralina non processa correttamente il comando
                  digitalWrite(RCH2, HIGH);
                  client.print(F("status ok"));
                  /*
                    client.print(value_int);
                    client.print(",Apertura:");
                    client.print(Apertura);
                  */
                }
                if (value_int < Apertura)
                {
                  /*
                    Serial.print("Chiudo la tenda da posizione:");
                    Serial.print(Apertura);
                    Serial.print("% a posizione:");
                    Serial.print(value_int);
                    Serial.print("%");
                  */
                  digitalWrite(RCH1, LOW);
                  delay(1800); // Attendo 1,8 secondi prima di riposizionare il relè sullo stato iniziale.
                  //Operazione necessaria per simulare la pressione del tasto altrimenti la centralina non riceve correttamente il comando
                  digitalWrite(RCH1, HIGH);
                  while (value_int < Apertura)
                  {
                    StampaApertura();
                    //Serial.println(Apertura);
                  }
                  digitalWrite(RCH1, LOW);
                  delay(250); //Attendo 250 millisecondi prima di riposizionare il relè sullo stato iniziale, altrimenti la centralina non processa correttamente il comando
                  digitalWrite(RCH1, HIGH);
                  client.print(F("status ok"));
                  /*
                    client.print(value_int);
                    client.print(",Apertura:");
                    client.print(Apertura);
                  */
                }
              }
              else
              {
                Serial.println(F("Valore fuori range"));
                client.print(F("Error, value out of range"));
              }
            }
          }
          //Fine apertura comandata tenda

ORSO2001: ...e la variabile t_tenda che valore ha all'inizio?

ziopippo: Grazie ma avevo dato per scontato di aver dichiarato

unsigned long t_tenda = 0; //Timer per la tenda
unsigned long push_timer = 0; //Timer per durata della pressione del tasto della tenda

ORSO2001: ciao...secondo me stai facendo una "bruttissima" cosa; hai in un if() con un while() annidato che verificano la stessa condizione...e dopo il while() esegui quella funzione della verifica tempo...tenda_slider().

in quel while c'è una sola funzione...StampaApertura()...spero che in essa ci sia la l'aggiornamento delle variabili value_int e Apertura...altrimenti non ci esci più...e comunque quando ci esci, dato che l'if() confronta la stessa cosa, esegui una volta la tua funzione tenda_slider() e poi !?

In che modo mi consigli di ottimizzarlo?

ciao...io ragionerei in questo modo...nello spezzone del tuo sketch verifichi se readString.sartsWith(....) ritorna true...se true appunto analizzi altre parti della Stringa ricevuta per ricavarne dei valori...ecco li io, invece di includere tutte le restanti azioni, imposterei una variabile globale (che tra le altre cose includere nella verifica di questo if in modo da non eseguire due volte la stessa azione) da 0 ad 1...con questa variabile ad 1 abilito una funzione od un pezzo di codice, esterno a questo if() che mi gestisca con millis() il digitalWrite()...magari il tempo di partenza di millis() l'ho salvato nella if della Stringa....eseguito il primo digitalWrite metto la stessa variabile a 2 e passo alla funzione StampaApertura...finita questa imposto la variabile a 3 e salvo ancora millis() ...con varibile a 3 eseguo il digitalWrite() di chiusura e finito anche questo imposto la variabile a 0.

non conoscendo tutto il codice e cosa deve fare di preciso mi viene in mente questo.

spero di esseremi spegato bene

Dovrò rileggerlo molto attentamente e più volte domani perchè ora non ho la lucidità per riuscire a capire a pieno quanto mi stai consigliando. E' un codice che scrissi nel lontano 2013 e solo da poco, dopo anni di pausa sabatica dalla programmazione causa lavoro, ho ripreso in mano cercando di modificarlo dopo aver "scoperto" millis. Se può esserti utile però poso allegare o, se lo preferisci mandartelo in privato, l'intero codice e volendo anche quello che stavo cercando sostituire con millis.

La funzione millis DA SOLA NON È LA SOLUZIONE se non si modifica anche la struttura del programma, trasformandola in macchine a stati finiti (quello che dice orso con altre parole).

Anzi, organizzando tutto come macchine a stati, per assurdo si può anche continuare ad usare delay, ma solo per piccoli tempi e/o per "regolare" il tempo di esecuzione del loop principale.

Si deve perciò pensare al programma non come sequenza monolitica di istruzioni (ritardi compresi) da eseguire dall'inizio alla fine in un colpo solo, ma spezzare invece l'esecuzione di tutte le parti in più passaggi ciclici, singolarmente molto veloci e senza ritardi di alcun genere.

La funzione loop potrebbe incaricarsi solamente di richiamare ciclicamente i vari processi (ad esempio circa 50 volte al secondo come nell'esempio seguente):

void loop(){
    processo1();
    processo2();
    processo3();
    delay(20);
}

Ogni processo può essere uno switch controllato da una propria variabile di stato:

void processo1(){
    switch(stato_proc1){
        case 0:
            break;
        case 1:
            break;
        case 2:
            break;
    }
}

In ogni case si può scrivere il frammento di codice da eseguire nello stato attuale, che deve:

  • Controllare se si verifica una certa condizione
  • Eventualmente eseguire qualche operazione
  • Eventualmente cambiare la variabile di stato

Con questa struttura un ritardo è semplicemente la permanenza in un certo stato per un certo numero di cicli. Si può ottenere con millis, o con un contatore che incrementa/decrementa ad ogni chiamata del processo, è -quasi- indifferente, quello che conta è che la logica sequenziale di una lunga funzione che monopolizza tutto il tempo si trasforma in una velocissima logica di controllo: rilevazione_evento->azione->cambio_stato. (Un esempio relativo alla rilevazione click/longpress di un pulsante)

Questo permette di:

  • Portare avanti N processi in parallelo in tempo reale
  • Aggiungere nuove funzionalità o processi indipendenti senza toccare quelli preesistenti
  • Scomporre una logica troppo complessa da affrontare tutta assieme in piccole macchine semplici, che inviano "segnali" alle altre tramite flag (esempio variabili globali)

@Claudio_FF

Ho li hai tramortiti, oppure è l'effetto delle feste (o entrambe). ;) Purtroppo ho costato più volte che quando tiri in ballo le macchine a stati finiti, l'utente rimane sconvolto. Mentre se gli suggerisci la funzione millis(), alla fine ne vengono fuori, si ma con un pastrocchio di if.

Comunque speriamo non siano rimasti tramortiti, ma solo sconvolti e che quindi a breve si riprenderanno, postando qualcosa. :)

Sempre in merito a FSM, qualche hanno addietro mi è venuta la fantastica idea di creare una applicazione basata su FSM facente uso di puntatori a funzione, la macchina ricordava anche lo stato precedente e in base a questo e ad altre flags decideva quale doveva essere lo stato successivo, fatto ciò, il break terminava la funzione e il controllo tornava al loop.

Dentro al loop venivano svolte alcune operazione cardine e poi c'era la chiamata a funzione tramite puntatore.

L'idea sembrava figa e funzionava alla grande, purtroppo dal punto di vista del programmatore seguire il flusso diventava macchinoso, sono andato nel pallone più volte, perché non sapevo chi decideva e quale sarebbe stata la funzione chiamata nel loop.

Allora ho implementato per ogni stato, le tre transizioni: A) Ingresso (poteva decidere se confermare lo stato o dirottarlo o abortire); B) Stato corrente: poteva decidere se e quando dirottare verso l'ultima transizione; C) Uscita da stato corrente: poteva o meno decidere il prossimo stato, se non lo faceva la macchina eseguiva una funzione standard. D) Abort opzionale: transizione alternativa scelta da A al posto di B.

Conclusione: 1) Implementare una macchina a stati finiti è divertente. 2) Usarla è un incubo 3) Sentivo la mancanza di un gestore di eventi che li catturasse.

Comunque speriamo non siano rimasti tramortiti, ma solo sconvolti e che quindi a breve si riprenderanno, postando qualcosa.

Gli ho dato la botta finale, non si riprenderanno mai più. :smiling_imp:

Ciao.

Né l'uno né l'altro @Maurotec. È solo l'effetto smartphone/tablet che ha inibito sin'ora la mia risposta. Nella versione che sto cercando di revisionare per l'appunto anche con la sostituzione del dalay a favore di millis ho rivisto un po' tutto spezzando il codice e creando diverse schede per una maggiore leggibilità. Il grosso problema resta però un buon pezzo di codice tra cui l'estratto che ho pubblicato che si occupa di rispondere alle richieste json per mostrare i dati su una app da me creata ad hoc su smartphone Android o direttamente facendo una specifica richiesta da browser Ovviamente con lo smartphone non ho possibilità di allegare codice

Maurotec: 1) Implementare una macchina a stati finiti è divertente. 2) Usarla è un incubo

Forse stiamo pensando a due diverse implementazioni, perché tra le varie opzioni per scrivere il codice (simulazione porte logiche/relé, codice procedurale ciclico con flag/if, macchina a stati realizzata con switch) la macchina a stati mi è sempre sembrata la più chiara. Però bisogna scomporre tutte le azioni del programma in piccole macchine, e non realizzare un'unica grossa macchina che gestisce tutto, quello si diventa un incubo.

Maurotec: 3) Sentivo la mancanza di un gestore di eventi che li catturasse.

Una macchina apposita che li rileva e comanda le altre macchine... o qualcosa del genere?

Maurotec: Il grosso problema resta però un buon pezzo di codice tra cui l'estratto che ho pubblicato che si occupa di rispondere alle richieste json per mostrare i dati

Perché volevi usare millis al posto di delay? Per rendere non bloccante quella funzione? Ok si può riscrivere in modo non bloccante, ma poi va usata in modo diverso, cioè va richiamata in continuazione condizionando il suo comportamento con una variabile di stato. Questa modifica però potrebbe essere incompatibile con l'intera struttura del resto del programma.

Allego il codice completo visto che non riesco ad allegare solo la parte relativa alle richieste JSON essedo troppo lungo.

Claudio_FF:
Perché volevi usare millis al posto di delay? Per rendere non bloccante quella funzione? Ok si può riscrivere in modo non bloccante, ma poi va usata in modo diverso, cioè va richiamata in continuazione condizionando il suo comportamento con una variabile di stato. Questa modifica però potrebbe essere incompatibile con l’intera struttura del resto del programma.

Esattamente, hai centrato il nocciolo del problema. Convertendo il delay con millis spero di ridurre i tempi di risposta ed evitare noiosi blocchi seppur momentanei della funzione.

ArduMotica_V2.28.ino (46.4 KB)

Questa invece è la nuova struttura che sto dando all'intero sketch.

|500x456

void loop(void)
{
  // ************************************* INIZIO loop(void) *************************************
  //RICHIAMO IL VOID JSon  PER IL COLLEGAMENTO CON RICHIESTE JSON A DISPOSITIVO ANDROID
  JSon();

  /* // Stampo i valori del Contatore KWh

     Serial.print(" totPowerCount= ");
     Serial.print(totPowerPulseCounter);
     Serial.print(" totPowerValue= ");
     Serial.print(totPowerValue);
     Serial.println(" Wh");
  */

  if (millis() - t > 5000) //Una volta ogni 5 secondi:
  {
    t = millis();
    // Inizio Sensore di temperatura DALLAS D18B20
    // call sensors.requestTemperatures() to issue a global temperature
    // request to all devices on the bus
    sensors.requestTemperatures(); // Send the command to get temperatures
    // Fine Sensore di temperatura DALLAS D18B20

    Cayenne.run();

    // INVIO I DATI AL DB
    sendDataToDB();
    Serial.println(F("Resto in attesa di un evento"));
    Serial.println(F(" ed invio i valori a cayenne"));
    Serial.println(F("========================================================="));
  }


}
// ************************************* FINE loop(void) *************************************

Come temevo tutto il resto del programma è “incompatibile”, a partire dalle letture dei DHT che portano via almeno 3 secondi ad ogni ciclo di loop :confused:

Si può certamente riscrivere la regolazione dell’apertura sotto forma di macchina a stati (attivata da un flag regAp) da richiamare continuamente dalla loop:

/*
    'regolaApertura' viene attivata ponendo a true il flag 'regApp'
    imposta a false il flag 'regApp' quando ha finito
    richiama 'StampaApertura' per ottenere il valore di 'Apertura'
    usa il valore 'value_int' ottenuto dalla request HTTP
    usa le variabili locali statiche 'stato' e 't'
*/
void regolaApertura()
{
    static byte stato = 0;
    static uint32_t t;

    switch(stato)
    {
        case 0:
            if(regAp) {
                digitalWrite(RCH2, LOW);
                t = millis();
                stato = 1;
            }
            break;

        case 1:
            if(millis() - t >= 1800) {
                digitalWrite(RCH2, HIGH);
                stato = 2
            }
            break;

        case 2:
            StampaApertura();   // in realta` legge l'apertura
            if(value_int <= Apertura) {
                digitalWrite(RCH2, LOW);
                t = millis();
                stato = 3;
            }
            break;

        case 3:
            if(millis() - t >= 250)
            {
                digitalWrite(RCH2, HIGH);
                stato = 0;
                regAp = false;
            }
    }
}

…ma anche tutto il resto dovrebbe essere riscritto in questo modo. Inoltre i tempi di esecuzione della regolaApertura possono risultare allungati dai tempi delle altre funzioni (letture dei DHT in primis).

Senza offesa ma in tutta sincerità non ci ho capito molto. Ovviamente la colpa è solo mia perché non sono così avanzato nella programmazione. Sto cercando di approfondire "scopiazzato " parti di codice quà e là e chiedendo consigli quando incontro problemi. Accetto onvviamente ancora consigli sul perchè il mio tentativo di sostituzione di delay con millis non funziona. ;)

ma se è solo far "lampeggiare 2 led" il Blink without Delay degli esempi nell ide basta e avanza te ne fai 2 con le necessarie piccole modifiche.

la funzione di millis va compresa per bene al più presto possibile,

e va presa in considerazione tutte le volte che bisogna fare qualcosa ogni tot tempo, il che significa che è uno dei pilastri fondamentali della programmazione

elrospo: ma se è solo far "lampeggiare 2 led" il Blink without Delay degli esempi nell ide basta e avanza te ne fai 2 con le necessarie piccole modifiche.

Ti ringrzio per la risposta. Millis l'ho già usato diverse volte e, ultimamente anche in un progetto un pochino più complicato di quello ma me allegato in questo thread. Se noti infatti nel mio primo post, è quello che ho fatto, però senza avere il risultato ottenuto e proprio per questo ho chiesto consiglio al forum. ;)

Claudio_FF: Come temevo tutto il resto del programma è "incompatibile", a partire dalle letture dei DHT che portano via almeno 3 secondi ad ogni ciclo di loop :confused:

Si può certamente riscrivere la regolazione dell'apertura sotto forma di macchina a stati (attivata da un flag regAp) da richiamare continuamente dalla loop:

...ma anche tutto il resto dovrebbe essere riscritto in questo modo. Inoltre i tempi di esecuzione della regolaApertura possono risultare allungati dai tempi delle altre funzioni (letture dei DHT in primis).

@Claudio_FF: ho provato ad apportare le tue modifiche, provvedendo opportunamente a creare due funzioni (una per l'apertura ed una per la chiusura) al posto di "regolaApertura()" però non fa ciò che deve. Il mio codice deve alzare od abbassare la tenda tramite il comando di una slide bar ricevuto da un'app sviluppata per Android.

Se applico il tuo codice mi funziona solo in chiusura (abassare la tenda) ovvero, solo se trascino la slide bar oltre la percentuale di apertura attuale. Se invece voglio alzarla non mi funziona. Inoltre se ho per esempio la tenda abbassata del 10% e la comando di portarsi al 60% per esempio, non si ferma alla posizione impostata desiderata ma solo quando arriva a fine corsa ovvero al 100%. E' come se non considerasse la funzione StampaApertura() Ti allego il codice che ho dovuto opportunamente modificare per poter scindere le operazioni di apertura e chiusura.

void AlzoTenda()
{
    static byte stato = 0;
    static uint32_t t_time;

    switch(stato)
    {
        case 0:
            if(regAp) {
                digitalWrite(RCH2, LOW);
                t_time = millis();
                stato = 1;
            }
            break;

        case 1:
            if(millis() - t_time >= 1800) {
                digitalWrite(RCH2, HIGH);
                stato = 2;
            }
            break;

        case 2:
            StampaApertura();   // legge l'apertura
            if(value_int >= Apertura) {
                digitalWrite(RCH2, LOW);
                t_time = millis();
                stato = 3;
            }
            break;

        case 3:
            if(millis() - t_time >= 250)
            {
                digitalWrite(RCH2, HIGH);
                stato = 0;
                regAp = false;
            }
    }
}

void AbbassoTenda()
{
    static byte stato = 0;
    static uint32_t t_time; //timer tenda

    switch(stato)
    {
        case 0:
            if(regAp) {
                digitalWrite(RCH1, LOW);
                t_time = millis();
                stato = 1;
            }
            break;

        case 1:
            if(millis() - t_time >= 1800) {
                digitalWrite(RCH1, HIGH);
                stato = 2;
            }
            break;

        case 2:
            StampaApertura();   // legge l'apertura
            if(value_int <= Apertura) {
                digitalWrite(RCH1, LOW);
                t_time = millis();
                stato = 3;
            }
            break;

        case 3:
            if(millis() - t_time >= 250)
            {
                digitalWrite(RCH1, HIGH);
                stato = 0;
                regAp = false;
            }
    }
}

il tutto richiamato nella scheda Json in questo modo:

 if (value_int >= 0 && value_int <= 100)
                {
                  if (value_int > Apertura)
                  {
                    AlzoTenda();
                  }
                  if (value_int < Apertura)
                  {
                    AbbassoTenda();
                  }
                }
                else
                {
                  Serial.println(F("Valore fuori range"));
                  client.print(F("Error, value out of range"));
                }

Se invece utilizzo questo codice usando però il delay fa esattamente ciò che voglio io.

              if (value_int >= 0 && value_int <= 100)
              {
                if (value_int > Apertura)
                {
                  /*
                    Serial.print("Apro la tenda da posizione:");
                    Serial.print(Apertura);
                    Serial.print("% a posizione:");
                    Serial.print(value_int);
                    Serial.print("%");
                  */
                  digitalWrite(RCH2, LOW);
                  delay(1800); // Attendo 1,8 secondi prima di riposizionare il relè sullo stato iniziale.
                  //Operazione necessaria per simulare la pressione del tasto altrimenti la centralina non riceve correttamente il comando
                  digitalWrite(RCH2, HIGH);
                  while (value_int > Apertura)
                  {
                    StampaApertura();
                    //Serial.println(Apertura);
                  }
                  digitalWrite(RCH2, LOW);
                  delay(250); //Attendo 250 millisecondi prima di riposizionare il relè sullo stato iniziale, altrimenti la centralina non processa correttamente il comando
                  digitalWrite(RCH2, HIGH);
                  client.print(F("status ok"));
                  /*
                    client.print(value_int);
                    client.print(",Apertura:");
                    client.print(Apertura);
                  */
                }
                if (value_int < Apertura)
                {
                  /*
                    Serial.print("Chiudo la tenda da posizione:");
                    Serial.print(Apertura);
                    Serial.print("% a posizione:");
                    Serial.print(value_int);
                    Serial.print("%");
                  */
                  digitalWrite(RCH1, LOW);
                  delay(1800); // Attendo 1,8 secondi prima di riposizionare il relè sullo stato iniziale.
                  //Operazione necessaria per simulare la pressione del tasto altrimenti la centralina non riceve correttamente il comando
                  digitalWrite(RCH1, HIGH);
                  while (value_int < Apertura)
                  {
                    StampaApertura();
                    //Serial.println(Apertura);
                  }
                  digitalWrite(RCH1, LOW);
                  delay(250); //Attendo 250 millisecondi prima di riposizionare il relè sullo stato iniziale, altrimenti la centralina non processa correttamente il comando
                  digitalWrite(RCH1, HIGH);
                  client.print(F("status ok"));
                  /*
                    client.print(value_int);
                    client.print(",Apertura:");
                    client.print(Apertura);
                  */
                }
              }
              else
              {
                Serial.println(F("Valore fuori range"));
                client.print(F("Error, value out of range"));
              }

Dov'è l'errore?

Claudio_FF: La funzione millis DA SOLA NON È LA SOLUZIONE se non si modifica anche la struttura del programma, trasformandola in macchine a stati finiti (quello che dice orso con altre parole).

Anzi, organizzando tutto come macchine a stati, per assurdo si può anche continuare ad usare delay, ma solo per piccoli tempi e/o per "regolare" il tempo di esecuzione del loop principale.

Si deve perciò pensare al programma non come sequenza monolitica di istruzioni (ritardi compresi) da eseguire dall'inizio alla fine in un colpo solo, ma spezzare invece l'esecuzione di tutte le parti in più passaggi ciclici, singolarmente molto veloci e senza ritardi di alcun genere.

La funzione loop potrebbe incaricarsi solamente di richiamare ciclicamente i vari processi (ad esempio circa 50 volte al secondo come nell'esempio seguente):

void loop(){
    processo1();
    processo2();
    processo3();
    delay(20);
}

Ogni processo può essere uno switch controllato da una propria variabile di stato:

void processo1(){
    switch(stato_proc1){
        case 0:
            break;
        case 1:
            break;
        case 2:
            break;
    }
}

In ogni case si può scrivere il frammento di codice da eseguire nello stato attuale, che deve:

  • Controllare se si verifica una certa condizione
  • Eventualmente eseguire qualche operazione
  • Eventualmente cambiare la variabile di stato

Con questa struttura un ritardo è semplicemente la permanenza in un certo stato per un certo numero di cicli. Si può ottenere con millis, o con un contatore che incrementa/decrementa ad ogni chiamata del processo, è -quasi- indifferente, quello che conta è che la logica sequenziale di una lunga funzione che monopolizza tutto il tempo si trasforma in una velocissima logica di controllo: rilevazione_evento->azione->cambio_stato. (Un esempio relativo alla rilevazione click/longpress di un pulsante)

Questo permette di:

  • Portare avanti N processi in parallelo in tempo reale
  • Aggiungere nuove funzionalità o processi indipendenti senza toccare quelli preesistenti
  • Scomporre una logica troppo complessa da affrontare tutta assieme in piccole macchine semplici, che inviano "segnali" alle altre tramite flag (esempio variabili globali)

BELLISSIMA SPIEGAZIONE!!!! :) semplice, pulita e chiarissima!

ziopippo: Ti ringrzio per la risposta. Millis l'ho già usato diverse volte e, ultimamente anche in un progetto un pochino più complicato di quello ma me allegato in questo thread. Se noti infatti nel mio primo post, è quello che ho fatto, però senza avere il risultato ottenuto e proprio per questo ho chiesto consiglio al forum. ;)

che poi alla fine millis() è solo un numero che avanza sempre, parte appena si accende il micro e continua ad andare avanti, e a dirla tutta non c'è niente di esoterico in questo "contatore"

è semplicemente un numero che avanza con la precisione di un discreto orologio, forse se l avevano chiamato secondis() scommetto che si capiva meglio :grin:

poi quello che uno ci vuole fare con un numero che avanza sempre dipende da lui, e a parte qualche rara eccezione (all'accensione del micro) mi pare che la maggior parte delle volte si usa sempre la formula lettura precedente lettura attuale

elrospo:
che poi alla fine millis() è solo un numero che avanza sempre …

… esattamente quello che ho scritto un po’ di tempo fa QUI :smiley: :smiley: :smiley:

Guglielmo

Ciao

scusa se ne approfitto ma sto cercando una nuova storiella da progettare,mi spieghi per favore cosa dovrebbe fare questa tenda livello umano mi spiego meglio:

ES 1-premo il pulsante si alza tutta,lo ripremo si abbassa tutta.

ES 2-premo un pulsante si alza finchè lo tengo premuto.

ES 3-Ect.Ect

Io non ho ancora capito cosa vuoi da questa tenda.

Se mi spieghi il tuo progetto ed a grandi linee quali componenti utilizzi(Motore normale o passopasso,pulsante 1 o 2,o telecomando ect.ect),ne approfitto per provarci anchio,ovviamente usando millis().

Ciao