Costruzione Orologio a led da parete - guida per dummies

zoomx:
Ma lo tieni all'aperto? Perché se non vede i satelliti potrebbe non mantenere la precisione.

Il fenix 3 è uno smartwatch che ha anche la funzione GPS per tracciare le attività, ma rimane comunque un'orologio....

tra l'altro ieri con l'aggiornamento all'ora solare ho provato a sincronizzarlo nuovamente e mi ha perso 10 secondi in un botto solo ..... MMM :sob: ora sembra stabilizzato... domani vi dico meglio :wink:

Io nei miei esperimenti ho usato un PC che aggiornava frequentemente (non troppo!) l'orario con un server NTP. Lo fa anche lo smartphone ma se tolgo la connessione Internet e il GPS va avanti di parecchio.
Ecco perché suggerivo una versione con ESP8266 e sincronizzazione NTP.
Ma tu come setti l'ora?

zoomx:
Ma tu come setti l'ora?

abbiamo inserito due pulsanti (uno per i minuti e uno per l'ora)... perchè?

Perché quando regoli l'orologio usando solo le ore e minuti lasci fuori i secondi per cui è normale che non siano sincronizzati al secondo.
Esempio.
Il fenix segna 12:10:50
Tu regoli il nuovo orologio a 12:10 ma i secondi possono essere qualsiasi, ad esempio 30 per cui già in partenza sei indietro di 20 secondi.
In alcuni orologi, quando regoli i minuti e passi ad un'altra regolazione i secondi si azzerano per cui se tu regoli al cambio del minuto sei sincronizzato meglio.

zoomx:
In alcuni orologi, quando regoli i minuti e passi ad un'altra regolazione i secondi si azzerano per cui se tu regoli al cambio del minuto sei sincronizzato meglio.

Si ma infatti lo sketch di Claudio_F prevede che quando si pigia il pulsante dei minuti vengano azzerati anche i secondi. Ovviamente io il pulsante lo schiaccio esattamente al cambio del minuto sul mio orologio...
E' come se ci sia stato uno sbalzo legato ad un "movimento" strano dell'hardware.
Ora sono fuori, stasera faccio una verifica ulteriore e poi vi dico :wink:

Probabilmente avevo sbagliato qualcosa nell'ultima sincronizzazione... sta di fatto che ora i 10 secondi di ritardo accumulati li sta piano piano riguadagnando... ora sono 7 :slight_smile:
praticamente ha guadagnato 3 secondi in 4gg... ripeto, nulla di che (e per quello che mi riguarda può andare bene così com'è).
Tuttavia siccome dovrei veramente farne altri per alcuni parenti, mi piacerebbe cercare di darglieli il più precisi possibile :wink:
.... Magari so cosa regalare a natale :smiley:

Ecco perché uso l'ESP8622. Si sincronizza lui e pensa anche al cambio dell'ora legale. Tutti i progetti che avevo iniziato con Arduino e RTC li sto convertendo proprio per questo.
Però serve una WiFi.

zoomx:
Ecco perché uso l'ESP8622.

Eventualmente che ESP mi consigli? ho guardato alcune recensioni su amazon ma non mi convincono molto...
come potrei integrarlo a tutto il circuito già fatto senza stravolgerlo ovviamente?

Potresti usarlo come uno shield WiFi. Ci dovrebbe essere uno shield che usa un ESP8266. Se invece hai più conoscenze di elettronica prendi il modulino ESP-01, che ormai in Cina è sui 2 euro, e lo colleghi all'Arduino con 2 pin per una seriale software. Questa è forse la soluzione migliore per integrare il WiFi nel tuo progetto esistente. Va alimentato a parte a 3.3V.

L'ESP8266 non ha molti pin in confronto all'Arduino, una decina solamente e ha una sola porta con convertitore A/D, non so alla fine quanti ne usi in questo progetto. Se ci bastano la conversione non è molto difficile, l'ESP8266 usa quasi le stesse istruzioni di Arduino però lavora a livelli 3.3V. I progetti che ho convertito fanno uso dei Neopixel (un anello di 12 led colorati) e di uno schermino OLED. La differenza consiste nell'aggiunta delle poche istruzioni per il collegamento in WiFi e il codice per prendere il tempo dai server NTP. Inoltre ho usato la libreria RTClib di Adafruit che permette di usare le stesse istruzioni base sia che usi un RTC hardware come il DS3231, sia che usi un RTC software.

Scusate! :slight_smile:
intanto buon anno a tutti !!
riprendo ancora questo post prima di chiuderlo definitivamente per chiedere:
se volessi alimentare l'orologio a batterie anzichè con la corrente cosa devo fare?
pensate sia conveniente? intendo: non è che a batterie me ne consuma una serie a notte :).

Auguri ancora a tutti!!

Altra piccola domanda: se volessi fare in modo che l’orologio alterni anche la data, pensate si possa fare aggiornando solo il software? Oppure dovrei mettere mano anche all’hardware?
Come sapete al’interno c’è un rtc che governa il tutto ma l’impostazione iniziale dell’ora avviene tramite due pulsanti... mi viene il dubbio che ne servano altri per la data :slight_smile:

Ancora una.... ;).
se volessi, sulla falsa riga di quanto già fatto finora, creare una radiosveglia artigianale da inserire in un box di un vino pensate sia possibile?
apro un nuovo topic per questa richiesta?

Possibile, e' possibile quasi tutto (tranne estirpare i corrotti dai tribunali e da montecitorio, e guarire il cancro con una pastiglia :D) ... ad esempio, uno dei circuiti che avevo postato prevedeva delle uscite extra con cui pilotare buzzer, ricevitore radio, sirena da tornado :D, o quant'altro si volesse ... ci sara' ovviamente da modificare anche lo sketch, oltre che il circuito, per la radiosveglia (se non avevi gia previsto le uscite extra, ma magari si possono saldare dei fili su quello che hai gia fatto e fare un piccolo millefori con il resto ;))

Prima della radiosveglia (per la quale aprirò un thred apposito) torniamo un attimo alla richiesta precedente relativa all’alimentazione tramite batteria... dite che è fattibile?

Se usi un paio di batterie da camion, si :smiley: ... con tutti quei led, fai presto a prosciugare una batteria :wink:

Puoi prevedere un "pacco" di batterie, ad esempio una decina di stilo NiMh, da inserire nella struttura come alimentazione di backup per le interruzioni saltuarie di tensione di qualche minuto o masismo decina di minuti, ma quegli oggetti sono tutti pensati per un'alimentazione da rete ...

Etemenanki:
Se usi un paio di batterie da camion, si :smiley: ... con tutti quei led, fai presto a prosciugare una batteria :wink:

Bene! allora lascio così com'è :). in fondo ho già la batteria tampone dell'rtc che mi fa da backup ;).

Se riesco a scoprire l'ultimo dubbio che ho faccio riassunto e chiudo il thread dopo 14 mesi di duro lavoro :D.

Il dubbio è: se volessi fare in modo che l'orologio alterni anche la data, pensate si possa fare aggiornando solo il software? Oppure dovrei mettere mano anche all'hardware?

Si puo fare, ma avendo solo 4 cifre, dovresti fare piu passaggi ... ad esempio, che ogni 30 secondi o roba simile, faccia un ciclo di piu "schermate" da 5 secondi ... tipo ...

ore (30s) -> temperatura (5s) -> giorno : mese (5s, con i punti fissi) -> anno (5s) -> ora (30s) eccetera

I dati li prendi dall'RTC, quindi basta modificare il software in modo che faccia le alternanze ... credo che la cosa piu semplice sia una "macchina a stati temporizzati" ...

Etemenanki:
credo che la cosa piu semplice sia una "macchina a stati temporizzati" ...

Macchina a strati temporizzati??? chi la produce la nasa??? :D.
in merito alle 4 cifre mi basterebbe che alternasse (come da te suggerito) le ore alla data (giorno e mese separati dai due punti centrali). alla fine 4 cifre bastano... solo che: come inserisco nello sketch questa funzione? E' possibile dare all'Atmega la data di inizio e poi fa i calcoli tutta da sola? come detto l'impostazione dell'ora in questo momento avviene a mano... anche quando arriverà l'ora legale :slight_smile:

Non ho ancora guardato il codice (sai che sono un "meccanico", non un programmatore :D) ... gli daro' un'occhiata stasera ... ma cosi ad occhio, direi che il modo piu semplice sia fare delle funzioni che visualizzano le varie cose (esempio, una per l'ora, una per la data, e cosi via), e poi nel loop richiamarle con degli if temporizzati ed una flag ... tipo, molto grossolanamente:

nel setup, fra le altre cose, imposto la flag al valore iniziale 0 ... e la variabile del tempo precedente a millis() ...

se nel loop premo qualche pulsante per impostare data/ora/ecc, metto la flag (ad esempio) al valore 9 ... poi ...

se la flag e' a 0 e non sono ancora trascorsi 30 secondi, chiamo la funzione ore ... quando i 30 secondi sono trascorsi, metto la flag a 1 e resetto la variabile del tempo precedente a millis() ...

se la flag e' ad 1 e non sono ancora trascorsi 5 secondi, chiamo la funzione data, quando i 5 secondi sono trascorsi, metto la flag a 2 e resetto la variabile del tempo precedente a millis() ...

se la flag e' a 2 e non sono ancora trascorsi i 5 secondi, chiamo la funzione temperatura, se i 5 secondi sono trascorsi metto la flag a 0 e resetto la variabile del tempo precedente a millis() ... (solo se si vuole anche la temperatura) ...

se la flag vale 9 (vuol dire che ho premuto qualche pulsante per fare delle variazioni), chiamo la funzione imposta data/ora/ecc ... in questa funzione rimetto la flag a 0 solo quando ho finito e ne esco ...

... e cosi via ... in questo modo hai una struttura relativamente flessibile, dove per fare qualche altra modifica, bastera' aggiungere (o modificare) una o piu funzioni, ed inserire le relative chiamate se le avrai aggiunte, senza stravolgere l'intero sketch ...

Questo è il codice usato e funzionante:

#include <Wire.h>
#define CLOCK_PIN 2
#define LATCH_PIN 3
#define DATA_PIN  4
#define MIN_PULS  5
#define HOUR_PULS 6
//-----------------------------------------------------------------------------
// Variabili di lavoro globali (28 byte)
//-----------------------------------------------------------------------------
typedef struct {
    uint32_t time;
    byte     stat;
} button_t;

button_t minPulsData = {millis(), 0};   // dati pulsante minuti
button_t hourPulsData = {millis(), 0};  // dati pulsante ora
uint32_t tempoPunti = millis();         // tempi di partenza
byte     point = 1;                     // variabile per lampeggio punti
byte     error = false;                 // true se errore lettura RTC
byte     minuti = 0;                    // minuti correnti
byte     ore = 0;                       // ore correnti
byte     tabella[10] = {0xFC, 0x60, 0xDA, 0xF2, 0x66,
                        0xB6, 0xBE, 0xE0, 0xFE, 0xF6};
//-----------------------------------------------------------------------------
// Rileva click su tasti con debounch 60 ms e autorepeat dopo 1 s
//-----------------------------------------------------------------------------
bool click(byte pin, ::button_t* data){
    uint32_t elapsed = millis() - data->time;
    bool press = digitalRead(pin);
    switch (data->stat)
    {
        case 0:                             // attesa pressione
            if (press){                     // se premuto
                data->stat = 1;             // passa ad antirimbalzo
                data->time = millis();
            }
            return false;


        case 1:                             // antirimbalzo pressione
            if (!press){                    // se non premuto
                data->stat = 0;             // ritorna ad attesa
                return false;
            }
            if (elapsed > 60){              // primo click
                data->stat = 2;
                data->time = millis();
                return true;
            }
            return false;


        case 2:                             // attesa inizio autorepeat
            if (!press){                    // se non premuto
                data->stat = 3;
                data->time = millis();
                return false;
            }
            if (elapsed > 1000){            // inizio autorepeat dopo 1 s
                data->stat = 4;
                data->time = millis();
                return true;                // primo autoclick
            }
            return false;


        case 3:                             // antirimbalzo rilascio
            if (press){                     // se premuto
                data->stat = 2;
                data->time = millis();
                return false;
            }
            if (elapsed > 60)               // rilasciato
                data->stat = 0;             // torna ad attesa
            return false;


        case 4:                             // autorepeat
            if (!press){                    // se non premuto
                data->stat = 5;
                data->time = millis();
                return false;
            }
            if (elapsed > 100){             // successivi click ogni 100 ms
                data->time = millis();
                return true;
            }
            return false;


        case 5:                             // antirimbalzo rilascio
            if (press){                     // se premuto
                data->stat = 4;
                data->time = millis();
                return false;
            }
            if (elapsed >= 60)              // rilasciato
                data->stat = 0;             // torna ad attesa
            return false;
    }
}

//-----------------------------------------------------------------------------
byte binBCD(byte n){
    return ((n / 10) << 4) | (n % 10);
}
//-----------------------------------------------------------------------------
void impostaRTC(){
    Wire.beginTransmission(0x68);   // <--- indirizzo RTC su bus i2c
    Wire.write(0);                  // <--- punta al registro 0
    Wire.write(0);                  // <--- azzera secondi RTC
    Wire.write(binBCD(minuti));     // <--- imposta minuti RTC
    Wire.write(binBCD(ore));        // <--- imposta ore RTC
    Wire.endTransmission();
}
//-----------------------------------------------------------------------------
void avanzaOra(){
    ore = (ore + 1) % 24;
}
//-----------------------------------------------------------------------------
void avanzaMinuto(){
    if (++minuti == 60){
        minuti = 0;
        avanzaOra();
    }
}
//-----------------------------------------------------------------------------
void blinkPunti(){
    if (millis() - tempoPunti >= 500){
        tempoPunti += 500;
        point ^= 1;
    }
}
//-----------------------------------------------------------------------------
byte BCDbin(byte n){
    return ((n >> 4) * 10) + (n & 0x0F);
}
//-----------------------------------------------------------------------------
void leggiRTC(){
    Wire.beginTransmission(0x68);   // <--- indirizzo RTC su bus i2c
    Wire.write(1);                  // <--- punta al registro 1
    if (Wire.endTransmission()){    // <--- errore di connessione
        error = true;
        return;
    }
    Wire.requestFrom(0x68, 2);      // <--- due registri da leggere
    if (Wire.available() != 2){
        error = true;               // <--- errore di ricezione
        return;
    }
    minuti = BCDbin(Wire.read());
    ore = BCDbin(Wire.read());
    error = false;
}
//-----------------------------------------------------------------------------
// Scrittura su display con blanking primo zero e lampeggio se errore
//-----------------------------------------------------------------------------
void visualizza(){
    digitalWrite(LATCH_PIN, LOW);
    if (error && !point){
        shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, 0);
        shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, 0);
        shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, 0);
        shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, 0);
    }else{
        shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, tabella[minuti%10]);
        shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, tabella[minuti/10]);
        shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, tabella[ore%10]|point);
        shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, (ore/10) ? tabella[ore/10] : 0);
    }
    digitalWrite(LATCH_PIN, HIGH);
}
//-----------------------------------------------------------------------------
// Impostazione sistema
//-----------------------------------------------------------------------------
void setup(){
    Wire.begin();                   // inizializza bus i2c
    pinMode(MIN_PULS,  INPUT);
    pinMode(HOUR_PULS, INPUT);
    pinMode(LATCH_PIN, OUTPUT);
    pinMode(CLOCK_PIN, OUTPUT);
    pinMode(DATA_PIN,  OUTPUT);
    digitalWrite(CLOCK_PIN, LOW);
    visualizza();                   // prima scrittura su display
}
//-----------------------------------------------------------------------------
// Ciclo principale eseguito circa 800 volte al secondo
//-----------------------------------------------------------------------------
void loop(){
    leggiRTC();                     // lettura ora corrente da RTC
    blinkPunti();                   // lampeggio punti 1 Hz

    if (click(MIN_PULS, &minPulsData)){     // se premuto puls.minuti
        avanzaMinuto();                     // regola minuti
        impostaRTC();
    }

    if (click(HOUR_PULS, &hourPulsData)){   // se premuto puls.ore
        avanzaOra();                        // regola ora
        impostaRTC();
    }

    visualizza();                   // aggiorna display
}

dove e come posso inserire i tuoi suggerimenti?