Aiutino per cronometro

Ciao a tutti, sono Andrea, nuovo su questo blog e nel mondo dell'elettronica/informatica in generale, è da circa una settimana che ho iniziato a seguire qualche tutorial.
Chiedo scusa se violo qualche sorta di ''codice morale'' del web, ma è la prima volta in vita mia che scrivo su un forum, in genere me la cavo da solo, ma con questa roba :sweat_smile: ne capisco poco.
Bando alle ciance.
Ho iniziato un cronometro semplice con arduino, del tipo

  1. premo il bottone e parte il cronometro

  2. premo il bottone e si ferma il cronometro.

il problema è che non riesco in nessun modo a far partire una variabile millis da zero quando premo il bottone. se mi date indicazioni di come poter incollare il codice lo faccio subito. intanto Grazie della pazienza

Prima che passi Guglielmo a sgridarti (:D) ti consiglio di presentarti nell'apposita sezione ... :wink:

Benissimo hahah, ho già fatto casini dopo un solo messaggio vado subito!

:smiley: ... e per evitare qualsiasi futuro problema ... ti consiglio di leggere con MOLTA attenzione il REGOLAMENTO.

Guglielmo

Ciao, benvenuto, allora la funzione millis() non la puoi azzerare infatti ti restituisce il tempo da quanto il micro è stato avviato (solo all'avvio millis vale zero) ma per fare ciò che vuoi fare tu non ti serve azzerarla ma salvarla in una variabile quanto avvi il cronometro, poi quando lo fermi la salvi nuovamente in un altra variabile e poi fai la differenza fra queste due

elapsed = tempoFine - tempoInizio;

in questo modo hai la differenza in millisecondi tra l'avvio e lo stop

Per incollare il codice ti basta utilizzare il primo pulsante in alto a sinistra dell'editor identificato da </> e mettere il tuo codice tra i due tag code

intanto grazie, il mio problema è un altro, il tempo dalla prima pressione alla seconda me lo riesce a calcolare, quello che vorrei fare è farmi comparire sul seriale il tempo che scorre dalla prima pressione alla seconda. non so se mi sono spiegato, un po come un cronometro normale.
intanto posto il codice

int button = 7;
int centesimi;
int stato = 0;
int secondi;
int tempo=0;

void setup() {
  Serial.begin(9800);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(button, INPUT);
}

void loop() {
  if (digitalRead(button) == HIGH && stato == 0) { //Accende cronometro
    stato = 1;
    while (digitalRead(button) == HIGH) {
      delay(10);
      centesimi = millis();
       
    }
  }


  while (stato == 1) {

   
    if (digitalRead(button) == HIGH && stato == 1) { //Spegne cronometro
      stato = 3;

      while (digitalRead(button) == HIGH) {
        delay(10);

      }
    }
  }
  if (stato == 3) {
    secondi = millis() - centesimi;
    Serial.println(secondi);
    stato = 0;
  }

}

ciao Andyyo,

una soluzione potrebbe essere: premo la prima volta, salvo millis() su variabile A; abiliti la stampa di (millis()-A)/1 o 10 o 100 o 1000...fino alla pressione successiva.

anche la stampa deve essere fatta utilizzando millis().

Rispetto a quanto dichiari nel primo post il tuo codice funziona in modo leggermente differente, ovvero premi il pulsante e aspetti che venga rilasciato poi aspetti senza fare nulla finché qualcuno non preme nuovamente e li resti finché non viene rilassciato il pulsante.
Solo a questo punto calcoli il tempo trascorso e lo stampi sulla seriale.
Tutto questo con dei while che in questo caso possono tranquillamente essere evitati, inoltre per aspettare il rilascio del pulsante introduci rallentamenti con i delay che per un cronometro non sono proprio il massimo :slight_smile:
Considera che tu sul micro hai la funzione loop che già cicla di continuo, quindi secondo me dovresti ristrutturare il codice in modo leggermente differente, ovvero hai più o meno gestito una macchina a stati finiti con la variabile stato, quindi potresti pensare di riscrivere il loop in questo modo:
Se lo stato è zero verifichi se qualcuno ha premuto il pulsante, se si salvi millis in una variabile.
Se lo stato è diverso da zero (e a questo punto puoi cambiare la variabile in booleana) allora verifichi se qualcuno ha premuto di nuovo il pulsante, se si salvi millis in un'altra variabile.
Fuori da questo controllo ma comunque nell'else della verifica della variabile stato stampi di continuo sulla seriale la differenza tra millis() e la variabile dove hai memorizzato il momento in cui il cronometro è stato avviato.
Se i while che hai messo per aspettare il rilascio dei pulsanti servono come sorta di debounce potresti eliminarli e implementare il debounce via harware, molto meglio sotto tanti punti di vista.
Se posso permettermi, cambia i nomi della variabili perché sono fuorvianti

secondi = millis() - centesimi;

porta a pensare che li hai effettivamente la differenza in secondi, invece hai la differenza in millisecondi dall'inizio e anche centesime è ugualmente fuorviante

Dato che sembra tu voglia fare tutto con un solo pulsante, potresti usare per leggerlo questo blocco di codice, in modo da effettuare le operazioni UNA sola volta alla pressione del pulsante, ignorandolo se poi viene tenuto premuto ... ti servono tre variabili byte extra, ad esempio chiamiamole st1, stp1 e cond1 (o qualsiasi altro nome tu gli preferisca dare), messe ad 1 nel setup ... supponendo che tu stia usando pulsanti che chiudono a massa, la logica sarebbe cosi ...

   st1 = digitalRead(pin)                      //leggi ingresso pulsante
   if ((st1 != stp1) && (stp1 == 0))      // pulsante appena premuto
   {
      if (cond1 == 1;                            //se e' la prima pressione (start)
      {
         stp1 = st1;                               //setta flag per pulsante premuto
         tempo1 = millis();                    //setta variabile inizio tempo
         cond1 = 2;                              //memorizza prima pressione
      }
      else if (cond == 2)                      //se e' la seconda pressione (stop)
      {
         stp1 = st1;                              //setta flag per pulsante premuto
         tempo2 = millis();                   //setta variabile fine tempo
         cond1 = 3;                             //memorizza seconda pressione
      }
      else if (cond == 3)                     //se e' la terza pressione (azzera)
      {
         stp1 = st1;                             //setta flag per pulsante premuto
         cond1 = 4;                             //memorizza terza pressione
      }
   }
   if ((st1 != stp1) && (stp1 == 1))   //pulsante appena rilasciato
   {
      stp1 = st1;                               //resetta flag per pulsante rilasciato
   }

al di fuori di questo blocco, avrai le seguenti condizioni:

cond1 vale 1, non hai ancora fatto nulla, attendi lo start o fai qualsiasi altra cosa vuoi fare nell'attesa

cond1 vale 2, pulsante premuto la prima volta, tempo1 ora vale l'istante della prima pressione (lo start)

cond1 vale 3, pulsante premuto la seconda volta, tempo2 vale l'istante della seconda pressione (lo stop), a questo punto puoi calcolare il tempo trascorso e visualizzarlo

cond1 vale 4, hai premuto il pulsante la terza volta per resettare il cronometro, quindi azzeri tutto, rimetti cond1 ad 1 e riparti

Questo e' solo un modo, ce ne sono altri, ovviamente ... :wink:

Intanto vi ringrazio, come prima esperienza in un forum mi sono trovato benissimo con voi.
Prima di provare i vostri consigli mi toccherà studiarmi un po di arabo del tipo Boolean e altre parole per ora incomprensibili.
Spero di scrivere presto eventuali risultati :slight_smile: :slight_smile:

allora, grazie ad alcuni consigli sono riuscito a fare dei buoni progressi, il cronometro va, i secondi si riavviano a 60 secondi come è giusto che sia.
Vorrei chiedere come risolvere un altro problema.
allora ho collegato al posto dell'interruttore un sensore di luce il tutto funziona abbastanza bene, ma non passa piu da stato 1 a stato 2 salvo se faccio così:

  if (luce < 400 && stato == 0 )  {
    stato = 1;
  }
  if (stato == 1 && luce > 400) {
    stato = 2;
  }

in questo modo funziona, ma al posto di avere 3 stati, ne devo mettere 5, in più non mi dà l'idea di essere molto affidabile. Qualche illuminante consiglio?

ci sono delle piccole "stranezze" nel tuo modo di programmare tipo si dovrebbe sempre (o quasi) >= oppure <=

se per caso il valore è proprio 400 il tutto sta "fermo"

nel link sotto leggi l istruzione != (not equal to) sembra piu appropriata in questo caso tipo

if (luce <= 400 && stato != 1 ) {
stato = 1;
}