Dopo il problema hardware eccomi al software! sempre per quanto riguarda il word clock.
essendo un orologio ho impostato il delay del void loop a 1000(un secondo insomma), in quanto fino ad ora non mi serviva aggiornare la matrice se non una volta al secondo.
ora c'ho montato una foto resistenza per regolarne la luminosità e un sensore capacitivo per impostarne i minuti.
Non è indispensabile ma sarebbe desiderabile che la luminosità scenda o salga non una volta al secondo, cosi come sarebbe meglio che il sensore capacitivo invii piu di un segnale al secondo.
Appesantirei molto l'arduino a farlo lavorare ad una frequenza magari di 3 loop al secondo?
Anche in termini di risparmio energetico e vita dei componenti. Vale la pena o è meglio che mi accontenti?
Inoltre noto una certa poca precisione e/o ripetibilità nell'orario: potrebbe essere che il delay di un secondo del loop dia in qualche modo fastidio al tempo scandito dal ds1307?
Ci sono troppe cose che non vanno d'accordo.
Il delay blocca il codice, ed è basato su un risonatore ceramico che è impreciso per cui può essere che alle volte un delay(1000) sia 999 ms altre che sia 1001 ms. Quindi avrai sempre uno sfasamento rispetto all'orario dato dal ds1307.
Potresti fare un controllo ogni 500 ms per vedere se l'orario è cambiato, ma usando millis e non delay.
Oppure potresti interrogare continuamente il ds1307 e cambiare l'ora quando vedi che i secondi sono cambiati.
Se ti interessa il risparmio energetico questo si ottiene mettendo il chip in standby. Ma se lo metti in standby, devi risvegliarlo.
Potresti attivare un interrupt generato dal pin clk-out del ds1307 e risvegliare il micro ad intervalli. Però perderesti il pilotaggio dell'orologio.
Un risparmio energetico non ha senso se l'arduino consuma 1/20 dei LED che segnano l'ora.
Potrestiusare il SQR OUT del RTC (1 Hz) messo su un interrupt per sincronizzare del aggiornamento dell ora.
Ciao Uwe
per quanto riguarda il consumo energetico uwefed hai perfettamente ragione.
per quanto riguarda la sincronizzazione usando l'interrupt: dovrei far ripartire il loop ad ogni segnale ad 1 Hz inviato dal pin SQW del ds1307, giusto?
se uso la libreria "RTClib.h" come richiamo il segnale del SQW da utilizzare come interrupt?
leggo in alcuni tutorial che il codice
RTC.sqw(1);
in fase di setup permette al led montato sulla shield di lampeggiare alla frequenza di 1Hz; la mia shield l'ho assemblata io secondo questo schema
e non è presente il led (ma questo credo sia ininfluente).
Però tutto ciò mi farebbe perdere in termini di tempi di risposta del sensore di luce e capacitivo.
Non so se mi conviene.
Se il delay è "un po sballato", il loop comunque dovrebbe riallinearsi al ds1307 prima o poi grazie a
DateTime now = RTC.now();
posto all'inizio del loop, o no?
Non pretendo che sia un cronografo spaccasecondo, ma solo che non accumuli ritardo isomma
Di usare un interrupt col pin del Ds1307 te l'avevo già suggerito io
Comunque basta far arrivare il pin SQW al pin D2 o D3 dell'Arduino ed agganciare un interrupt con attachInterrupt().
e in setup come dico a SQW di inviare segnali a 1Hz?
Si, me l'hai suggerito prima tu, ma per una funzione diversa!
Ragazzi, siete gentilissimi! Grazie!
edit:
mi sto informando sull 'interrupt; volendo rendere prioritaria l'esecuzione del settaggio dei minuti col sensore capacitivo alla lettura dell'orario dal DS1307, alla rilevazione di una variazione del sensore inibisco l'interrupt del SQW tramite un detachInterrupt(0)?
sto impazzendo, non riesco a farlo funzionare.
Se la funzione richiamata nell' interrupt non deve avere parametri e non deve restituire alcun valore, come cavolo si fa a farle leggere l'orario dal DS1307 tramite DateTime now = RTC.now() ed utilizzare quest'orario nel loop??
Ogni variabile usata dalla funzione richiamata dall'interrupt deve essere dichiarata come "volatile": la variabile DateTime now = RTC.now() è dichiarabile come volatile??
Ho fatto questo seplice sketch per testare ma mi stampa una sola volta "ciao" e basta
#include <Wire.h>
#include <RTClib.h>
#include <LedControl.h>
LedControl lc=LedControl(12,10,11,2);
RTC_DS1307 RTC;
volatile DateTime now;
void setup () {
Serial.begin(9600);
Wire.begin();
RTC.begin();
// Set SQW/Out signal frequency to 1 Hz.
RTC.setSqwOutSignal(RTC_DS1307::Frequency_1Hz);
attachInterrupt(0,leggiora,CHANGE);
}
void loop () {
Serial.println("ciao");
delay(500);
}
void leggiora(){
DateTime now = RTC.now();
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
}
proncito:
Se la funzione richiamata nell' interrupt non deve avere parametri e non deve restituire alcun valore, come cavolo si fa a farle leggere l'orario dal DS1307 tramite DateTime now = RTC.now() ed utilizzare quest'orario nel loop??
Devi usare delle variabili globali che potrai usare in qualunque parte del programma e a prescindere da dove gli cambi il valore, questo sarà poi visibile in tutte le altre parti dello sketch.
Ho fatto questo seplice sketch per testare ma mi stampa una sola volta "ciao" e basta
Se dichiari now all'interno della routine di interrupt, il suo valore sparisce appena l'esecuzione esce perché quella variabile è locale, quindi vale solo dentro leggiora().
Sto facendo mille tentativi, finora sono riuscito solo a far stampare una parola allo scandire dell'unterrupt, ma non riesco a far aggiornare l'ora i nessun modo; DateTime now = RTC.now() l'ho dichiarata solo dentro, solo fuori, dentro e fuori, come volatile e non volatile, DateTime now fuori e now=RTC.now dentro; insomma ho perso il conto e non sono riuscito a capire la logica dei come aggiornare "now" con l'interrupt.
Anzichè dirmi cosa fare potresti modificarmi questo semplice sketch in modo che funzioni? Cosi prendo spunto e riesco finalmente a capire e poi me lo adatto al mio sketch
#include <Wire.h>
#include <RTClib.h>
RTC_DS1307 RTC;
DateTime now;
void setup () {
Serial.begin(9600);
Wire.begin();
RTC.begin();
RTC.setSqwOutSignal(RTC_DS1307::Frequency_1Hz);// Set SQW/Out signal frequency to 1 Hz.
attachInterrupt(0,leggiora,RISING);
}
void loop () {
int ora=now.hour();
unsigned long orario=10000L*ora+100*now.minute()+now.second();
int minutaggio=100*now.minute()+now.second();
Serial.print(orario);
Serial.print(minutaggio);
delay(2000);
}
void leggiora(){
now= RTC.now();
}
Grazie!
Definisci una variabile booleana che viene posta "vera" ogni secondo tramite interrupt.
Ad ogni loop verifichi la variabile e se posta "vera" aggiorni l'orario". Per funzionare il ciclo del loop non deve durare più di 1 secondo, altrimenti perdi aggiornamenti; quindi niente delay.
#include <Wire.h>
#include <RTClib.h>
RTC_DS1307 RTC;
DateTime now;
boolean aggiorna = false;
void setup () {
Serial.begin(9600);
Wire.begin();
RTC.begin();
RTC.setSqwOutSignal(RTC_DS1307::Frequency_1Hz);// Set SQW/Out signal frequency to 1 Hz.
attachInterrupt(0, update, RISING); // chiama update 1 volta al secondo
}
void loop () {
if (aggiorna) {
now= RTC.now();
aggiorna = false;
}
int ora=now.hour();
unsigned long orario=10000L*ora+100*now.minute()+now.second();
int minutaggio=100*now.minute()+now.second();
Serial.print(orario);
Serial.print(minutaggio);
// delay(2000);
}
void update(){
aggiorna = true;
}
Non ho il DS montato, quindi non ho provato lo sketch. Tra l'altro non mi compila perché la lib che ho io non ha il metodo sqw.
Si, funziona!
Non ci avevo pensato di sfruttare l'interrupt per vie traverse, mi ero fissato sulla via diretta. Ho comunque trovato un modo per farlo ma mi piace di piu il tuo modo! Adottato!
Quindi il delay non lo devo mettere proprio o posso metterne uno tipo da 333ms?
E per rendere prioritario il settaggi dei minuti col sensore capacitivo va bene inibire l'interrupt con detachInterrupt(0) subito prima e riattivarlo subito dopo il controllo del sensore?
Se metti il delay rischi che il sensore capacitivo non funzioni: infatti se tocchi il sensore durante il delay non andrà.
L'interrupt io non lo staccherei. Basta che prima sommi il tempo e poi aggiorni l'orario con l'IF (aggiorna).
Tra l'altro puoi sempre mettere l'if alla fine del loop e non all'inizio posticipando l'aggiornamento dopo tutte le altre operazioni effettuate nel ciclo.