Orologio \ Sveglia DCF77 RTC 6 digit 7 segmenti

Ho provato il codice ma non funziona. Faccio scrivere sulla seriale SecBCD e priorSec e quando SecBCD cambia, priorSec rimane a 0. Come mai?

Non è che una di quelle variabili è usata / impostata anche da qualche altra parte?

Eh no, SecBCD varia quando la lettura è ok e rxSec della funzione dcf() viene convertito in BCD. Dopodiché viene scritto nell'RTC e poi viene letto di volta in volta dall'RTC.
priorSec invece lo utilizzo solo la.
Allego comunque il codice, purtroppo siccome faccio riferimento a variabili anche di altre funzioni, ho fatto un po' di casino per la cronologia delle funzioni.

DCF77_Clock_6_Digit_7-Segments.ino (39 KB)

Mi sono accorto di un errore stupidissimo.

priorSec == SecBCD

quando invece doveva essere

priorSec = SecBCD

Ora anche priorSec varia, però SYNC no! Ne sto uscendo pazzo.

if(SecBCD != priorSec){SYNC = true; priorSec = SecBCD;}

L'unica cosa prima di questa riga che ho fatto è stata assegnare queste due variabili

bool SYNC = false; byte priorSec;

Nella seriale vedo variare SecBCD e priorSec nella stessa maniera e allo stesso tempo. Ciò vuol dire che entro nell'if, sennò priorSec non varierebbe.
A questo punto SYNC dovrebbe andare su true, quindi dovrei leggere un 1 sulla seriale, ma rimane a 0!

Inoltre mi sono accorto di una cosa che non pensavo si potesse fare:

if(SecBCD != priorSec){SYNC = true; priorSec = SecBCD;} Questo if dovrebbe funzionare quando SecBCD non è uguale a priorSec. SecBCD e priorSec assumono lo stesso valore. SYNC rimane false sempre però.

if(SecBCD == priorSec){SYNC = true; priorSec = SecBCD;} Questo if vale quando SecBCD e priorSec hanno lo stesso valore, il doppio uguale confronta e non assegna. Infatti in questo caso SecBCD varia, priorSec invece rimane a 0. SYNC rimane false.

if(SecBCD = priorSec){SYNC = true; priorSec = SecBCD;} Con questo if invece eguaglio SecBCD e priorSec! Non pensavo che l'argomento di un if fosse un comando, pensavo fosse solo una comparazione!
In questo caso infatti SecBCD rimane a 0, così come priorSec! SYNC rimane false.

Metti questo

Serial.println("Sono entrato nell'if");

e vedi quando lo stampa sulla seriale.

Entra nell'if ogni secondo, ma SYNC non cambia di stato.

Ho cambiato SYNC, anziché variabile booleana l'ho fatto diventare un byte. Quando cambia il secondo SYNC = 1.

Sto provando nel loop a scrivere questo:

if(SYNC == 1){digitalWrite(DCF77ErrorLED, 1); SYNC = 0;}

In questo modo però il LED rimane acceso fisso mentre SYNC rimane sempre a 0. Questo perché quando SYNC va a 1 accendo il LED ma non lo spengo mai, mentre SYNC appena va a 1 viene assegnato il valore 0.

A questo punto però dovrei fare un ciclo che dopo 500 mS mi spegne il LED.

if(SYNC == 1){digitalWrite(DCF77ErrorLED, 1); SYNC = 0; if(millis() - DCF77ErrorLEDTime >= DCF77ErrorLEDLoop){DCF77ErrorLEDTime = millis(); digitalWrite(DCF77ErrorLED, 0);}}

Ho scritto questo, ma il LED rimane spento, mentre:

if(SYNC == 1){digitalWrite(DCF77ErrorLED, 1); SYNC = 0; DCF77ErrorLEDTime = millis(); if(millis() - DCF77ErrorLEDTime >= DCF77ErrorLEDLoop){DCF77ErrorLEDTime = millis(); digitalWrite(DCF77ErrorLED, 0);}}

Il LED rimane acceso.

Non ci sto capendo più niente.

Hai messo tutte le operazioni sotto la condizione SYNC che si verifica per un solo ciclo.

if(SYNC) {                              // se evento sync
    digitalWrite(DCF77ErrorLED, 1);     //   accende
    SYNC = 0;                           //   azzera evento
    DCF77ErrorLEDTime = millis();       //   salva tempo iniziale
}
if (digitalRead(DCF77ErrorLED)                              // se acceso
    && millis() - DCF77ErrorLEDTime >= DCF77ErrorLEDLoop)   // e timeout
        digitalWrite(DCF77ErrorLED, 0);                     //   spegne

Non pensavo che l'argomento di un if fosse un comando, pensavo fosse solo una comparazione!

L'if valuta la booleanità (verità) del risultato dell'espressione contenuta tra parentesi, che in pratica è falsa per 0 e vera per tutto il resto. Incidentalmente(?) in C anche un assegnamento ritorna un valore, e può essere scritto come argomento di un if. Non so se esistono altri linguaggi che permettono questo tipo di errore (scambiare = con ==), peraltro molto comune e subdolo.

E' incredibile come io compia tanti errorini stupidi!

Infine un'altra cosa che non riesco a capire è questa:

void gestDCF77ErrorLED2(){
  switch (DCF77ErrorLEDStat){
    case 0:
      digitalWrite(DCF77ErrorLED, 1);
      break;
    case 1:
      if(SYNC){
        digitalWrite(DCF77ErrorLED, 1);
        SYNC = false;
        DCF77ErrorLEDTime = millis();
      }
      if(digitalRead(DCF77ErrorLED) && millis() - DCF77ErrorLEDTime >= DCF77ErrorLEDLoop)
        digitalWrite(DCF77ErrorLED, 0);
    case 3:
      digitalWrite(DCF77ErrorLED, 0);
      break;
  }
}

void gestDCF77ErrorLED(){
  switch (DCF77ErrorLEDStat){
    case 0:                                     /* caso 0, DCF77ErrorLED sempre acceso */
      digitalWrite(DCF77ErrorLED, 1);           /* accendi DCF77ErrorLED */
      break;
    case 1:                                     /* caso 1, ogni 500 mS cambia stato a DCF77ErrorLED */
      if(millis() - DCF77ErrorLEDTime >= DCF77ErrorLEDLoop){  /* confronta il contatore dei mS con il tempo precedentemente salvato, quando la differenza è maggiore di 500 mS */
        digitalWrite(DCF77ErrorLED, 1);         /* accendi DCF77ErrorLED */
        DCF77ErrorLEDTime += DCF77ErrorLEDLoop; /* aumenta la variabile del tempo di 500 mS così da azzerare l'if sopra */
        DCF77ErrorLEDStat = 2;                  /* passa a caso 2 */
      }
      break;
    case 2:                                     /* caso2, aspetta 500 mS e spegni DCF77ErrorLED, passa a caso 1 */
      if(millis() - DCF77ErrorLEDTime >= DCF77ErrorLEDLoop){  /* confronta il contatore dei mS con il tempo precedentemente salvato, quando la differenza è maggiore di 500 mS */
        digitalWrite(DCF77ErrorLED, 0);         /* spegni DCF77ErrorLED */
        DCF77ErrorLEDTime += DCF77ErrorLEDLoop; /* aumenta la variabile del tempo di 500 mS così da azzerare l'if sopra */
        DCF77ErrorLEDStat = 1;                  /* passa a caso 1 */
      }
      break;
    case 3:                                     /* caso 3, DCF77ErrorLED, sempre spento */
      digitalWrite(DCF77ErrorLED, 0);           /* spegni DCF77ErrorLED */
      break;
  }
}

I codici sono equivalenti, però se chiamo la versione con il SYNC (gestDCF77ErrorLED2() ) il LED sta spento fisso, mentre se chiamo la versione "tradizionale" (gestDCF77ErrorLED() ) il LED funziona regolarmente. La chiave di volta è DCF77ErrorLEDStat che mi manda nei vari case. Finché è "a riposo" la variabile è uguale a 3, quando deve lampeggiare è uguale a 1, quando deve stare accesa fissa è uguale a 0, e funziona correttamente.

Anche qui non riesco a capire come mai una versione funziona e l'altra no.

Comunque ho applicato la parte del tuo codice ai LED dei secondi e funziona ottimamente!
Appena ho un attimo di tempo applico a tutti i cicli di LED e al buzzer questo, così da averli tutti sincronizzati, però non mi spiego come mai la versione "nuova", sebbene utilizzi lo stesso caso ... stato di quella "vecchia", non funziona correttamente.

Hai dimenticato il break.

void gestDCF77ErrorLED2(){
  switch (DCF77ErrorLEDStat){
    case 0:                                     /* caso 0, DCF77ErrorLED sempre acceso */
      digitalWrite(DCF77ErrorLED, 1);           /* accendi DCF77ErrorLED */
      break;
    case 1:                                     /* caso 1, al cambiare del secondo blinka DCF77ErrorLED per 500 mS */
      if(SYNC){                                 /* quando SYNC = true */
        digitalWrite(DCF77ErrorLED, 1);         /* accendi DCF77ErrorLED */
        SYNC = false;                           /* porta SYNC = false */
        DCF77ErrorLEDTime = millis();           /* salva in DCF77ErrorLEDTime il tempo in millis() */
      }
      if(digitalRead(DCF77ErrorLED) && millis() - DCF77ErrorLEDTime >= DCF77ErrorLEDLoop){  /* quando DCF77ErrorLED è acceso AND la differenza fra millis() e il tempo salvato da quando SYNC = true è maggiore o uguale di DCF77ErrorLEDLoop */
        digitalWrite(DCF77ErrorLED, 0);         /* spegni DCF77ErrorLED */
      }
      break;
    case 3:                                     /* caso 3, DCF77ErrorLED sempre spento */
      digitalWrite(DCF77ErrorLED, 0);           /* spegni DCF77ErrorLED */
      break;
  }
}

Così intendi? Avevo provato anche ieri ma non funziona comunque.

Si intendevo quel break.

Però con il break aggiunto non vedo errori, neppure di precedenza degli operatori.

Non so perché ma, quando chiamo la funzione gestDCF77ErrorLED2() anziché la versione tradizionale, la variabile DCF77ErrorLEDStat rimane a 3 e non cambia. Addirittura la flag rxError non mi va a true, perché ho messo nell'if(rxError) anche un Serial.println per capire se entra la dentro e non viene stampato. Mentre se chiamo la funzione gestDCF77ErrorLED() non ci sono problemi. Cosa sta succedendo?! Io continuo a guardare e riguardare il codice.

In questo momento sto stampando a seriale DCF77ErrorLEDStat e vari messaggi per sapere in che case sono. Il multiplexing del display è molto lento e magari la funzione per il dcf() non funziona con le tempistiche giuste perché il processore è occupato per troppo tempo con le stampate sulla seriale che avviene ad ogni clock. Devo provare a stampare su seriale solo in caso di cambio della variabile.

Ho sistemato il codice di debug, in maniera tale da scrivere su seriale solo nel momento in cui i dati cambiano.
DCF77ErrorLEDStat adesso entra nel caso 1, ma il LED rimane spento.

case 1:                                     /* caso 1, al cambiare del secondo blinka DCF77ErrorLED per 500 mS */
      if(DCF77ErrorLEDStat != DCF77ErrorLEDStatPrior){Serial.println("Sono entrato nel caso 1 di gestDCF77ErrorLED2()"); DCF77ErrorLEDStatPrior = DCF77ErrorLEDStat;}
      if(SYNC){                                 /* quando SYNC = true */
        digitalWrite(DCF77ErrorLED, 1);         /* accendi DCF77ErrorLED */
        SYNC = false;                           /* porta SYNC = false */
        DCF77ErrorLEDTime = millis();           /* salva in DCF77ErrorLEDTime il tempo in millis() */
        Serial.println("Sono entrato in if di SYNC di gestDCF77ErrorLED2()");
      }
      if(digitalRead(DCF77ErrorLED) && millis() - DCF77ErrorLEDTime >= DCF77ErrorLEDLoop){  /* quando DCF77ErrorLED è acceso AND la differenza fra millis() e il tempo salvato da quando SYNC = true è maggiore o uguale di DCF77ErrorLEDLoop */
        digitalWrite(DCF77ErrorLED, 0);         /* spegni DCF77ErrorLED */
        Serial.println("Sono entrato nel conteggio di gestDCF77ErrorLED2()");
      }
      break;

Non entra in SYNC. Potrebbe essere dovuto al fatto che SYNC lo porto a false già con la funzione che mi fa blinkare i LED da 4 mm ogni secondo?

Perché in pratica io adesso porto a true la flag SYNC ad ogni cambio di secondo, poi ogni funzione che ha bisogno di SYNC mi porta a SYNC = false una volta che ricevono l'impulso. Forse una gestione di questo genere non va bene.

Infatti ho eliminato tutte le funzioni che utilizzano la stessa strategia, cioè di portare a false SYNC una volta utilizzato, e la funzione funziona (scusate il gioco di parole).
A questo punto che strategia posso usare? Posso farlo tornare a SYNC = false dopo diciamo un 50 mS automaticamente?

in poche parole vado a fare questo codice:

if (SecBCD != priorSec){SYNC = true; priorSec = SecBCD; SYNCTime = millis();}  /* ogni cambio di secondo porta SYNC = true, che poi viene azzerato dalle funzioni che lo sfruttano */
if(SYNC && millis() - SYNCTime >= SYNCHigh){SYNC = false;}

Le funzioni che utilizzano il SYNC non si sballano, perché la condizione per "cominciare a contare" per poi spegnere il LED è appunto che il LED sia High e poi che il conteggio vada "fuori" del valore che ho prefissato. Ma io comincio a contare da quando SYNC = true e non mi interessa per quanto tempo SYNC rimane = true.

Bene, siamo riusciti con una flag SYNC a sincronizzare tutti gli eventi con il cambio del secondo! Per il momento ci siamo!

Claudio_FF però adesso volevo capire il tuo discorso su come spegnere le singole digit con l'uso dei 4543. Devo dire che non ho studiato troppo a fondo il datasheet per mancanza di tempo però.

Mentre ti faccio questa richiesta, cerco di fare autonomamente la funzione sia per impostare il fatto che solo quando ore minuti e secondi coincidono allora suoni la sveglia e soprattutto la lettura della flag della sveglia. Mi sto rileggendo il datasheet del DS3231. Qualcosa avevo buttato giù come codice, ma il secondo non funziona, devo ancora ragionarci un po' su.

Intanto, il codice per far suonare la sveglia quando ore minuti e secondi coincidono è questo qui:

void readRTCAlarm(){
    Wire.beginTransmission(0x68);               /* indirizzo RTC su bus i2c */
    Wire.write(0x07);                           /* punta al registro 7 */
    if (Wire.endTransmission()){RTCError = 1; return;}  /* errore di connessione */
    Wire.requestFrom(0x68, 3);                  /* tre registri da leggere */
    if (Wire.available() != 3){RTCError = 2; return;}  /* errore di ricezione */
    aSecBCD = Wire.read() - 0B10000000;         /* leggi secondi allarme RTC */
    aMinBCD = Wire.read();                      /* leggi minuti allarme RTC */
    aHourBCD = Wire.read();                     /* leggi ore allarme RTC */
    RTCError = 0;                               /* azzera variabile errore RTC */
}

void setRTCAlarm(){
    Wire.beginTransmission(0x68);               /* indirizzo RTC su bus i2c */
    Wire.write(0x07);                           /* punta al registro 7 */
    Wire.write(0B10000000 + aSecBCD);           /* imposta l'allarme che suoni quando combaciano ore minuti secondi e imposta i secondi allarme RTC */
    Wire.write(aMinBCD);                        /* imposta minuti allarme RTC */
    Wire.write(aHourBCD);                       /* imposta ore allarme RTC */
    Wire.endTransmission();                     /* fine trasmissione */
}

Questo dovrebbe andare bene, quando vado a salvare il valore dei secondi, aggiungo il bit 7. Quando vado a leggere l'RTC tolgo il bit 7 e leggo l'orario corretto. In questo modo il bit 7 è sempre "alto".

Ho finalmente capito bene come funzionano i bit e i registri del DS3231.

In pratica io devo impostare i bit della tabella "Alarm Mask Bits", in questo caso voglio che "suoni" soltanto quando corrispondono ore, minuti e secondi. Per fare ciò devo mettere a 1 il bit 7 chiamato "A1M4" del registro 0A e azzerare (essere sicuro che stiano a 0) gli altri bit 7 chiamati "A1M1", "A1M2", "A1M3" dei registri 07, 08, 09.

void setRTCAlarm1(){
    Wire.beginTransmission(0x68);               /* indirizzo RTC su bus i2c */
    Wire.write(0x07);                           /* punta al registro 7 */
    Wire.write(0B00000000 + aSecBCD);           /* imposta secondi allarme 1 RTC e azzera gli altri bit */
    Wire.write(0B00000000 + aMinBCD);           /* imposta minuti allarme 1 RTC e azzera gli altri bit */
    Wire.write(0B00000000 + aHourBCD);          /* imposta ore allarme 1 RTC e azzera gli altri bit */
    Wire.write(0B10000000);                     /* imposta il bit 7 del registro 0Ah "A1M4" a 1 in maniera tale che la flag per l'allarme 1 sia uguale a 1 quando combaciano ore, minuti, secondi */
    Wire.endTransmission();                     /* fine trasmissione */
}

Per quanto riguarda la lettura, tolgo la stessa cosa che ho aggiunto, per mera simmetria nel ragionamento più che altro

void readRTCAlarm1(){
    Wire.beginTransmission(0x68);               /* indirizzo RTC su bus i2c */
    Wire.write(0x07);                           /* punta al registro 7 */
    if (Wire.endTransmission()){RTCError = 1; return;}  /* errore di connessione */
    Wire.requestFrom(0x68, 3);                  /* tre registri da leggere */
    if (Wire.available() != 3){RTCError = 2; return;}  /* errore di ricezione */
    aSecBCD = Wire.read() - 0B00000000;         /* leggi secondi allarme RTC, tolgo quello che ho aggiunto quando ho scritto nel registro */
    aMinBCD = Wire.read() - 0B00000000;         /* leggi minuti allarme RTC, tolgo quello che ho aggiunto quando ho scritto nel registro */
    aHourBCD = Wire.read() - 0B00000000;        /* leggi ore allarme RTC, tolgo quello che ho aggiunto quando ho scritto nel registro */
    RTCError = 0;                               /* azzera variabile errore RTC */
}

Per quanto riguarda vedere quando corrispondono orario corrente e orario allarme succede questo:

Quando c'è il match, comanda la tabella "Alarm Mask Bits". Quando è vera quella, il bit flag, cioè il bit 1 chiamato "A1F" del registro 0F, passa a 1.

Se poi il bit 1 chiamato "A1E" è a 1 e il bit 3 chiamato "INTCN" è a 1, entrambi del registro 0E, allora quando A1F = 1 ho il segnale sull'uscita INT/SQW dell'integrato.

A me interessa leggere semplicemente la flag A1F

void readRTCAlarm1Stat(){
    Wire.beginTransmission(0x68);               /* indirizzo RTC su bus i2c */
    Wire.write(0x0F);                           /* punta al registro 0F */
    if (Wire.endTransmission()){RTCError = 1; return;}  /* errore di connessione */
    Wire.requestFrom(0x68, 1);                  /* un registro da leggere */
    if (Wire.available() != 1){RTCError = 2; return;}  /* errore di ricezione */
    reg0F = Wire.read();                        /* leggi il registro 0F */
    RTCError = 0;                               /* azzera variabile errore RTC */
    
    Serial.println(reg0F);
    if((reg0F & 1) == 1){A1F = true;}           /* la variabile booleana è true se il primo bit è 1 */
    else {A1F = false;}                         /* in ogni altro caso la variabile è false */
}

Devo provare il codice!
E dovrei un attimo riguardare la parte che azzera tutti i bit, quando vado a fare la scrittura dei registri per l'allarme 1, magari lo faccio con un & . In quel caso comunque potrei togliere la parte in cui tolgo 0B00000000 quando vado a leggere l'orario allarme 1.

E infatti il codice non funziona.

Io stampo a seriale il registro 0F, quello con all'interno la flag per l'alarm 1. Ma questo registro è sempre uguale a 128, cioè il bit 7 chiamato "OSF" è a 1, com'è giusto che sia. Anche il bit 3 chiamato "EN32kHz" dovrebbe essere a 1, ma il bit 1 "A1F" è a 0. Infatti se stampo anche il valore di A1F esso rimane a 0. Il problema è che la flag rimane a 0 anche quando l'orario corrente corrisponde a quello impostato in alarm 1.

Nel registro 0A ho scritto 0B10000000 e mi succede quello che ho appena descritto. Se anziché scrivere il byte in bit scrivo direttamente 128, il registro 0F è uguale a 129 e la flag A1F è positiva.

Adesso ho provato a scrivere nel registro 0A "0B10000000" al posto di 128, riportando tutto come scritto nel post precedente, ma ora il registro 0F mi rimane a 129 con A1F = 1.

Come mai un comportamento del genere?

Buonasera a tutti, oggi ho fatto qualche prova ma nulla di nuovo. Non ho ben capito se la flag dopo che è andata a 1 devo azzerarla.

Inoltre non ho ben capito quando utilizzare i numeri in esadecimale, quando in decimale e quando in binario. Ho cambiato un po' i numeri decimali in esadecimale quando vado a fare le operazioni sui bit e ora non funziona più nulla. Non capisco come mai. Adesso ho fatto questo codice ma non l'ho provato. Nella funzione reset prima erroneamente ho fatto un OR anziché un & ed ho azzerato il registro 0F tranne che per il bit 1, cioè la flag A1F:

void setRTCAlarm1(){
    Wire.beginTransmission(0x68);               /* indirizzo RTC su bus i2c */ /* 0x68 in esadecimale, 0B01101000 in binario, 104 in decimale */
    Wire.write(0x07);                           /* punta al registro 07 */ /* 0x07 in esadecimale, 0B00000111 in binario, 7 in decimale */
    Wire.write(aSecBCD &= 0x7F);                /* imposta secondi allarme 1 RTC e azzera gli altri bit */ /* 0x7F in esadecimale, 0B01111111 in binario, 127 in decimale */
    Wire.write(aMinBCD &= 0x7F);                /* imposta minuti allarme 1 RTC e azzera gli altri bit */ /* 0x7F in esadecimale, 0B01111111 in binario, 127 in decimale */
    Wire.write(aHourBCD &= 0x7F);               /* imposta ore allarme 1 RTC e azzera gli altri bit */ /* 0x7F in esadecimale, 0B01111111 in binario, 127 in decimale */
    Wire.write(aDayDateBCD |= 0x80);            /* imposta il bit 7 del registro 0Ah "A1M4" a 1 in maniera tale che la flag per l'allarme 1 sia uguale a 1 quando combaciano ore, minuti, secondi */ /* 0x80 in esadecimale, 0B10000000 in binario, 128 in decimale */
    Wire.endTransmission();                     /* fine trasmissione */
}

void readRTCAlarm1Stat(){
    Wire.beginTransmission(0x68);               /* indirizzo RTC su bus i2c */ /* 0x68 in esadecimale, 0B01101000 in binario, 104 in decimale */
    Wire.write(0x0F);                           /* punta al registro 0F */ /* 0x0F in esadecimale, 0B00001111 in binario, 15 in decimale */
    if (Wire.endTransmission()){RTCError = 1; return;}  /* errore di connessione */
    Wire.requestFrom(0x68, 1);                  /* 1 registro da leggere */ /* 0x68 in esadecimale, 0B01101000 in binario, 104 in decimale */
    if (Wire.available() != 1){RTCError = 2; return;}  /* errore di ricezione */
    reg0F = Wire.read();                        /* leggi il registro 0F */
    RTCError = 0;                               /* azzera variabile errore RTC */
    
    if(reg0F & 1){A1F = true; A1FTime = millis();}  /* la variabile booleana è true se il primo bit del registro 0F è 1 */ /* 0x01 in esadecimale, 0B00000001 in binario, 1 in decimale */
    if(A1F && millis() - A1FTime >= A1FHigh){A1F = false; resetRTCAlarm1Stat();}  /* porta a false la flag A1F dopo 50 mS */
    
}

void resetRTCAlarm1Stat(){
  Wire.beginTransmission(0x68);                 /* indirizzo RTC su bus 12c */ /* 0x068 in esadecimale, 0B01101000 in binario, 104 in decimale */
  Wire.write(0x0F);                             /* punta al registro 0F */ /* 0x0F in esadecimale, 0B00001111 in binario, 15 in decimale */
  Wire.write(reg0F &= 0xFE);                    /* fai un AND del registro con il byte che ha 0 solo nel bit 1, così da azzerare il bit 1 */ /* 0xFE in esadecimale, 0B11111110 in binario, 254 in decimale */
  Wire.endTransmission();                       /* fine trasmissione */
}

Ora ho fatto una prova. Ho azzerato A1F con la funzione resetRTCAlarm1Stat(). Flasho con la funzione readRTCAlarm1Stat() attivata. Giustamente il registro 0F è pari a 0 finché non scatta l'allarme. Quando scatta il registro va a 1 e A1F va a 1. Però non torna a 0 dopo aver trascorso il tempo necessario, evidentemente non trascorre il tempo necessario, perché invece la flag A1F è positiva.

if(reg0F & 1){A1F = true; A1FTime = millis();}  /* la variabile booleana è true se il primo bit del registro 0F è 1 */ /* 0x01 in esadecimale, 0B00000001 in binario, 1 in decimale */
if(A1F && millis() - A1FTime >= A1FHigh){A1F = false; resetRTCAlarm1Stat();}  /* porta a false la flag A1F dopo 50 mS */

Mi sembra di rifare le stesse funzioni già fatte e che funzionano ma di volta in volta non funzionano.

La domanda sui numeri esadecimali, binari e decimali resta però! Da quando ho cambiato i numeri decimali in numeri esadecimali sia nella conversione binBCD e vice versa, sia nella funzione DCF, il DCF77ErrorLED non blinka più e non so perché.

Insomma sto impazzendo, le mie basi non sono così solide per essere sicuro del codice che faccio e quello che fino a prima sembrava funzionare perfettamente poi non funziona bene. Sono tornato alla vecchia versione con i numeri decimali ma il DCF77ErrorLED continua a non blinkare.

I numeri scritti in bin / esa / dec sono la stessa cosa.

Si usa la forma che in quel contesto rende più chiaro il programma.

Ad esempio una maschera AND che "lasci passare" i soli bit 4:3 è più chiara scritta come B00011000 che 24 o 0x18.


Il driver CD4553 (tabella datasheet pagina 5) permette due condizioni di blank (quelle in basso) quando l'ingresso D3 è alto, ed è alto almeno uno tra D2 e D1.

Ora non ricordo bene a quali pin di Arduino sono stati collegati questi segnali, ma nella routine di visualizzazione se non sbaglio si leggeva un array (memoria video), quindi basta scrivere nell'array un valore con questi bit alti, ad esempio 12, e la cifra corrispondente risulterà spenta (in questo modo si potrebbe implementare il lampeggio delle singole cifre)

...quasi spenta... perché rimane il problema del leggero aliasing tra le cifre è creato dal multiplex senza blanking tra una cifra e l'altra.

Se non sbaglio il selettore dei digit (IC5 dello schema del post iniziale) ha l'uscita 0 non usata, quindi si potrebbe attivare quell'uscita per spegnere tutte le altre, calcolare i nuovi valori e riscrivere.

Prendendo spunto dalla routine multiplex di qualche post indietro così potrebbe andare:

// bit 4:2 di PORTD = DIGIT
// bit 7:5 di PORTD = i tre bit bassi di VALUE
// bit 0   di PORTB = bit alto di VALUE
void display6digit7segment(byte DIGIT1, byte DIGIT2, byte DIGIT3)
{
    byte VALUE;
    PORTD &= B00000011;  // indirizza digit 0 inesistente
    switch (DIGIT = 1  +  DIGIT % 6)
    {
      case 1:  VALUE = DIGIT1 & B00001111; break;
      case 2:  VALUE = DIGIT1 >> 4;        break;
      case 3:  VALUE = DIGIT2 & B00001111; break;
      case 4:  VALUE = DIGIT2 >> 4;        break;
      case 5:  VALUE = DIGIT3 & B00001111; break;
      case 6:  VALUE = DIGIT3 >> 4;
    }
    PORTB = (PORTB & B11111110) | (VALUE >> 3);
    PORTD = (PORTD & B00000011) | (DIGIT << 2) | (VALUE << 5);
}

Wire.write(aSecBCD &= 0x7F);

Attenzione che con &= non calcoli solo un'espressione, ma effettui un assegnamento/modifica della variabile 'aSecBCD'