[RISOLTO] comprensione loop(), millis(), do while

Salve a tutti,
forse sono stupido io ma proprio non capisco… sto provando questo sketch che poi dovrà essere implementato in un altro un po’ più complesso (ma non di molto) e non riesco a capire come funziona. questo è lo sketch:

int apriCancelloR = 5;
unsigned long tAttuale;
int ritardo;
int tLimite = 30000;

void setup()
{
  delay(250);
  //inizializzo la porta seriale
  Serial.begin(9600);
  Serial.println("prova millis");
  pinMode(apriCancelloR, INPUT_PULLUP);
  tAttuale = millis();
}

void loop()
{
  do
  {
    ritardo = digitalRead(apriCancelloR);
    tAttuale = millis();
    Serial.println(tAttuale);
  } 
  while (ritardo == HIGH || tAttuale < tLimite);
  if (ritardo == LOW)
  {
    Serial.println("apro il cancello");
    unsigned long tAttuale;
  }  
  else
  {
    Serial.println("il cancello resta chiuso");
    unsigned long tAttuale;
    Serial.println(tAttuale);
  }  
}

per come avevo capito io il funzionamento doveva essere il seguente.
dichiaro le variabili,
le inizializzo nel setup(),
nel loop eseguo il ciclo do while fino a che una delle due condizioni non si avveri,
se premo il bottone esco dal do while
quindi se il bottone è stato premuto apro il cancello e resetto la variabile
oppure non apro il cancello ma la variabile la azzero lo stesso per ricominciare il loop da capo.
E’ corretto il mio ragionamento?

ma il loop non si chiama in questo modo perchè cicla all’infinito???

ho modificato la condizione in questo modo:

  Serial.println(tAttuale);
  Serial.println(ritardo);
  ritardo = digitalRead(apriCancelloR);
  while (ritardo == HIGH || tAttuale < tLimite);
  {
    ritardo = digitalRead(apriCancelloR);
    tAttuale = millis();
    Serial.println(tAttuale);
  }

e tutto quello che ottengo dal monitor seriale è questo:

prova millis
249
0

non capisco… oltretutto apriCancelloR è dichiarato PULLUP… non dovrebbe essere a 1

Hai dimenticato un ; dopo il while

Il punto e virgola ci va se è do...while();
se è while() {} no

Mmm … in quel programma c’è qualche problema, ed il primo che vedo è :

do {
   ritardo = digitalRead(apriCancelloR);
   tAttuale = millis();
   Serial.println(tAttuale);
}
while (ritardo == HIGH || tAttuale < tLimite);

la parte che non va è “tAttuale < tLimite” visto che tAttuale, che prende il valore di millis() cresce sempre e quindi, appena diventa superiore a tLimite tu la dentro non ci entri più.

Se vuoi implementare un meccanismo di “TimeOut” lo devi implementare, come sempre, con delle “differenze” e non con dei valori fissi …

tAttuale = millis();
do {
   ritardo = digitalRead(apriCancelloR);
   Serial.println(tAttuale);
}
while ( (ritardo == HIGH) ||  ( ! ( millis() - tAttuale > tLimite)) );

… nota l’operatore negazione che inverte il valore di quel confronto … se non si è superato il tempo limite, avresti FALSE che, negato, diventa TRUE, quando il valore limite sarà superato, quella espressione diventerà TRUE e, grazie alla negazione, verrà trasformata in FALSE e si uscirà dal while … :wink:

O … almeno spero fosse questo il comportamento che volevi ottenere … :grin:

Guglielmo

ok l'ho tolto ma continua a non funzionare secondo come io mi aspetto che funzioni....
mi spiego meglio... ora senza il ; credo entri nel while (ma devo verificare togliendo la print iniziale, però se premo il bottone non esce dal while e comunque sia non azzera la variabile tAttuale...

30003
apro il cancello
30003
0
apro il cancello
30003
0
apro il cancello
30003
0
apro il cancello
30003
0
30127
30134
30141

non è uscito per tempo limite raggiunto e malgrado lo "0" che si vede tAttuale non viene resettata, va avanti

Hai letto il mio post ??? ]:smiley: ]:smiley: ]:smiley:

Guglielmo

@guglielmo

si è quello che voglio ottenere, uscire dal ciclo se premo il bottone oppure se si raggiunge il tempo limite

lo hai postato mentre io rispondevo a nid :slight_smile:

Ok ...
... e se vuoi stare lontano dai guai ... NON usare mai millis() come la stavi usando, ma sempre con una tecnica di "differenza tra valori" ... ti metti al riparo sia dal problema che stavi incontrando, sia dal problema che ... dopo poco più di 49 gg. millis() si azzera e riparte :wink:

Guglielmo

@guglielmo

questo è lo sketch con la modifica che mi hai suggerito

int apriCancelloR = 5;
unsigned long tAttuale;
int ritardo;
int tLimite = 30000;

void setup()
{
  delay(250);
  //inizializza lo shield con il mac e l'ip  
  //inizializza la porta seriale
  Serial.begin(9600);
  Serial.println("prova millis");
  pinMode(apriCancelloR, INPUT_PULLUP);
}

void loop()
{
  tAttuale = millis();
  do {
    ritardo = digitalRead(apriCancelloR);
    Serial.println(tAttuale);
  }
  while ((ritardo == HIGH) ||  ( ! ( millis() - tAttuale > tLimite)));
  if (ritardo == LOW)
  {
    Serial.println("apro il cancello");
    unsigned long tAttuale;
  }  
  else
  {
    Serial.println("il cancello resta chiuso");
    unsigned long tAttuale;
    Serial.println(tAttuale);
  }  
}

e adesso il monitor seriale mi continua a stampare "249" come se tAttuale non si incrementasse più... mi correggo non visualizza la variabile che si incrementa ma appena ho premuto il bottone...

249
249
apro il cancello
1532223
1532223
1532223

il problema è che adesso nel ciclo while non ci entra più, e l'altro problema è che doveva uscire dal ciclo per aver raggiunto il limite e stampare sul monitor "il cancello resta chiuso", invece è uscito solo quando ho premuto il bottone e se premo il bottone nuovamente non succede proprio niente.

Se volete vi spiego meglio quello che questo sketck di prova dovrà fare quando sarà "in produzione" presso un agriturismo così magari mi aiutate a capire meglio il problema e riesco, con il vostro aiuto, a trovare una soluzione.

ok cosi dovrei aver risolto

int apriCancelloR = 5;
unsigned long tAttuale;
int ritardo;
int tLimite = 3000;

void setup()
{
  delay(250);
  //inizializza lo shield con il mac e l'ip  
  //inizializza la porta seriale
  Serial.begin(9600);
  Serial.println("prova millis");
  pinMode(apriCancelloR, INPUT_PULLUP);
  tAttuale = millis();


}

void loop()
{
//  Serial.println(tAttuale);
  do {
    ritardo = digitalRead(apriCancelloR);
    if ( millis() - tAttuale > tLimite) 
    {
      Serial.println(tAttuale);
      tAttuale = millis();
      break;
    }  
  }
  while (ritardo == HIGH);
  if (ritardo == LOW)
  {
    Serial.println("apro il cancello");
  }  
  else
  {
    Serial.println("il cancello resta chiuso");
    Serial.println(tAttuale);
  }  
}

Se provi a spiegare bene il problema, descrivendo tutte le varie fasi, magari troviamo una forma ... "più pulita" per fare quello che ti serve :wink:

Guglielmo

Questo pezzo di sketch in particolare serve in un agriturismo per un’apertura del cancello “ritardata”.
In pratica gli ospiti che hanno terminato il loro soggiorno in questo agriturismo fanno il check-out, montano in macchina e se ne vanno, la strada da percorrere per arrivare dalla tenuta al cancello è sterrata e presenta salite e discese ed in media ci si mettono dai 6 ai 10 minuti per arrivare al cancello.
Attualmente i proprietari quando fanno il check-out di un cliente e lo salutano, si mettono davanti al PC che visualizza il cancello (sia lato esterno che interno) ad aspettare che il cliente arrivi al cancello per premere il pulsante di apertura e permettere l’uscita.
Mi hanno chiesto di risolvere il problema ed io ho pensato ad arduino.
In pratica succederà questo:
il cliente fa il check-out, il proprietario preme un’icona di consenso sul suo desktop che manda, via web browser (avevo detto che gli arduino sono 3, tutti equipaggiati con ethernet shield W5100? :slight_smile: ) il seguente messaggio: “http://192.168.0.46/rapr/” l’arduino al cancello recepisce il messaggio “rapr” e parte questo ciclo:

          if (msg.indexOf("rapr") > 0)
          {
            int ritardo;
            do
            {
              ritardo = digitalRead(apriCancelloR);
              if ( millis() - tAttuale > tLimite) 
              {
                tAttuale = millis();
                break;
              }  
            }
            while (ritardo == HIGH);
            if (ritardo == LOW)
            {
              pc_client.print("<p>apertura cancello ritardata</p>");
              digitalWrite(apriCancello, HIGH);
              delay(1000);
              digitalWrite(apriCancello, LOW);
            }

quindi il cliente ha 10 minuti di tempo(da quando il proprietario ha premuto l’icona del consenso) per arrivare al cancello e premere un pulsante che apre il cancello. Passati i 10 minuti (ho impostato tLimite a 600000) il pulsante non funziona più ed il cliente deve suonare il campanello per farsi aprire (non state a sindacare, i proprietari vogliono così ed io attacco l’asino dove vuole il padrone).
E questo è tutto… per stasera :smiley:

Se volete posto lo sketch completo così mi date un opinione…

Se l'ospite si ferma a guarda un fiore resta intrapolato.
Metterei un campanello all'interno del cancello che il cliente deve premere.
Puó suonare un campanello in casa e il propretario apre il cancello oppure il propretario alla partena del ospite attiva per x minuti il pulsante interno che in quel tempo funge da apricancello automatico.
Ciao Uwe

Dubbio ...
... faccio il check-out, prendo la macchina e mi avvio, il proprietario pigia il bottone e scattano i 10 min.

Dopo 5 minuti, arriva un altro e fa check-out anche lui, prende la macchina e si avvia ... e il padrone che fa ? Preme di nuovo il pulsante ? E cosa avviene al tempo ?

Perché a me mancano ancora 5 minuti per arrivare al cancello, mentre al secondo ne mancano 10 ...
... hai previsto questa cosa ??? :wink:

Guglielmo

@uwe
ci sono due pulsanti all'interno del cancello, uno che apre il cancello previo consenso, e l'altro è il campanello che sarà premuto in caso di scadenza dei 10 minuti

@guglielmo
no questa cosa al momento non è prevista

prima c'era solo il campanello e adesso i proprietari hanno voluto in questo modo