funzione millis() come si resetta?

salve a tutti sto realizzando un cronometro utilizzando il tempo di funzionamento di arduino pero il problema sta nel azzerare il tempo quando arriva a 60 per incrementare i minuti di 1 e di conseguenza anche le ore. come posso fare? usando una variabile di appoggio? ci provo da ore ma non ci riesco sapete aiutarmi?

millis() non si resetta. Se vuoi capire come si usa, dai un'occhiata qua:

https://forum.arduino.cc/index.php?topic=355435.msg2460825#msg2460825

Affronta la cosa per gradi.

Prima prova a fare un contasecondi, un programma che ogni secondo incrementa una variabile e te la scrive sul serialmonitor.

Parti da questo.

Inserisci questo programma dentro Arduino e apri la seriale. Ogni secondo sulla seriale ti apparirà scritto quanti secondi sono passati. Sarebbe la parte di un cronometro.

int val = 0;
void setup() {
  Serial.begin(9600);
}
void loop() {
  val = val+1;
  delay(1000);
  Serial.println(val);
}

Se invece vuoi contare i millisecondi basta che togli il delay e per dirgli che ogni volta che arriva a 59 secondi deve aumentare di un secondo basta che fai:

int val = 0;
int valb = 0;
void setup() {
  Serial.begin(9600);
}
void loop() {
  val = val+1;
  delay(19);
  if(val >= 60)
  {
    val = 0;
    valb = valb+1;
  }
  Serial.print(valb);
  Serial.print(":");
  Serial.println(val);
}

SukkoPera:
millis() non si resetta.

Non è vero :slight_smile:
Se vuoi resettare la millis è possibile farlo basta fare così:

extern unsigned long timer0_millis;


timer0_millis = 0; // resetta millis

Se vuoi aggiungere i minuti (quindi minuti-secondi-millisecondi) basta fare:

int val = 0;
int valb = 0;
int valc = 0;
void setup() {
  Serial.begin(9600);
}
void loop() {
  val = val+1;
  delay(19);
  if(val >= 60)
  {
    val = 0;
    valb = valb+1;
  }
  if(valb >= 60)
  {
    valb = 0;
    valc =valc+1;
  }
  Serial.print(valc);
  Serial.print(":");
  Serial.print(valb);
  Serial.print(":");
  Serial.println(val);
}

In questo modo quando arriverà a 60 minuti, non passerà ad ore, ma andrà a continuare con i minuti

GiovanniGigantino:

int val = 0;

int valb = 0;
int valc = 0;
void setup() {
  Serial.begin(9600);
}
void loop() {
  val = val+1;
  delay(19);
  if(val >= 60)
  {
    val = 0;
    valb = valb+1;
  }
  if(valb >= 60)
  {
    valb = 0;
    valc =valc+1;
  }
  Serial.print(valc);
  Serial.print(":");
  Serial.print(valb);
  Serial.print(":");
  Serial.println(val);
}

Riscrivi quel codice senza usare delay ma implementando l'uso di millis, per un risultato leggermente piu professionale.

int val = 0;
int valb = 0;
int valc = 0;
int tempo = 19;
void setup() {
  Serial.begin(9600);
}
void loop() {
  val = val+1;
  tempo = millis();
  if(val >= 60)
  {
    val = 0;
    valb = valb+1;
  }
  if(valb >= 60)
  {
    valb = 0;
    valc =valc+1;
  }
  Serial.print(valc);
  Serial.print(":");
  Serial.print(valb);
  Serial.print(":");
  Serial.println(val);
}

astrobeed:
Non è vero :slight_smile:

Che "non si resetti" non vuol dire che non si può fare, ma solo che non è buona pratica farlo. E sicuramente non è necessario farlo per risolvere il problema del topic.

@GiovanniGigantino: non ci siamo :). Quel 19, calcolato empiricamente presumo, deve sparire.

SukkoPera:
ma solo che non è buona pratica farlo. arire.

Può essere necessario resettare millis, dipende da cosa uno deve fare, in fin dei conti è solo un contatore, nulla di più nulla di meno, non sta scritto da nessuna parte che "non si può, non si deve" resettare.

Grazie @SukkoPera per la correzione... dopo averlo postato mi sono reso conto che il programma era errato...
Per usare millis comunque bisognerebbe dare una variabile , come ad esempio var "var =millis();"
per poi in un if scrivere che dopo un tot tempo "quindi se, ad esempio, equivale a 300", per poi fare qualcosa (ovviamente da quel che ho capito). Forse mi sbaglio...

astrobeed:
Può essere necessario resettare millis, dipende da cosa uno deve fare, in fin dei conti è solo un contatore, nulla di più nulla di meno, non sta scritto da nessuna parte che "non si può, non si deve" resettare.

RIPETO: Sicuramente non è necessario farlo per risolvere il problema del topic.

@Giovanni: se guardi il link che ho postato, che è anche nella mia firma, proprio non riesci a farlo? 300 non c'entra niente. millis() conta i MILLISECONDI, di cui ce ne sono 1000 in un secondo, per cui...

Che poi basta fare due conti, se vogliamo rendere "leggibile" l'uptime di Arduino:

unsigned long now = millis() / 1000;
byte s = now % 60;
byte m = (now / 60) % 60;
byte h = (now / 3600) % 24;

E così via... % rappresenta l'operatore di modulo, ovvero il resto della divisione.

Grazie @SukkoPera. Poi ho una domanda che riguarda il forum. Perché dopo che mando qualcosa nel forum, dopo che provo a inviare qualcos'altro nel forum, il sito me lo impedisce?

Grazie ragazzi tutti molto disponibili :slight_smile:
Sono riuscito a farli con i delay ma volevo evitarlo perché infatti perde facilmente millesimi di secondo e in un minuto rimane indietro di circa 1 secondo mettendo altre funzione in mezzo al ciclo loop.
Alla fine sono riuscito usando una variabile d'appoggio che assumeva il valore del resto della divisione in questo modo:

secondi = millis () / 1000; 
Resto = secondi % 60;

@decca97

Dovresti avere intuito che gli strumenti forniti dal Core di arduino e le varie librerie permettono di raggiungere risultati in breve tempo, tuttavia nulla è perfetto e ci sono casi in cui classi, funzioni pronte per essere usato ti permettono di realizzare il programma che però non rientra nelle specifiche che hai imposto come vincolanti.

Questo fenomeno si verifica con qualunque piattaforma anche ben più potente di un AVR ad 8 bit, accade ciò perché si vuole spremere il micro fino all'ultimo ciclo di clock. In questo caso anche spremendo per bene il micro avrai sempre una o più variabili che mutano, sulle quali hai poco o nessun controllo, uno di questi riguarda il sistema di clock usato, se quarzo o oscillatore o altro generatore di clock.

Indipendentemente da come è generato il segnale di clock, questo è dipendente dalla temperatura di lavoro.
Per semplificare il discorso, la soluzione soddisfacente al problema la si raggiunge scrivendo codice dedicato alla applicazione (il cronometro), cercando e sperimentando e verificando quale dei tanti codice sorgenti sotto test è quello che compie lo stesso lavoro in meno cicli CPU, in particolare nei momenti critici.
La scrittura di codice sorgente dedicato all'applicazione embedded può essere o meno la soluzione, in quanto si tratta di considerare accettabile la perdita di precisione. Detta in altri termini, anche con questa tecnica o addirittura scendendo a livello più basso di programmazione coinvolgendo il codice asm e l'assembler potresti scoprire di non avere raggiunto il risultato sperato o che comunque i vincoli imposti non sono rispettati.

L'applicazione in questione può essere realizzata evitando di usare le funzioni (di cui non si conosce con precisione le operazioni che svolge internamente) pronte e ricorrere alla manipolazione dei registri interni, in particolare quelli relativi ai tre timer counter presenti dentro l'atmega, in più uno di essi (Timer1) ha la risoluzione di 16bit.
Anche così facendo, ricorda che la frequenza di oscillazione del quarzo varia in base alla temperatura e allora più che trovare un espediente per mantenere la temperatura costante, si potrebbe invece scegliere un generatore di clock che offra la precisione richiesta.

PS:Ti consiglio per il momento di mettere da parte questo tipo di progetti (dove i vincoli temporali determinano o meno la soluzione al problema), quando ne saprai di più riprendi il progetto in mano, tuttavia se te la senti c'è un manuale composto da più di 600 pagine, in lingua Inglese. Leggendolo e comprendendolo hai anche modo di fare domande inerenti il manuale e troverai sicuramente la risposta che cerchi.

Ciao.

Ragazzi continuo su questo topic x non aprirne uno nuovo, l'argomento è simile.

Devo aggiungere alla mia presa comandata via BT (che funziona egregiamente da un pò) un paio di if con spegnimenti temporizzati. Allo scopo vorrei usare il millis() e non il delay() in quanto poi se risulterà necessario spegnere il carico prima della fine della temporizzazione, devo essere in grado di farlo.

Il codice è questo:

#include <SoftwareSerial.h>
int rxPin = 10;
int txPin = 11;
SoftwareSerial bluetooth(rxPin, txPin);
unsigned long tempo;
String message;
#define LED 4
#define rele 8
 
void setup()
{
  Serial.begin(9600); //set baud rate
  bluetooth.begin(9600); //set baud rate
  pinMode(rele, OUTPUT);
  pinMode(LED, OUTPUT);
}
 
void loop()
{
  while (bluetooth.available()) {
    message += char(bluetooth.read());
  }
  if (!bluetooth.available())
  {
    if (message != "") {
 
      if (message == "1") {
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        delay(20);
        message = "";
      }
      if (message == "2") {
        digitalWrite(rele, LOW);
        digitalWrite(LED, LOW);
        delay(20);
        message = "";
      }
      if (message == "3") {
        tempo=millis();
        digitalWrite(rele, HIGH);
        digitalWrite(LED, HIGH);
        if ((millis() - tempo) >= 5000) {
          digitalWrite(rele, LOW);
          digitalWrite(LED, LOW);
          delay(20);
          message = "";
        }
      }
    }
  }
}

il problema è che la temporizzazione non va. Se metto un delay(), invece si. Penso che il motivo sia che ad ogni passaggio l'uguaglianza tempo=millis() venga riconfermata sempre e quindi l'equazione
if ((millis() - tempo) >= 5000)
non potrà mai essere soddisfatta.

Soluzioni? Posso resettare il millis()?

Ovviamente è sbagliata la logica del codice (millis() NON va resettata ... è un errore concettuale volerlo fare).

Devi impostare tempo = millis() SOLO ed esclusivamente quando veramente devi cominciare a contare il tempo e NON sempre e comunque ad ogni giro altrimenti è ovvio che il tempo non sarà mai passato.

Guglielmo

Ciao Guglielmo, l'istante preciso è questo:

if (message == "3") { .....

cioè quando dall'app invio il comando. Quindi io penso di farlo già...ma mi rendo conto che sbaglio qualcosa, solo che non saprei come correggere...

Ma ogni volta che il message == 3 devi azzerare il conteggio e ripartire a contare ? ? ?

Se SI, porta fuori il controllo dei millis e condizionalo con una flag così viene effettuato SOLO se la flag è vera.

Guglielmo

In effetti no, tramite app invio 3 una volta sola, e ciò che vorrei accadesse lato arduino è:

si accende il carico
parte la temporizzazione
al termine della temp, si spegne il carico