Ciao a tutti, Avete presente la funzione millis()?
OK
siamo abituati a vederla applicata in questo modo
unsigned long previousMillis = 0;
const long interval = 1000;
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
*
*
*
}
}
Con questo tipo di codice ho notato che l'errore andrà a sommarsi, quindi per evitare ciò ho pensato a questo tipo di codice
unsigned long previousMillis = 0;
const long interval = 1000;
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis += interval;
*
*
*
}
}
Con questo l'errore viene risolto o almeno migliorato.
Vorrei implementare al codice una funzione di start and stop solo che ho problemi a causa della funzione millis()
Ciao, non riesco a capire perché dovrebbe esserci un miglioramento. Non è una critica ma logicamente mi sembra la stessa cosa.
MI SPIEGO
Nel primo codice quando currentMillis è maggiore uguale a intervallo, assegno a previousMillis currentMillis,
che appunto è maggiore di un valore pari ad intervallo.
Nel secondo codice invece aggiungi direttamente intervallo, ma il valore è lo stesso in entrambi i casi.
O meglio la differenza può essere minima , cioé il tempo di valutazione dell'espressione, veramente minimo.
Si la differenza è minima ma applicato a un tempo lungo tipo un ora con il primo ciclo perdo tipo 1 minuto e 30 secondi mentre con il secondo metodo non perdo praticamente niente
Secondo me non è questione di perdere o no dei tempi
Sono due cadi differenti
Uno garantisce la "cadenza"
L'altro garantisce "l'intervallo"
Si sceglie quello che serve
davides98:
Si ma con RTC non riesco a scendere oltre il secondo, come potrei applicarlo per fare un countdown utilizzando il tm1637 (7 segmenti)
Mmmm ... un RTC come il DS3231 ha un pin (SQW) che da un segnale di frequenza estremamente precisa. Es. impostatono i due bit RS0 ed RS1 a (0 , 1) hai un segnale a 1024 Hz ... lo mandi su un pin di interrupt ed incrementi un contatore che, arrivato a 1023, riporti a zero. tale contatore ti permette di avere in un secondo un numero che va da 0 a 1023 ... a secondo della precisione che ti serve (decimi? centesimi?) fai la divisione e, salvo un piccolo errore di arrotondamento, hai i tuoi decimali.
Guglielmo
P.S.: Oppure, usare l'RTC per HH:MM:SS e millis() solo per i decimi/centesimi ...
davides98:
Si ma con RTC non riesco a scendere oltre il secondo, come potrei applicarlo per fare un countdown utilizzando il tm1637 (7 segmenti)
millis() non e nient'altro che un contatore (un numero) che avanza sempre dall'accensione del micro
non c'e nulla di "esoterico" in questo,
sta all 'utente il modo/maniera di utilizzarlo,
un modo sbagliatissimo e fargli fare da orologio/data perché un risuonatore ceramico e un orologio molto impreciso e soggetto a molte influenze esterne (temperatura etc),
per il resto dipende dalla capacita del programmatore
di sicuro la "formula (e simili)
unsigned long currentMillis = millis();
La differenza tra i due modi di aggiornare la variabile tempo può essere abissale.
Metti di testare la condizione quando sono già passati 1.2 secondi, il prossimo secondo periodico scade non tra un secondo, ma tra 0.8 secondi. Se ricarichi la variabile con il millis attuale aspettando un altro intero secondo sei già in ritardo di 0.2 secondi, e questo ritardo si accumula ogni volta che la valutazione della condizione è un po' in ritardo con il momento esatto in cui scade il secondo.
Vero la forma più usata è l'altra, forse per semplicità, forse perché per quegli esempi la precisione non conta o non è necessario creare periodi regolari.
gpb01: P.S.: Oppure, usare l'RTC per HH:MM:SS e millis() solo per i decimi/centesimi ...
Purtroppo il problema è il momento in cui cambia il secondo reale... che non è sincronizzato in alcun modo con il timer. Le possibilità sono due, attendere il primo cambio di secondo e da li contare il tempo (si può ritardare fino a un secondo dal momento dello start), oppure non attendere il primo cambio di secondo (e allora si può anticipare fino a un secondo dal momento dello start).
La soluzione dell'onda quadra mi aggrada, un comune contatore binario esterno (es: CD4040) la può abbassare di 16 volte ottenendo 64Hz che mi sembrano meno stringenti come tempi, e la risoluzione/errore sarebbe di onesti 15.625 millisecondi.
Non ho capito la steia del "secondo reale". Quello che lo ip sta facendo (o meglio, l'unica cosa che può fare) é un timer, vale a dire una macchina che conta del tempo da quando parte, quinci il " secondo reale" non é noto. Il mio timer di cucina se lo carico 30 minuti alle 00:00:00 mi chiamerà alle 00:30:00, e se lo carico alle 05:14:37 mi chiamerà alle 05:44:37, che é 30 minui dopo, ma che siano passati 37 secondi da inizio minuto lui non lo sa, e non gli interessa.
Può, invece forse, interessare la differenza di durata tra un secondo "reale" e un "secondo timer". In quel caso, però, va usato lo stesso fenomeno per fare i test, perché a poco giova usare l'orologio DCF77 della cucina per confrontare millis() o un altro sistema. Questo sarebbe, a mio avviso, come misurare un tavolo in pollici e dire 15, e poi ricontrollare con il metro. Se decidiamo ge il pollice é giusto ricontrollo in pollici, non in metri. Quindi prima si sceglie come misurare, poi si confronta con li stesso sistema. O in caso non sia possibile si fanno le opportune correzioni
Claudio_FF:
... Purtroppo il problema è il momento in cui cambia il secondo reale... che non è sincronizzato in alcun modo con il timer. Le possibilità sono due, attendere il primo cambio di secondo e da li contare il tempo (si può ritardare fino a un secondo dal momento dello start), oppure non attendere il primo cambio di secondo (e allora si può anticipare fino a un secondo dal momento dello start). ...
Non dovrebbe esser un problema ...
... lui deve realizzare un "count-down" ... ne momento in cui da il via legge millis() e lo usa come base per fare la differenza e visualizzare i decimi/centesimi ... e, ogni cambio dei secondi, rifà la cosa ed ha sempre un riferimento diverso come punto di partenza per il calcolo della differenza (... più difficile a spiegare che ha fare).
L'errore dovrebbe essere ridotto a pochi millisecondi ... :
Silente:
Non ho capito la steia del "secondo reale".
... quello che NON hai capito è che ha lui serve visualizzare anche i decimi/centesimi di secondo e ... mentre per HH:MM:SS va bene quello che gli restituisce l'RTC (... che è preciso) per i decimi/centesimi gli serve un altro metodo.
gpb01:
e, ogni cambio dei secondi, rifà la cosa ed ha sempre un riferimento diverso come punto di partenza
Si, una volta a regime è così, ma il problema è il primo cambio di secondoRTC dal momento dello start, che può avvenire anche subito se lo start viene dato immediatamente in prossimità del cambio secondoRTC, in pratica ci si mangerebbe subito il primo secondo.
In alternativa si attende il primo cambio, e da li si procede con millis + RTC, ma bisogna attendere il primo cambio, che può anche essere un secondo dopo lo start se si da lo start quando il secondoRTC è appena cambiato, e quindi si può ritardare di un secondo.
L'unica sarebbe azzerare l'RTC al momento dello start (se dobbiamo solo realizzare un "timer cucina" l'ora esatta non conta), allora si, i secondiRTC partirebbero sincronizzati con il momento dello start.
... altra soluzione, usare un generatore di clock esterno di precisione (... es. uno di quelli termostabilizzati) e scriversi la propria myMillis() basata sugli impulsi di detto oscillatore di precisione
Qualcosa porta via anche quel maggiore al posto di maggiore o uguale (perché anche le volte che il tempo trascorso sarebbe uguale all'intervallo voluto si fa comunque un altro giro).
previousMicros = micros(); e fratelli bannati da ogni mio codice subito
Dipende, se si vuole scandire un tempo periodico ok, ma se serve solo fare qualcosa "fra almeno" N millisecondi, e poi, anche se erano di più, di nuovo farla da quel momento "fra almeno", allora la forma "classica" va bene, e non ha il difetto di far risultare vera la condizione per molte volte di seguito (finché la variabile tempo "torna al passo") in caso di un ritardo prolungato.
Come dice standardoil sono due casi di utilizzo diversi.
Questa "previousMicros += 500;" è una semplice somma a 32 bit, pochi cicli macchina ...
... questa invece "previousMicros = micros();" è una chiamata ad una funzione con assegnazione del valore di ritono, il che comporta una grossa quantità di operazioni che coinvolgono lo stack e ... la differenza dei tempi di esecuzione e assegnazione si vedono