Go Down

Topic: RTC DS3231 impostare allarmi (Read 2570 times) previous topic - next topic

zoomx

Ho visto su GitHub che l'impostazione degli allarmi è una cosa sentita, c'è uno che ha proposto una modifica per gli allarmi ma su PCF8523.

Ci sono librerie apposta per il DS3231 che gestiscono tutto.

ziopippo

Il cambio delle librerie la potrei anche fare ma sicuramente non mi metto a reimpostare tutti gli allarmi ora che ho quasi finito (con molta fatica e tanto tempo dedicato). Mi restano solo un paio di funzioni di implementare ed un controllo sulle temperature per ultimare tutto il progetto. Se posso invece risolvere il problema delle date lo farei molto volentieri.  ;)

Claudio_FF

#92
May 24, 2018, 06:32 pm Last Edit: May 24, 2018, 06:49 pm by Claudio_FF
Quote from: ziopippo
Questa è la dichiarazione delle variabili:
Code: [Select]

uint8_t tmpYear;

Il motivo per cui ho dovuto fare quelle strane sottrazioni non me lo spiego neanche io, soprattutto quella relativa al 2018.
Ok, tutto chiaro, più o meno, c'è ancora un errore nascosto da qualche parte ma adesso è chiaro.

Partiamo dal principio.

La funzione 'year()'  restituisce un valore a 16 bit compreso tra 1970  2069.

La cosa più semplice sarebbe quindi usare una 'tmpYear' da 16 bit (una banale variabile tipo int) per manipolare l'anno (regolandolo quindi con l'encoder dal 1970 al 2069), e poi sottrarre 1970 quando la si vuole copiare nella 'tm.Year', perché 'tm.Year' è un offset rispetto al valore 1970. Tutto questo in tabella 1, semplice, lineare, nessuna possibilità di errore:

TABELLA 1
                    -1970
   Year()    tmpYear      tm.Year
------------------------------------
   1970       1970         0
   1971       1971         1
    .         .            .
    .         .            .
   1998       1998         28
   1999       1999         29
------------------------------------
   2000       2000         30
   2001       2001         31
   2018       2018         48
    .         .            .
    .         .            .
   2068       2068         98
   2069       2069         99


MA...
Tu hai usato una 'tmpYear' a 8 bit che non può contenere un valore superiore a 255, quindi servono due operazioni invece di una. Prima sottraiamo 2000 al valore restituito da 'year()', in modo da lavorare in 'tmpYear' a 8 bit con un valore compreso tra 0 e 69 per gli anni 2000..2069, ma anche un valore negativo in complemento a due per gli anni dal 1970 al 1999.

E' un problema? No. Ci basta regolare l'anno in 'tmpYear' solo da 0 a 69 senza sconfinare nei valori negativi e tutto funziona. Quando dobbiamo aggiornare 'tm.Year' dobbiamo anche aggiungere 30 per riportare i valori come 'tm.Year' richiede. Il tutto in tabella 2, anche questo funziona senza errori:

TABELLA 2
        -2000         +30
   Year()    tmpYear      tm.Year
------------------------------------
   1970       226 (-30)    0
   1971       227 (-29)    1
    .         .            .
    .         .            .
   1998       254 (-2)     28
   1999       255 (-1)     29
------------------------------------
   2000       0            30
   2001       1            31
   2018       18           48
    .         .            .
    .         .            .
   2068       68           98
   2069       69           99


MA...
Invece tu hai fatto così per tentativi (tabella 3):

TABELLA 3
         -1999        -2018
    Year()    tmpYear      tm.Year
-------------------------------------
    1970       227 (-29)    1
    1971       228 (-28)    2
     .         .            .
     .         .            .
    1998       255 (-1)     29
    1999       0            30
-------------------------------------
    2000       1            31
    2001       2            32
    2018       19           49
     .         .            .
    2068       69           99
    2069       70           100


Iniziamo con il lolloso 2018... sottrarre 2018 da una variabile 8 bit senza segno è del tutto equivalente a sommare 30, in pratica se scrivevi +30 era la stessa cosa (il fatto che siamo nel 2018 è una pura coincidenza :) )

Di differente dalla tabella 2 rimane solo quel 1999... che sfalsa di uno i valori degli anni, per cui va sicuramente a "compensare" un errore (probabilmente un decremento) presente da qualche altra parte.

Risolto quell'errore si può quindi tranquillamente usare l'attuale procedimento (ma sottraendo 2000 come in tabella 2) regolando 'tmpYear' da 0 a 69.

Il caso è chiuso :)
* * * *    if non è un ciclo   * * * *
* * * Una domanda ben posta è già mezza risposta. * * *

ziopippo

Grazie mille per le tue "indagini". Sono rientrato da poco dal lavoro e non ho la lucidità per comprendere le tue finezze.
Domani spero di tornare prima a casa e di riuscire a capire meglio quello che hai scritto. Nel caso ti chiederò ulteriori spiegazioni. ;)
GRAZIE!!!

ziopippo

Ok, tutto chiaro, più o meno, c'è ancora un errore nascosto da qualche parte ma adesso è chiaro.

Partiamo dal principio.

La funzione 'year()'  restituisce un valore a 16 bit compreso tra 1970  2069.

La cosa più semplice sarebbe quindi usare una 'tmpYear' da 16 bit (una banale variabile tipo int) per manipolare l'anno (regolandolo quindi con l'encoder dal 1970 al 2069), e poi sottrarre 1970 quando la si vuole copiare nella 'tm.Year', perché 'tm.Year' è un offset rispetto al valore 1970. Tutto questo in tabella 1, semplice, lineare, nessuna possibilità di errore:
...

Il caso è chiuso :)
Dunque, caro il mio Sherlock Holmes, hai dimenticato di dire anche elementare Watson!  :smiley-mr-green:
Grazie alla tua tenacia e capacità di aver saputo spiegare l'arcano anche ad un asino (come me!)
Ho optato per ridichiarare tmpYear come int ed ho corretto il codice in questo modo:
Code: [Select]
void SetYear() // Modifico l'anno
{
  if (LCDML_BUTTON_checkUp()) // incremento i minuti
  {
    tmpYear = tmpYear < 99 ? tmpYear + 1 : tmpYear;
    lcd.setCursor(x, y);
    lcd.print(tmpYear + 1970);
    LCDML_BUTTON_resetUp();
  }
  else if (LCDML_BUTTON_checkDown()) // decremento i minuti
  {
    tmpYear = tmpYear > 30 ? tmpYear - 1 : tmpYear;
    lcd.setCursor(x, y);
    lcd.print(tmpYear + 1970);
    LCDML_BUTTON_resetDown();
  }
  else if (LCDML_BUTTON_checkEnter()) // termino
    scelta = 3;
  LCDML_BUTTON_resetEnter();
}

void SaveDateTime() // Memorizzo Data ed ora
{
  tm.Hour = tmpHours;             //set the tm structure to 23h31m30s on 13Feb2009
  tm.Minute = tmpMinutes;
  tm.Second = 0;

  tm.Day = tmpDay;
  tm.Month = tmpMonth;
  tm.Year = tmpYear;

  SyncRTC(); // Sincronizzo il RTC per recuperare la data corretta
  RTC.write(tm);            //set the RTC from the tm structure
  Serial.println(F("MEMORIZZO ED ESCO"));
  SyncRTC(); // Sincronizzo il RTC per aggiornare ora e data sul display
}


e... tutto FUNZIONA QUASI ALLA PERFEZIONE!
L'unico "problema" che resta è quello di non fare il controllo sugli anni bisestili e comunque sui mesi con data inferiore a 31 giorni. Impostando ovviamente tipo il 31 aprile salva, ovviamente, come data il 01 maggio.
Controllo che detto tra noi non mi ero ancora posto.
Ho completato tutto il progetto come lo avevo pensato. Non sono riuscito ad inserire delle componenti grafiche sul display utilizzando i custom char perchè ne fa già uso la libreria LCDMenuLib  e non capisco il motivo per cui mi bypassa le definizioni che vorrei aggiungere. Ho anche chiesto aiuto sulla sezione dedicata in tedesco (scrivendo in inglese) ma nessuna risposta in merito.
Purtroppo (e per fortuna, per altri fronti) il mio tempo, causa lavoro, da dedicare a questo progetto è quasi finito quindi,  se qualcuno sa darmi una soluzione facile ed indolore per gestire il problema della data < a 31 la implemento atrimenti "amen".

Grazie ancora per la vostra infinita pazienza!!!  :smiley-kiss:

ziopippo

Sono ovviamente onorato di condividere l'intero progetto se qualcuno ne fa richiesta...

Claudio_FF

Quote from: ziopippo
se qualcuno sa darmi una soluzione facile ed indolore per gestire il problema della data < a 31
Basta dire al tuo amico che se sbaglia ad inserire il giorno i pesci muoiono.
Problema risolto  8)
* * * *    if non è un ciclo   * * * *
* * * Una domanda ben posta è già mezza risposta. * * *

ziopippo

 
Basta dire al tuo amico che se sbaglia ad inserire il giorno i pesci muoiono.
Problema risolto  8)
Ok ci sto. Però dico che sei stato tu a suggerirmelo.    :smiley-mr-green:

Go Up