Ciao a tutti, questo è il mio primo post qui.
Volevo realizzare un orologio (un po' particolare, ma non è questo il punto) usando l'Arduino Diecimila. Sono partito dalla cosa base, ovvero tenere il tempo (hh:mm:ss) usando le funzioni dell'Arduino. Ho scritto questo codice, che ho trovato in giro su internet e che dovrebbe aggirare l'overflow di millis():
unsigned long current_millis_value = 0;
unsigned long previous_millis_value = 0;
unsigned long m = 0;
unsigned int seconds = 0;
unsigned int minutes = 0;
unsigned int hours = 0;
void loop() {
current_millis_value = millis();
m += current_millis_value - previous_millis_value;
seconds += m / 1000;
m = m % 1000;
minutes += seconds / 60;
seconds = seconds % 60;
hours += minutes / 60;
minutes = minutes % 60;
hours = hours % 24;
previous_millis_value = current_millis_value;
delay(150);
}
La prima cosa che noto testando questo codice (ho attaccato dei LED all'Ardunio grazie ai quali posso leggere minuti e secondi) è che l'Arduino tende ad andare più veloce di un normale orlogio. Ho misurato, riferendomi a un orologio via web che è sincronizzato con un orologio atomico, che l'Arduino va avanti di un secondo ogni due ore, abbastanza linearmente. E' normale che il clock dell'Arduino non sia precisissimo???
Ora, questo probema sarebbe anche risolvibile se, da programma, ogni due ore scalo la variabile dei secondi. L'errore verrebbe minimizzato e reso trascurabile.
Ho poi testando il comportamento del codice all'overflow di millis(), dopo circa 9 ore e mezza. E qui c'è il problema peggiore. Non riesco a capire perchè, nel momento dell'overflow, l'orologio (partito dalle 00:00:00) passa da 09:32:39 a 09:45:27!
Vi giuro, mi sto scervallando a capire questo problema, ma niente... Voi che mi dite???
Sto risolvendo il problema grazie all'aiuto di bens in una sezione inglese del forum. http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1215338347
Ovviamente (per completezza e per aiutare chi in futuro si troverà nella mia stessa condizione) posterò qui il codice finale e le considerazioni fatte una volta risolto il tutto.
Secondo me sbagli ad affidarti al clock del micro.
Solitamente si usa un RTC (real time clock): un intergrato (es. DS1302 della maxim) che si interfaccia via I2C è ti fornisce oraio e data. Poi lascia ad arduino il compito di ricevere i dati dall'RTC, spedirli ad un LCD o fagli compiere le operazioni a seconda dell'ora/data.
Questa è la prassi (figurati che esistono microcontrollori con l'RTC integrato).
Ho letto infatti di orologi costruiti così, con l'Arduino e un integrato specifico.
Ma non volevo complicarmi troppo la vita, così ho pensato di usare il clock dell'Arduino. Secondo le specifiche del suo oscillatore, l'Arduino dovrebbe avere un errore massimo di 2sec circa ogni giorno. Nel topic inglese puoi leggere le mie prove (ho 1 secondo di errore ogni due ore) e quelle di altri due utenti che sono increduli dei miei risultato (loro hanno un errore di gran lunga più piccolo). Magari sono io ad aver avuto sfortuna...
Sta di fatto che dopo diversi test, l'errore di -0.5sec/h senbra decisamente costante e preciso perciò correggendolo da algoritmo, dovrei riuscire a ridurlo tanto da renderlo trascurabile.
Per quanto riguarda l'overflow di millis(), ho corretto in modo perfetto l'algortitmo che lo "aggira". L'errore nel codice precedente era dovuto ad una mia svista. millis() non va in overflow perché va in overflow l'unsigned long con cui viene rappresentato (il mio algoritmo partiva da questo sbagliato presupposto). Va invece in overflow a causa dei calcoli interni alla funzione (se qualcuno vuole approfondire legga il topic inglese o guardi la funzione millis() in [Arduino001]\hardware\cores\arduino\wiring.c). L'algoritmo deve quindi considerare il valore massimo che può assumere millis() (calcolato e testato a 34359737, quindi in overflow a 34359738), e su questo fare i suoi calcoli:
#define MAX_MILLIS_VALUE 34359738
unsigned long current_millis_value = 0;
unsigned long previous_millis_value = 0;
unsigned long m = 0;
unsigned int seconds = 0;
unsigned int minutes = 0;
unsigned int hours = 0;
void loop() {
cli(); // disable interrupts
current_millis_value = millis();
sei(); // enable interrupts
// overflow millis()
if (current_millis_value < previous_millis_value)
m += MAX_MILLIS_VALUE - previous_millis_value + current_millis_value;
else m += current_millis_value - previous_millis_value;
seconds += m / 1000;
m = m % 1000;
minutes += seconds / 60;
seconds = seconds % 60;
hours += minutes / 60;
minutes = minutes % 60;
hours = hours % 24;
previous_millis_value = current_millis_value;
delay(150);
}
Questo codice è stato testato per 21 ore finora, e funziona.
Ho letto infatti di orologi costruiti così, con l'Arduino e un integrato specifico.
Ma non volevo complicarmi troppo la vita, così ho pensato di usare il clock dell'Arduino.
L'RTC non ti complica la vita, anzi il contrario....basta solo una lettura dal bus I2C e nient'altro, e ottinei anche un risultato di gran lunga più preciso e non prechi risorse di 'Arduino.
Insomma se un giorno dovessi usare questo orologio per qualcosa di concreto, che va oltre il semplice esperimento personale, valuta la soluzione con RTC.
Insomma se un giorno dovessi usare questo orologio per qualcosa di concreto, che va oltre il semplice esperimento personale, valuta la soluzione con RTC.
Sì, certo, prenderò in considerazione questa soluzione, se necessario. Al momento quello che voglio realizzare è un orologio a LED che indichi HH:MM da mettere nella mia stanza, che si comporti come il TIX Led Clock che puoi trovare su ThinkGeek (il numero di led accessi in ciascuno dei quattro riquadri indica la rispettiva cifra nell'indicazione HH:MM, e i led si accendono ogni volta in configurazioni casuali). E' solo un'esperimento personale per usare l'Arduino in qualcosa di concreto, uno sfizio più che altro...
Perdonatemi se sfrutto questo topic per un'altra domanda, ma il tema è esattamente lo stesso: vorrei costruire i solito orologio utilizzando un RTC. Ho trovato parecchio materiale sugli integrati Maxim (tipo il ds1302), ma non ho trovato un sito italiano da dove comprarli (non ho un negozio vicino a casa e non vorrei buttar via capitali in spedizione).