DS3231 Per misurare millisecondi

Buongiorno, sto cercando di realizzare un timer sportivo, ho quindi bisogno di sincronizzare 2 o piú dispositivi con lo stesso orario ma anche avere una precisione di almeno 3 millisecondi mmm. Millis() dopo pochissimo tempo diventa completamente inaffidabile, ho letto molti thread online ma nessuno che dia soluzioni concrete su come fare. Ho letto di usare un modulo GPS con il pin pps per resettare un timer ottenuto con millis() ogni volta, non so se sia il metodo piu sensato. Ho letto anche di usare un DS3231 che puó teoricamente andare a frequenze diverse per contare i secondi e poi calcolare da questi i ms? Ma non mi é chiaro l'approccio da usare. Qualcuno ha qualche idea?

Benvenuto nella sezione Italiana del forum :slight_smile:

Cortesemente, leggi attentamente il REGOLAMENTO di detta sezione:
[REGOLAMENTO] Come usare questa sezione del forum
(... e, per evitare future possibili discussioni/incomprensioni, prestando molta attenzione al punto 15)
e poi, come da suddetto regolamento (punto 16.7), fai la tua presentazione IN CODA ALL'APPOSITA DISCUSSIONE:
Presentazioni nuovi iscritti: fatevi conoscere da tutti! (Part 2)
spiegando bene quali esperienze hai in elettronica e in programmazione, affinché noi possiamo conoscere la tua esperienza ed esprimerci con termini adeguati.

Grazie
Gianluca

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposita discussione, nel rispetto del succitato regolamento, nessuno ti risponderà (eventuali risposte, o tuoi ulteriori post, verrebbero temporaneamente nascosti), quindi ti consiglio di farla al più presto. :wink:

P.P.S.: Evitate di utilizzare la traduzione automatica fatta dal browser ... vi impedisce di capire la lingua della sezione dove andate a scrivere ...

Grazie, ho appena completato quanto richiesto.

Mmm ... normalmente i modulini basati su DS3231 mettono a disposizione il pin SQW che può essere programmato per fornire vari frequenze (1Hz, 1024Hz, 4096HZ e 8192Hz) che puoi usare come frequenza da dare in ingresso al clock di un timer e generare un interrupt con il periodo voluto.

Se il modulo espone il pin 1 (32KHz), come normalmente è:

Using a DS3231 Module with Arduino • AranaCorp

... allora hai anche a disposizione un oscillatore a frequenza più elevata fisso a 32 KHz da usare sempre allo stesso modo.

Guglielmo

Grazie per la risposta. Sono un neofita, che approccio mi consigli di usare? Sto usando una board LOLIN32 LITE che ha un esp32 come chip (non so se è rilevante nella scelta). Quale approccio mi assicura un conteggio dei ms più affidabile? Dove posso leggere come configurare un approccio tale, se c'è qualche guida che già affronta questa tematica. Grazie mille in anticipo.

Benvenuto, Alessandro! :slight_smile:

Potresti spiegare esattamente che cosa vuoi fare, in particolare a proposito di "sincronizzare due o più dispositivi con lo stesso orario? Start e stop vengono forniti a un solo dispositivo o a due dispositivi diversi? I dispositivi possono essere collegati con un cavo?

Gianluca

Scusate non sono stato preciso.
Due o più dispositivi registrano il tempo quando vengono oltrepassati. Prima di essere posizionati devono avere il tempo syncronizzato per assicurarsi che i risultati siano coerenti. Che sia l'ora vera o meno è secondario l'importante è che se ci ha messo 10 secondi e 343 millesimi quello sia effettivamente il valore stampato. All'inizio quindi questi possono essere collegati tra loro da un cavo per effettuare la Sync ma successivamente si troveranno a diversi metri di distanza che non renderà possibile ciò.
In sintesi il primo dispositivo alla partenza prende un tempo es 10:15:37.372 il secondo poi 10.16.02.842 e poi magari un terzo e così via. L'importante è l'intervallo di tempo tra i vari checkpoint. È per una gara di regolarità in sintesi. Ora l'importante è assicurarmi la coerenza dei tempi ottenuti, poi il passaggio dei dati e il resto mi è già chiaro come realizzarlo. Quindi semplicemente ora facendo i miei test collegando due schede con un bottone in comune e andando a stampare il valore di millis sfora già dopo pochi secondi dove uno è potenzialmente davanti l'altro rendendo quindi il risultato non attendibile.

Visto che si tratta di esp32, una possibile soluzione potrebbe essere configurarne uno come NTP server e far sincronizzare gli altri con il primo.

L'unica incognita sono i tempi di latenza delle richieste UDP che però un una LAN locale dovrebbero essere minimi (e soprattutto costanti).

Diciamo che come ho già detto non è rilevante che il tempo sia effettivamente il tempo effettivo. Può anche essere mezzanotte, l'importante è la coerenza dei dati, dato che il tempo può essere preso in un qualunque momento avere un server ntp che fornisce l'orario ogni tanto con latenze non necessariamente prevedibili (il primo esp32 può arrivare ad una distanza di 1km dallultimo potenzialmente) non mi sembra adatto alla mia situazione. La parte rilevante qui è il conteggio dei millisecondi corretto essendo una gara dove 10 ms fanno effettivamente la differenza

Curiosità... Trattandosi di tempi (presumo) relativamente brevi, non sarebbe sufficiente rendere più preciso millis() e usare solo quello?
Si da lo start in sincrono e poi si fa la differenza...
La faccio troppo facile?

... ottimo ... dicci come (per di più su ESP32) :slight_smile:

Guglielmo

Mmm ... normalmente i modulini basati su DS3231 mettono a disposizione il pin SQW che può essere programmato per fornire vari frequenze (1Hz, 1024Hz, 4096HZ e 8192Hz ) che puoi usare come frequenza da dare in ingresso al clock di un timer e generare un interrupt con il periodo voluto.

Avresti una qualche fonte che posso consultare per realizzare questo timer utilizzando il pin dei 32Khz per un esp32 attraverso gli interrupt? Grazie in anticipo

No, su Arduino si, sui moduli ESP non so nulla ... occorre studiarsi l datasheet e vedere come programmare i timers per un clock esterno ... NON è cosa banale.

Guglielmo

Capisco, riusciresti comunque a darmi un mano per Arduino per capire come comportarmi, sinceramente non mi servono per questo le funzionalità dell'esp ma l'ho preso per la comodità di avere il collegamento della batteria ricaricabile quindi potrei facilmente prendere una board Arduino se ciò mi assicurasse di riuscire nel mio intento. Grazie in anticipo

Non sono così ferrato in materia... Ho letto il tuo post sui DS e i pin con le varie frequenze... E ho dato per scontato che si potesse fare...
Mi taccio per evitare ulteriori brutte figure.

Intanto ti do un documento che scrisse tempo fa un ex admin di questo forum, leo72 ...

Timer.pdf (747.4 KB)

... così vedi, sugli AVR, come funzionano i timers e come puoi fornirgli un clock esterno.

Se poi vai nell'indice delle librerie, nella sezione "timing" ... probabilmente trovi anche librerie già fatte per la loro gestione ... :roll_eyes:

Guglielmo

1 Like

Grazie, ho studiato un po come affrontare il problema intanto che aspettavo arrivasse il modulo DS3231, ma ho scoperto che usa un cristallo 32.768 khz e che quindi non ho un tick preciso che segna il millisecondo e che quindi andrebbe fuori sync ogni ciclo di un po, non assicurandomi una misurazione precisa. Quindi non so bene come dovrei fare per affrontare il problema

Mi sembra che tu ti stia facendo del male da solo

Se i moduli ds3231 danno un impulso ogni ms lo calcoleranno loro in qualche loro maniera, magari con divisori programmabili, non darti pena per "come" fanno non è un tuo problema

Comunque perché vuoi contare gli impulsi uno ogni ms?

Metti un ds3231 per ogni unità periferica e chiedi direttamente al ds3231 l'ora, è il suo lavoro...

Basta solo che li sincronizzi tra loro tutti una volta sola prima della gara

Nella gara però è importante misurare il tempo segnato con i ms, nel caso di pareggio di secondi sono i ms a fare la differenza e il modulo ds3231 non ha una risoluzione così alta.
In più non ha un impulso ogni ms, ha un cristallo di 32.7...kHz e posso settarlo ad un po' di meno ma comunque numeri non arrotondabili ad impulsi per secondo preciso quindi non utili per misurare in modo preciso. Stavo pensando di controllare il cambio del secondo nel modulo e a quel punto resettare il timer millis() sperando che in un secondo non sia troppo sballato. Così facendo stampando il valore di millis ad ogni cambio di secondo ottengo circa 850/1000 risultati uguali a 1000ms passati, quindi giusti e gli altri uguali a 999 o 1001, che mi assicurerebbe una precisione del centesimo di secondo circa che comunque non è tanto male ma mi chiedo se si possa fare di meglio, esistono pur cronometri da gara con precisione più alta..

Il quarzo nei sistemi che misurano il tempo è storicamente da 32768Hz perché si tratta di una potenza di 2 ovvero 2^15. In questo modo basta ad esempio una catena di flip-flop per arrivare con semplicità ad un segnale ad una frequenza di 1Hz per cadenzare il secondo con una buona precisione.

Nel tuo caso, hai bisogno di una risoluzione di 1ms, e potresti quindi dividere questo clock per 32 sfruttando il prescaler dei timer inclusi nell'ESP32 cosi viene fatto tutto a livello hardware.
La risoluzione sarebbe addirittura migliore perché 32768/32 fa 1024 ovvero 0.9765ms di incremento minimo.

Ricapitolando:

  • configuri un timer dell'ESP32 per fare in modo che venga incrementato da un clock esterno (32768Hz). Il timer dovrà avere un prescaler da 32.
  • abiliti l'interrupt del timer e nella ISR associata incrementi un contatore. Siccome c'è il prescaler l'incremento sarà ogni 1/1024 secondi. Se contatore == 1023, azzeri il valore (oppure fai un modulo 1024).

Quando devi leggere il tempo sul giro, ottieni il valore fino ai secondi leggendo i normali registri del DS3231 e la parte dei millesimi facendo una semplice proporzione del valore del contatore attuale (X = contatore / 1024);

Siccome la fonte del clock è la stessa i valori saranno sicuramente sincronizzati.

Edit
La stessa cosa la puoi fare sfruttando il pin SQW come ti hanno già suggerito, cosi da evitare il prescaling del clock (in pratica lo fa già il DS3231 internamente se noti quali sono i valori di frequenza disponibili).