Orologio a palette. Master clock

Buona sera , sto per andare a nanna , ma so che dormirò serenamente perché domattina ( spero) sarò più vicino alla soluzione del mio quesito.
Siccome possiedo un vecchio , e fantastico, orologio/datario a palette (nota marca in quel di Udine)
vorrei molto vederlo in funzione. Il mio modello ha bisogno di un "pilota" che lo faccia girare. Ricordo , proverò successivamente a banco , che voglia ai suoi soli due capi di connessione una tensione da 24v DC che però inverte la polarità ad ogni impulso. (ogni minuto).
Che poi magari qualcuno di voi è un reduce di questi fantastici oggetti e mi potrà correggere se sto ricordando male.
Comunque sia , ad ora sono riuscito a scrivere un codice per avere l'ora esatta e riesco anche ad azionare un comando ad ogni minuto (grande soddisfazione per me....non immaginate quanto)
Ora il dilemma : come posso "ciclare" un output? sarebbe questa la strada da seguire?
oppure esiste un relé commutatore ?
Arduino si ricorda se ha azionato un output? potrei usare il costrutto switch?
Boh, spero sia chiara la mia richiesta.
grazie .

/* COLLEGARE PULSANTI C.TO DEBOUNCE*/

#include <TimeLib.h>
#include <Wire.h>
#include <PCF8574_HD44780_I2C.h>
PCF8574_HD44780_I2C lcd(0x27,16,2);
#include <DS3232RTC.h>
time_t t;
tmElements_t tm;

#define settaggio 10  //pulsante settaggio
#define avanti 9      //pulsante +
#define indietro 8    //pulsante -

int indiceset      = 0;  // indice utilizzato per avviare e gestire la routine di settaggio dei parametri
int setta          = 0;  // valore pulsante settaggio
int su             = 0;  // pulsante +
int giu            = 0;  // pulsante -
int incremento     = 0;  // valore utilizzato per aumentare o diminuire il parametro in via di settaggio
int indicedati     = 0;  // indice di scorrimetno della tabella tabdati
int riga           = 0;  // riga del display sulla quale si sta agendo
int datodaesporre  = 0;  // parametro in via di esposizione
long tempoprec     = 0;  // zona di memorizzazione del momento dell'ultima esposizione dei dati
long tempocorrente = 0;  // zona di memorizzazione del momento corrente
int intermittenza  = 0;  // 0 espone il parametro, 1 non espone il parametro
int tabdati [21]         // tabella di acquisizione dei parametri
{ // min   max  valore
  10,     99,      0,   // anno
  1,      12,      0,   // mese
  1,      31,      0,   // giorno
  0,      23,      0,   // ora
  0,      59,      0,   // minuto
  0,      59,      0,   // secondo
  0,      0,       0,   // centesimi
};
int digits         = 0;    // zona di memorizzazione dei minuti e dei secondi da esporre sul display lcd
char tabmesi [37]  =  "genfebmaraprmaggiulugagosetottnovdic";  // tabella descr. mesi
int mese           = 0;    // zona di memorizzazione del mese corrente
int lavoro         = 0;    
int era_minuti ;
int ora_minuti ;

void esponidati()
{
  lcd.setCursor(0, 0);
  lcd.print("   ");
  lcd.print(day());
  lcd.print(' ');
  mese = month();                        
  mese = mese - 1;                       
  lcd.print (tabmesi [(mese * 3)]);      
  lcd.print (tabmesi [(mese * 3 + 1)]);  
  lcd.print (tabmesi [(mese * 3 + 2)]);  
  lcd.print(' ');
  lcd.print(year());
  lcd.setCursor(4, 1);
  lcd.print(hour());
  digits = (minute());
  printDigits();                         
  digits = (second());
  printDigits();                         
}
void printDigits()
{
  lcd.print(':');
  if (digits < 10)
    lcd.print('0');
  lcd.print(digits);
}

void sincronizzarduino () //settaggio dell'orologio e routine di sincronizzazione del timer di arduino con il timer del ds3231
{
  lcd.clear ();
  lcd.setCursor(0, 0);       
  setSyncProvider(RTC.get);  // sincronizza il timer di Arduino con i dati presenti sul modulo RTC
  lcd. clear ();
  if (timeStatus() != timeSet)  // verifica se la sincronizzazione e' andata  a  buon fine
    lcd.print(" orologio non");
  else
    lcd.print("   orologio");
  lcd.setCursor (0, 1);
  lcd.print  (" sincronizzato");
  delay (1500);
}

void acquisiscidati () //settaggio dell'orologio
{
  lcd.clear ();
  // inserisce in tabdati i valori provenienti dal timer di arduino
  tabdati [2] = year();
  tabdati [2] = tabdati [2] - 2000;
  tabdati [5] = month ();
  tabdati [8] = day ();
  tabdati [11] = hour ();
  tabdati [14] = minute ();
  tabdati [17] = second ();
 
  for (indiceset = 0; indiceset < 6; indiceset = indiceset)
  {
    esponitabdati ();
    setta = 0;
    su    = 0;
    giu   = 0;
    incremento = 0;
    setta = digitalRead (settaggio);
    su    = digitalRead (avanti);
    giu   = digitalRead (indietro);
    if ((setta == 1) || (su == 1) || (giu == 1))
      delay (500);   // attende 5 decimi di secondo per evitare di interpretare una doppia pressione
    if (setta == 1)
      indiceset ++;
    if (su == 1)
      incremento = 1;
    if (giu == 1)
      incremento = -1;
    //
    // modifica il parametro corrente di tabadati con il valore presente in  "incremento" e verifica
    // che il nuovo valore in tabdati non ecceda i limiti
    tabdati [(indiceset * 3) + 2] = tabdati [(indiceset * 3) + 2] + incremento;
    if (tabdati [(indiceset * 3) + 2] > tabdati [(indiceset * 3) + 1])
      tabdati [(indiceset * 3) + 2] = tabdati [(indiceset * 3) + 1];
    if ( tabdati [(indiceset * 3) + 2] < tabdati [(indiceset * 3) ] )
      tabdati [(indiceset * 3) + 2] = tabdati [(indiceset * 3)];
  }
  //  inserisce in ds3231 i nuovi dati
  tm.Year = y2kYearToTm(tabdati [2]);
  tm.Month  = tabdati [5];
  tm.Day    = tabdati [8];
  tm.Hour   = tabdati [11];
  tm.Minute = tabdati [14];
  tm.Second = tabdati [17];
  t         = makeTime(tm);
  RTC.set(t);           // aggiorna (setta) il modulo RTC
  setTime(t);           // aggiorna (setta) il modulo RTC
  indiceset = 0;        //  azzera l'indice di tabdati e riprende le normali funzioni dell'orologio
}

void esponitabdati ()  //esposizione dei dati in via di settaggio
{  
  tempocorrente = millis ();
  if ((tempocorrente - tempoprec) > 500)  // espone solo se sono passati piu' di 5 decimi di secondo dall'ultima visualizzazione
  {
    tempoprec = tempocorrente;
    riga = 0;
    lcd.setCursor (6, 0);
    lcd.print ("/");
    lcd.setCursor (9, 0);
    lcd.print ("/");
    lcd.setCursor (6, 1);
    lcd.print (":");
    lcd.setCursor (9, 1);
    lcd.print (":");
    for (indicedati = 0; indicedati < 6; indicedati++)
    { // espone i parametri presenti in tabdati
      if (indicedati > 2)
        riga = 1;
      datodaesporre = tabdati [(indicedati * 3) + 2];
      lcd.setCursor (((indicedati - riga * 3) * 3) + 4, riga);
      if (datodaesporre < 10)
        lcd.print ("0");
      lcd.print (datodaesporre);
    }
    riga = 0;
    if (indiceset > 2)
      riga = 1;
    if (intermittenza == 1)  // gestisce il blinking del parametro corrente
    {
      intermittenza = 0;
      lcd.setCursor (((indiceset - riga * 3) * 3) + 4, riga);
      lcd.print ("00");
    }
    else
    {
      intermittenza = 1;
      datodaesporre = tabdati [(indiceset * 3) + 2];
      lcd.setCursor (((indiceset - riga * 3) * 3) + 4, riga);
      if (datodaesporre < 10)
        lcd.print ("0");
      lcd.print (datodaesporre);
    }
  }
}

void setup()
{
  Serial.begin (9600);       
  pinMode (settaggio, INPUT);  
  pinMode (avanti, INPUT);     
  pinMode (indietro, INPUT);   
  pinMode (13, OUTPUT);        
  lcd.begin(16, 2);          
  lcd.backlight();           
  lcd.print ("   buongiorno");
  delay (1500);
  sincronizzarduino ();  // sincronizza il timer di arduino con i dati forniti da ds3231
  lcd.clear();
  
}

void loop()
{
  int ora_minuti = minute() ;
  indiceset = 0;
  indiceset = digitalRead (settaggio);
  if (indiceset == 1)    // se e' stato premuto il pulsante di settaggio
  { delay (500);         // attende un secondo per evitare l'interpretazione di una doppia pressione)
    acquisiscidati ();   // lancia la routine di settaggio
  }
  
  tempocorrente = millis();
  if ((tempocorrente - tempoprec ) > 900)  // se e' passato piu' di un secondo dall'ultima visualizzazione
  {
    esponidati ();
    tempoprec = tempocorrente;
    }
  if (ora_minuti != era_minuti) {
    digitalWrite (13, HIGH);
    delay(500);
    digitalWrite (13, LOW);
    era_minuti = ora_minuti ;
  }
 
}

Si, cioè non è che sia proprio chiaro. Certamente dopo un digitalWrite(2, HIGH) esegui
if (digitalRead(2) == true) Serial.println("il 2 è HIGH");

Verrà stampato nel serial monitor:
il 2 è HIGH

Quindi se lo ricorda eccome.

Il resto invece non è chiaro, ad esempio: come posso ciclare ...

Domani provo a rileggere il tutto magari intuisco qualcosa.

Ciao.

Io adoro gli orologi a palette :star_struck:
Ne ho ben 4, di cui 3 dei Fratelli Solari come il tuo (a proposito, che modello è?)

Lo sketch che hai allegato è solo a scopo di prova immagino perché vedo LCD ed altre cose "estranee".

Ad ogni modo per i due orologi che hanno lo stesso principio di funzionamento del tuo (24V invertiti ogni minuto), io ho fatto uno sketch molto molto semplice:

  • uno step-up per ottenere i 24V a partire dai 5 di alimentazione
  • un driver per motore DC cosi da avere tutta l'elettronica per pilotare l'elettromagnete già pronta all'uso
  • un DS3231per il timing (il clock dei vari Arduino & Co. è notoriamente poco adatto per un orologio)
  • un Arduino Pro Mini ridotto all'osso per limitare i consumi (rimossi led e regolatore di tensione)

Il DS3231 viene impostato per generare un'onda quadra di 1 Hz sull'uscita predisposta che verrà usata come base dei tempi. Ogni 60 secondi il micro invia un impulso in tensione all'elettromagnete invertendone la polarità (ovviamente per mezzo del driver DC).

Tra un secondo ed il successivo, il micro va in deepsleep giusto perché non ha nient'altro da fare (inizialmente pensavo di alimentarlo a batteria, ma poi l'ho lasciato sempre collegato).

Può accadere che al primo avvio, l'orologio perda un minuto perché l'impulso non è della polarità corretta. Siccome l'orologio alla fine sta sempre acceso (ed ha una batteria che ho comunque lasciato come backup), ho deciso di ignorare questo "malfunzionamento" e regolare il minuto mancante all'occorrenza.

1 Like

Dolce mattina , grazie mille a tutti!
Non avevo menzionato alla marca , perché avevo paura che non si potesse :face_with_hand_over_mouth:
io ho un Solari cifra 2 syncron in funzione a memoria d'uomo , ed un Dator 6042. é quest'ultimo che vorrei mettere in funzione.
Ecco , usare un driver mi sembra una "gallata" , oltretutto ne ho già uno ( IBT 2) ed ho anche diversi Sketch in cui ci giocavo :grin:.
Oggi ci lavoro su , ed anche se posso dedicarci parecchio tempo realisticamente non so riuscirò a fare tutto in giornata...
Per ora grazie ancora.

Nooo è esagerato.
Io ho usato un DRV8838 mi pare... sta su un'unghia e fa tutto quello che deve.


Belli gli orologi! I miei sono un po' più moderni... ho un Solar, due Cifra 6 ed un "clone" di marca francese

Beh, io pensavo di tenere spento il display e non pensavo ad una batteria tampone ( però sarebbe da fare....ancora da studiare , uff...non si finisce proprio mai :grinning:).
Per il resto direi che ci sono quasi....

Questa è tosta per me...devo studiarla.

Ah ecco...vabbè , magari oggi vedo di farlo girare con quello che ho , intanto che arriva quello che mi hai suggerito.

Già , personalmente ritengo siano delle vere e proprie opere d'arte . Fanno parte di quelle poche "cose" che si potevano creare in autonomia e umanamente ; "cose" d'altri tempi che coinvolgevano e tessevano la comunità.

1 Like

Ce ne sono di tanti tipi, non devi necessariamente usare quello.
Ad esempio quelli a doppio canale si trovano molto più facilmente online.

Ma se l'RTC lo usi come generatore di impulso unitario ogni secondo che necessità hai di risvegliare il MC ogni secondo per consumare inutilmente energia? Lascialo dormire e risveglialo manualmente solo quando hai la necessità di leggere o impostare ora e data

Inoltre manda in sleep anche il driver della bobina perché quel tipo di orologi a bobina che siano a cartellino o a lancette sono fatti per fare durare una singola cella batteria ,litio da 3.7V nel tuo caso, per un anno o due

Il clock è di un impulso al secondo perché purtroppo non si può fare diversamente con il DS3231, ma il segnale da mandare all'orologio invece ha una frequenza di una volta al minuto quindi devo "contare" gli impulsi.

Pensandoci bene, potrei valutare l'idea di impostare un allarme che genera interrupt spostandolo di minuto in minuto, ma come dicevo non ho più l'esigenza vera di ridurre i consumi perché alla fine ho deciso di lasciarlo collegato al cavo.

Ho ripreso in mano il driver , e però parte del mio problema rimane.
Come faccio ad alternare il comando?

  if (ora_minuti != era_minuti) {
    digitalWrite (13, HIGH);
    delay(500);
    digitalWrite (13, LOW);
    era_minuti = ora_minuti ;

al momento io sto ragionando in questo modo , però come faccio a digli che una volta metterò HIGH al PIN13 e la volta successiva sarà HIGH il pin12 ?
Si può fare con un costrutto if / else ?
Non voglio che lo scriviate voi , solo sapere se è fattibile.
Se si , poi dovrei fare un costrutto while in cui aggiorno le variabili , giusto?

Grazie.

byte drvPin = 12;

void loop() {
    if (drvPin == 12) {
        digitalWrite(drvPin, HIGH);
        drvPin = 13
    } else {
        digitalWrite(drvPin, HIGH);
        drvPin = 12;
    }
}

Oppure in un milione di modi diversi, ad esempio contatore 0 1 2 3 4 5, se è pari usi il 12 se è dispari usi il 13,

Ciao.

Wow! dvrPin non credo di averlo mai visto.
Avevo pensato anch'io ad usare un contatore, però non ancora ben capito come mettere tutti i pari insieme, lo dovrei fare con un Array, giusto? ... è un argomento che fatico a mettere in pratica....
Grazie mille!

Come dice @Maurotec ci sono mille modi...

Ad esempio, visto che il numero che "controlla" tutto è quello dei minuti, potresti semplicemente controllare se è pari oppure dispari senza aggiungere ulteriori variabili.

void doPulse(int num) {
  // Operatore ternario (vedilo come una forma "contratta" di if-then-else)
  // condizione ? vero : falso

  // Se l'operazione modulo %2 di num è == 1 -> allora num è dispari e pin = 13
  int pin = (num % 2) ? 13 : 12;  
  digitalWrite (pin, HIGH);
  delay(500);
  digitalWrite (pin, LOW);
}
............

if (ora_minuti != era_minuti) {
  doPulse(era_minuti);
  era_minuti = ora_minuti ;
}
1 Like

Non è proprio il caso di fare Wow, il nome di una variabile la decide il programmatore e poi con quella variabile di ci si fa quello che serve.
Invece studia bene, ma proprio bene quello che ti ha mostrato @cotestatnt, in particolare questo:

Però se non hai ben chiaro il resto del codice come ad esempio il passaggio di argomenti a funzione usato qui:

farai fatica a capire e non potrai fare tuo ciò che vedi nel codice.

Ciao.

1 Like

Uff....che figura! :smiling_face_with_tear:
Ero col cellulare e mi credevo che dvrPin fosse un magheggio di quelli che diventano rossi :wink:
Vabbè , non è certo la prima e non sarà l'ultima.

Intanto sperimento e imparo....tenendo conto del tempo che scorre a palette.
Grazie mille a tutti.
Grazie davvero.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.