swRTC

si fa quel che si puo' :slight_smile:

non appena si parlo' di usare un quarzo su un pin strorsi il naso, non avevo mai fatto test su quarzi ma intuivo che i valori in gioco non lo permettevano.
Tutto cioe' che serve ad un quarzo per oscillare e' integrato nei micro, e per questo che lo si puo' attaccare solo su determinati pin.
Non ha senso questa strada perche' al posto di costruire un oscillatore esterno prendi un Rtc.

ha piu' senso a questo punto usare il micro in modalita' 32KHz quarzo + 8MHz interni, oppure lasciarla cosi', con i 16MHz e basta.
Resta il problema batteria backup

io nel frattempo ho ordinato uno schedino RTC da 6 euro che include batteria, 5 anni di autonomia senza corrente, alimentato, e quindi con la batteria a sopperire solo temporanei blackout, si arriva alla naturale morte della stessa :slight_smile:

A me l'idea del quarzo da 32 kHz mi piace.

Io direi comunque una cosa: la libreria va bene così, appena lesto completa i calcoli per tornare dal timestamp all'ora/data, faccio una modifica ed implemento una funzione RTCmodule con la quale si informa la lib che il micro opera con oscillatore interno ed ha disponibile il quarzino esterno, per chi vuole una buona precisione di calcolo e può rinunciare a 2 pin.

leo qualcosa nella tua forma non funziona: 1.0/(F_CPU/1024.0/256.0)

dici essere il numero di overflow al secondo, ma a me sembrano più la durata di un overflow, infatti a 8Mhz ottengo 0.032768, e a 16MHz ottengo 0.016384..

il numero di overflow al secondo pare essere solo (F_CPU/1024.0/256.0)

mi puoi dare conferma?

edit: come fai a dire che essendo potenze di 2 le cifre decimali non andranno mai oltre le 6?

riedit: per evitare di passare dai float ho ideato:

  duration = F_CPU;
  secondsRapresented=1;
  while(duration%262144!=0){
    duration*=10;
    secondsRapresented+=10;//the number of seconds duration rapresent
  }
  overflows = duration/262144;

ora sappiamo che ogni tot "overflows" sono trascorsi "secondsRapresented" secondi.

quindi l'interrupt diventa

counterT++;
	
	if (counterT>=overflows+delta){//if one hour is passed
	  timestamp+= secondsRapresented;//add a hour to timestamp
	  counterT-=overflows+delta; //remove one hour from counter
	}

notare il ritorno in auge del delta, settabile a mano

e il calcolo del timestamp diventa:

return timestamp + map( counterT, 0, overflows+delta, 0, secondsRapresented );

infine abbiamo di nuovo il delta:

boolean swRTC::setDelta(unsigned long deltaT) {
  if ( delta<=overflows)
    return false;
  delta=deltaT;
  return true;
}

allego la libreria, ma non è testata (ma le modifiche dalla mia originale son solo queste), so solo che compila, ma dovrebbe essere corretta. Riaggiunto il setDelta().

ora diventa un poco più macchinoso settare il delta a mano, perchè bisogna conoscere sia il valore di overflow che di secondsRapresented; forse si può semplificare un pò ma ora son stanco

swRTClesto.zip (6.08 KB)

bug trovati: i commenti nell'interrupt si riferiscono all'ora, ma sono solo rimasugli del vecchio codice.

l'if in setDelta()

 if ( delta<=overflows)

è sbagliato, corretto diventa:

 if ( deltaT<=overflows)

Ciao. Stamattina ho avuto da fare (figli a casa), vedo di dare un'occhiata ai tuoi quesiti e di controllare il codice.

Allora... è vero. La formula non dà gli overflow ma la loro durata. La formula non è mia, l'ho trovata sul forum ma non mi ricordo male. Probabilmente ho mal interpretato la spiegazione di quello che la mise ma, siccome la usavo solo per i millisecondi, pareva a logica che mi tornasse. Difatti anche quando ho provato il quarzino con il modulo RTC c'era qualcosa che non mi tornava, ricordi?

Detto questo, questo calcolo si può levare, se non ho capito male perché lo hai sostituito con quello con i long, giusto?

Per la questione del delta, che ordini di grandezza raggiungono i numeri con cui lavori? Sapendolo, si potrebbe fare in modo di far inserire all'utente un parametro da riportare poi nel range giusto.

leo72:
Per la questione del delta, che ordini di grandezza raggiungono i numeri con cui lavori? Sapendolo, si potrebbe fare in modo di far inserire all'utente un parametro da riportare poi nel range giusto.

cosa buona sarebbe :slight_smile:

giusto, non ci avevo pensato, esattamente come uso la map per cavarci i secondi veri, si può usare la map al contrario per settare il delta!!

Detto questo, questo calcolo si può levare, se non ho capito male perché lo hai sostituito con quello con i long, giusto?

sì, è stato sostituito con i long perché non mi fido della precisione dei float. potrei tentare di estrarre la matissa, ma poi tutti calcoli in base 2... sbatti

Per la questione del delta, che ordini di grandezza raggiungono i numeri con cui lavori?

secondsRapresented diventa 1000000 sia 16 che 8 MHz.

però ho trovato un altro bug:

nel while non è

secondsRapresented+=10;//the number of seconds duration rapresent

ma

secondsRapresented*=10;//the number of seconds duration rapresent

Ok. Ecco la libreria, nata dall'integrazione della precedente con le tue ultime modifiche.

Devi spiegarmi a che serve il metodo updateDate perché sinceramente non l'ho capito. Non è chiamato da nulla, non accetta nessun parametro in ingresso. Ho aggiornato anche la revisione delle versioni ed il file Readme (senza updateDate). Ho anche aggiornato il file keywords: adesso colora i nuovi metodi ed oggetti.

PS:
ho tolto i riferimenti al "fork" dato che stiamo lavorando alla stessa libreria, altrimenti si confonde la gente e basta :wink:

PPS:
da PROVARE, ho solo provato la compilazione

swRTC_0-9-1.zip (8.87 KB)

il metodo updateDate(), a partire dal timestamp aggiorna la struttura "data" (è dichiarata e inizializzata nel file .h). Essendo una struttura pubblica, può essere acceduta (ummm suona male) dall'esterno. Quindi il timestamp è aggiornato real time, la data solo quando serve.
L'ideale sarebbe eliminare quella struttura pubblica, creare un motodo getData() che ritorna una struttura mallocata al momento, ma senza un garbage collector è molto facile che "sprovveduti" della programmazione OO creino garbage.

La soluzione migliore è rendere la struttura privata, utilizzare i classici metodi getOre, etc.. e ognuna di queste funzioni per prima cosa chiama updateTime, e poi la funzione ritorna il valore contenuto nella struttura.

Sì, ho visto che è dichiarata nell'header ma non ne capivo la funzione.
Però va messa nel "retrobottega", senz'altro. Per 2 motivi: il primo è quello che hai detto tu, il secondo è perché l'aggiornamento delle variabili di stato va fatto secondo me sempre, perché il programma non può sapere se l'utente quando chiama la funzione di impostazione dell'orologio cambia solo l'ora o la data e se l'ora, durante il cambiamento, influenza anche l'orario.

leo72:
il secondo è perché l'aggiornamento delle variabili di stato va fatto secondo me sempre, perché il programma non può sapere se l'utente quando chiama la funzione di impostazione dell'orologio cambia solo l'ora o la data e se l'ora, durante il cambiamento, influenza anche l'orario.

ASSOLUTAMENTE NO!

aggiornare sempre vuol dire aggiornare dall'interrupt, ovvero calcoli inutili che diminuiscono la precisione.

E il programma SA quando l'utente cambia le impostazioni, perché non lo può fare direttamente sulle variabili (se lo fa è un errore, e volendo lo si può rendere rilevabile) ma deve chiamare le opportune funzioni, che quindi si prendono carico di effettuare i giusti cambiamenti (esattamente come le varie get chiamano updateTime(), le set richiameranno qualcosa stile resetTime() o simile)

Però va messa nel "retrobottega"

sicuramente, e quindi dovrà essere trasformato in un metodo privato della classe, ma potrà essere fatto solo quando anche la struttura "data" sarà privata e accessibile via get

oggi mi e' arrivato l'rtc e stavo cercando info per la sua implementazione, arrivo alla libreria TIME e leggo:
"The Time library adds timekeeping functionality to Arduino with or without external timekeeping hardware"

WITHOUT EXTERNAL HARDWARE ???

Che significa ? Che differenza c'e' con la tua lib ?

TUTTO OK :slight_smile:


  • TimeSerial.pde shows Arduino as a clock without external hardware.
    It is synchronized by time messages sent over the serial port.
    A companion Processing sketch will automatically provide these messages
    if it is running and connected to the Arduino serial port.

spetta spetta, pero' c'e' uno sketch che fa da orologio per arduino, e funziona pure, quindi nella libreria TIME ufficiale gia' esiste la funzione che stai creand tu con la tua lib ? :fearful: :fearful:

/*
 * TimeRTC.pde
 * example code illustrating Time library with Real Time Clock.
 * 
 */

#include <Time.h>  
#include <Wire.h>  
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t

void setup()  {
  Serial.begin(9600);
/*  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");      
*/
}

void loop()
{
   digitalClockDisplay();  
 //  delay(1000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Lo dicevo io che finiva che ci mordevamo le chiappe con sta storia :grin:
Non perdiamo di vista che l'obiettivo di Leo era evitare di usare hardware esterno, stai dicendo che lo sketch che hai postato fa diventare Arduino un RTC senza quarzi esterni e quant'altro :fearful:? cosa cavolo dici Willy?

prova a caricarlo e vedi, lanci la seriale e lui inizia a contare dal 1 gennaio 2000 senza null'altro attaccato :fearful:

Beh, è normale visto che funzioni visto che usa millis()... basta dare un'occhiata al suo sorgente.
La swRTC usa invece un timer tutto suo interrupted ha la correzione per allineare il tempo calcolato al tempo reale.
E' un approccio differente ma, secondo me, molto migliore dato che non usa funzioni precostituite di Arduino ma direttamente gli interrupt.

leo72:
Beh, è normale visto che funzioni visto che usa millis()... basta dare un'occhiata al suo sorgente.
La swRTC usa invece un timer tutto suo interrupted ha la correzione per allineare il tempo calcolato al tempo reale.
E' un approccio differente ma, secondo me, molto migliore dato che non usa funzioni precostituite di Arduino ma direttamente gli interrupt.

cioè è possibile usarlo mentre sul micro gira un altro software che usa la tua lib come se fosse un RTC esterno, giusto? MI pareva questo l'obiettivo iniziale.

Esatto.
La forza di una routine che gira in un interrupt è che è trasparente allo sketch dell'utente. Quest'ultimo può accedere al primo ma è come accedere ad un sistema chiuso.

Immagina di ordinare una pizza per telefono o di fartela in casa. Nel primo caso alzi la cornetta, fai l'ordine, poi torni a lavorare finché non suonano alla porta e te la consegnano. Nel secondo caso, sei costretto ad interrompere ciò che stavi facendo, prendere gli ingredienti, impastare la pizza e metterla in forno, dopodiché tornare periodicamente a vedere se è pronta.