Automatikus téli nyári óraállítás

Tartalom:

  • Téli és nyári óraálltás időpontjai
  • Óraállításkor kikapcsolt óra bekapcsoláskor
  • Tesztelés és fejlesztés szimulátorban, DS3231 RTC óra szimulálása UnoArduSim programban
  • Forráskód

Elhatároztam, hogy csinálok végre egy olyan órát, amit egyáltalán nem kell „gondozni”! Legyen automatikus a hét napjainak kezelése, ne kelljen órát állítani a téli és a nyári átálláskor, csinálja meg maga. Ez így egyszerűnek hangzik, és az is, de mégis sokat dolgoztam vele.

A hét napjainak automatikus kezelését már előbb megcsináltam, annak részletei itt találhatóak. Ennek megléte fontos, mert tudjuk mindannyian, hogy a nyári óraállításra március utolsó vasárnapján hajnali kettőkor, illetve október utolsó vasárnapján hajnali kettőkor kerül sor. Nem véletlen ez a döntés, az embereket megviseli az óraállítás, ezért a legcélszerűbb időpont a hétvége. Így legalább egy napjuk marad kipihenni a fáradalmakat. Pl. szegény fiatalok, akik szombaton hajnali ötre érnek haza a házibuliból, valójában március utolsó vasárnapján 6-ra érnek haza. Ekkor már nem is érdemes lefeküdni, hiszen a korán kelő szülőknek ekkor már indul az élet.

Szóval az automatikus óraállításhoz meg kell tudni határozni, hogy melyik az adott hónapok utolsó vasárnapja. Bevallom nem csináltam meg, de lehetett volna. Bamba módon felvettem egy tömböt és beleírtam 2050-ig ezeket a dátumokat. Nem szép megoldás, de én már biztosan nem érem meg, hogy ezért valaki is leszidjon. Az ifjúság majd jobb algoritmust ír, ha hazaért a buliból.

Első körben az óraállítás 5 programsorból meg volt, de aztán eszembe jutott, mi van, ha az óra nem volt bekapcsolva amikor az átállást meg kellett volna csinálni. Természetesen a belső elemes óra tovább jár (DS3231 chip), de nem áll át automatikusan. Nem nagy kunszt, gondoltam, hozzáadok vagy levonok egy-egy órát ha bekapcsoláskor észre veszem, hogy az óra nem állt át. Természetesen azt, hogy az óra nyári vagy téli időszámításban van, azt valahol meg kell jegyezni, tehát egy bitet el kell használnunk az eeprom-ból. Szóval leporoljuk a padláson felejtett óránkat, amiben elemről ment tovább az idő, elindul a kezelő program, és azt látja, hogy nincs az óra nyári időszámításra állítva pedig épp nyár van, vagyis március utolsó vasárnapja már elmúlt, de még nem érkezett el október utolsó vasárnapja. Azt, hogy az óra nincs nyári üzemmódban, az eeprom-ból fogja megtudni a program. Ekkor hozzáad egy órát az elemes DS3231 idejéhez. Igen ám, de mi van akkor, ha pont a bulizó fiatalok találták meg az óránkat, és éjfél előtt pár perccel dugták be a konnektorba? Ha hozzáadunk a 23 órához egy órát, akkor 24 lesz. Az meg nincs? Miért nincs? Mert az már egy másik nap. Tehát növelni kell a dátum napját eggyel és 0 órát beállítani. De ha éppen a hónap utolsó napja volt? Egyáltalán mi abban a hónapban a hónap utolsó napja? A DS3231 chip tudja, mert beleépítették az algoritmust, de az Arduino program nem! Vagyis immár tudja, hiszen leprogramoztam.

Nem is egyszerű a dátum állítás, hiszen a szökőévekre is figyelni kell. Igaz ez csak akkor lényeges, ha éppen nyári üzemmódban van az óraszerkezet, mert pl. ha júliusban kihúzták a konnektorból, és átaludta a téli óraálltást. Ha ezek után véletlenül épp március 1.-én kapcsolják be éjfél és egy óra között, akkor februárra kell visszaállítani, és szökőévben 29-re, nem szökőévben meg 28-ra! Ugye, hogy nem is annyira egyszerű?

Végigjátszottam az összes lehetséges verziót. Pl. január 1.-én éjfél és egy óra között a nyári időszámítás állapotában áram alá helyezett órának (saját elemes órája szerinti időről beszélek), előző év december 31-re kell visszaállni 23 és 0 óra közé!

A problémát a tesztelés okozta. Ezért használatban vettem a majdnem elfelejtett UnoArduSim programot. Gondok okozott, hogyan szimuláljam a DS3231 órachip-et, hiszen az nincs benne a szimulátorban. Végül az az ötletem támadt, hogy csináltam egy magszakításokkal működő Arduino órát. A 2-es kivezetésre (interrupt 0. bemenet) kötöttem a szimulátorban egy 1 másodpercre beállított négyszög jelgenerátort, és megírtam egy óra programot. A megszakítás növeli a másodpercek számát, és a belső regiszterekben képzi az időt és a dátumot. Már csak kicsit át kellett alakítani a saját DS3231 kezelő függvényeimet, hogy ne I2C-n keresztül kérdezgessék a DS3231 chip-et, hanem intézzék el ugyanezt „házon belül” memóriaváltozókkal. A nyári üzemmód eeprom tartalmát is egy változóval szimuláltam. Így már könnyű dolgom volt, beírtam egy kezdő időpontot a forrásba, beállítottam, hogy milyen üzemmódban (nyári, téli) van éppen az óra, és elindítottam a programot és néztem a kijelzőn, hogy mi történik. Az elindítás egyenértékű volt az óra bekapcsolásával.

Jó fél napot játszottam a szimulátorral, mire kijavítgattam a rengeteg hibát, és lekezeltem azokat az eseteket, amikre nem gondoltam. Reményeim szerint most hibátlan az algoritmus. Tök önállóan átáll az óra, akármikor is kapcsolják be.

És íme, az algoritmus. Lehet küldeni a Milka csokikat, ha valaki felhasználja, mert sokat dolgoztam vele! Jó szórakozás volt!

#include <Wire.h>
#include <Adafruit_LiquidCrystal.h>   // Az UnoArduSim program ezt az LCD kerekteres kijelző meghajtó programot ismeri

//#include <EEPROM.h>              //valós program esetén kell az eeprom is

//Az óra használatához szükséges cím, amin a DS3231 chip-et meg lehet szólítani (a szimulátorban nem kell) 
//#define CLOCK_ADDRESS 0x68  //a modulon található óra IC címe az I2C buszon. 

Adafruit_LiquidCrystal lcdx(0);  // Az UnoArduSim program ezt az LCD kerekteres kijelző meghajtó programot ismeri
                                 // A szimulátorban a futtatás előtt kel beállítani 2x16 karakteresre, I2C címe x20, de ez alapértelmezett
                                 // Valós programban ki kell cserélni a ténylegesen letöltött LCD kezelő könyvtárra

struct dat_ido {      // a dátum és idő beállításához illetve kiolvasásához létrehozunk egy struktúrát dat_ido néven (változó típus)
  int ev;             //év tárolása a struktúrában (évszázadokkal kell megadni, illetve így kapjuk meg az eredményt a dátum kiolvasásakor)
  byte ho;            //ho tárolása a struktúrában
  byte nap;           //nap tárolása a struktúrában
  byte het_napja;     //hét napja a struktúrában (1-hétfő....7-vasárnap)
  byte ora;           //óra tárolása a struktúrában (24 órás üzemmódot fogunk használni)
  byte perc;          //perc tárolása a struktúrában
  byte masodperc;     //másodperc tárolása a struktúrában
  bool pontos;        //ez a változó fogja megadni az IDO kiolvasását követően, hogy pontos-e a kiolvasott időpont 
                      //(ha elemes működés közben leáll a DS3231 oszcillátora, akkor az "OSF" flag bebillen, és ezt olvassuk ki
};

dat_ido ds3231;  //létrehozzuk az dat_ido típusú változónkat DS3231 változó néven

// Mivel a szimulátorban az idő előrehaladását 1000msec-enként egy pulzus generátor megszakítással éri el, ezek a változók 
// a megszakítással szimulált óra belső változói. A valóságban ezek a változók a DS3231 IC-ben vannak benne, és a megszakítás sem kell.
// Azért volatilte, mert ezekhez a változókhoz a megszakításkor meghívott függvény is hozzányúl, és a loop()-ba futó program is.
// Volatile esetén a változót a RAM-ban kezeli a rendszer és nem a vezérlő belső regiszterekben, így mindkét szál (megszakítás és loop() is)
// azonos változó értéket lát minden időpillanatban.
volatile int _ev=2022;
volatile byte _ho=3;
volatile byte _nap=27;
volatile byte _ora=1;
volatile byte _perc=59;
volatile byte _masodperc=50;
volatile byte _het_napja=2;
bool eeprom_nyari=0;    //teli időszámítás=0, nyari időszámítás=1, ez az eeprom-ban tárolt értéket szimulálja. A szimulátorban nehézkes
                        //az eeprom használat, ezért változóba tettem az értéket, a valóságban ezt a változót eeprom-ban kell tartani
                        //eeprom-ba írni az értékét, és onnan olvasni.

long ido_tmp=millis();  //az egy másodperces időzítéshez segédváltozó. Egy másodpercenként frissíti a loop() az LCD tartalmát

//Ez a szimulátorban egy másodpercenként meghívott függvény, ez szimulálja az órát. Az egy másodperces időzítést egy hardver megszakítás
//állítja elő. Ha lenne egy másodperces pontos impulzusunk, akár a valóságban is lehetne így belső órája az az ATmega chip-nek.
//nem tökéletes a dátum algoritmusa, mert nem jó a szökőév megállapítás algoritmusa, csak 2100-ig működik jól
void int_0() {
  _masodperc++;                                                              //másodperc növelése
  if (_masodperc>59) {  _masodperc=0;_perc++;}                               //perc növelése, másodperc 0
  if (_perc>59) { _perc=0;_ora++;}                                           //óra növelése, perc 0
  if (_ora>23) {  _ora=0;_nap++;_het_napja++;}                               //nap és hét napjának növelése
  if (_het_napja>7) { _het_napja=1;}                                         //hét napja csak vasárnapig növekszik (7), aztán újra hétfő (1)
  if (_nap>31 && (_ho==1 || _ho==3 || _ho==5 || _ho==7)) {  _nap=1;_ho++;}   //a nap ezekben a hónapokban 31-ig növekedhet
  if (_nap>31 && (_ho==8 || _ho==10 || _ho==12)) {  _nap=1;_ho++;}           //a szimulátor nem tudott egyben ennyi feltétet kezelni, ezért lett külön if()
  if (_nap>30 && (_ho==4 || _ho==6 || _ho==9 || _ho==11)) { _nap=1;_ho++;}   //ezekben a hónapokban a nap 30-ig növekedhet
  if (_ev%4==0 && _nap>29 && (_ho==2)) {  _nap=1;_ho++;}                     //szökőévben a február 29 napos
  if (_ev%4!=0 && _nap>28 && (_ho==2)) {  _nap=1;_ho++;}                     //ha nem szökőév, akkor a február 28 napos
  if (_ho==13) {  _ho=1;_ev++;}
}

//ez a segéd táblázat megmondja, hogy az adott éveben mely dátumra esik az a vasárnap, amikor a téli, illetve a nyári időszámításra át kell állni
const byte ho_tabla[] { //Március utolsó vasárnapjának dátuma és október utolsó vasárnapjának dátuma 2021-2050-ig 2 byte-on
  28,31,27,30,26,29,31,27,30,26,29,25,28,31,26,29,
  25,28,31,27,30,26,28,31,27,30,26,29,25,28,30,26,
  29,25,28,31,27,30,25,28,31,27,30,26,29,25,27,30,
  26,29,25,28,31,27,29,25,28,31,27,30
};

void setup() {
  lcdx.begin(16,2);               //LCD start
  lcdx.setCursor(0,0);            //LCD kurzor 0,0 pozicióba
  pinMode(2, INPUT);              //megszakítás 0 bemenet előkészítése (2-es láb a 0-ás megszakítás bemenete) 

  attachInterrupt(0, int_0, RISING); //a kettes bemeneten 0 jelenik meg akkor meghívódik a int_0 függvény
  //most következik az óra beállítása. A setTime24() függvény egy saját függvény, nem használtam idegen lib-et
  //a DS3231-hez. A setTime24() 24 órás üzemmódot állít be alapból és a ds3231 nevű saját struktúrájú
  //változót használja fel, ennek aktuális értékét állítja be. A getTime24() függvény ugyanebbe a változóba
  //olvassa be az aktuális belső időt.
  ds3231.masodperc=55;
  ds3231.perc=59;
  ds3231.ora=23;
  //ds3231.het_napja=2;    //nem kell beállítani, mert a setTime24() függvény kiszámolja 
  ds3231.nap=31;
  ds3231.ho=3;
  ds3231.ev=2022; 
  setTime24();             //órabeállítás
}

void loop() {
  if (ido_tmp+1000<millis()) {            //egy másodpercenként kiolvassuk az időt, és kiírjuk az LCD-re
    ido_tmp=millis();
    getTime24();                          //idő kiolvasása a szimulált órából
    atallas_ell();                        //nyári és téli időszámítás óraállításának ellenőrzése
    lcdx.setCursor(0,0);
    lcdx.print(ds3231.ev);lcdx.print(".");
    if (ds3231.ho<10) { lcdx.print("0");}lcdx.print(ds3231.ho);
    lcdx.print(".");
    if (ds3231.nap<10) {  lcdx.print("0");}lcdx.println(ds3231.nap);
    lcdx.setCursor(0,1);
    if (ds3231.ora<10) {  lcdx.print("0");}lcdx.print(ds3231.ora);
    lcdx.print(":");
    if (ds3231.perc<10) { lcdx.print("0");}lcdx.print(ds3231.perc);
    lcdx.print(":");
    if (ds3231.masodperc<10) {  lcdx.print("0");}lcdx.print(ds3231.masodperc);
  }
}

void setTime24() {
  //Ez a programrész működne egy valós DS3231 chip esetén
  /*//status regiszter be?ll?t?sa
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x0e);               //A control regiszterbe fogunk írni, azt címezzük meg
  Wire.write(0b01100011);         //BBSQW bit 1, vagyis elemes táplálásnál is működik az oszcillátor
                                  //ha 1-re állítanánk, elemes táplálásnál nem járna az óra, csak őrizni az utolsó időpontot
                                  //A RS2 és RS1 bit 0-val beállítja a négyszögjel kimenetet 1Hz-ra, ezen lehet változtatni:
                                  // 0b01101011 esetén 1024Khz, 0b01110011 esetén 4096Khz, 0b01111011 esetén 8192Khz.
                                  //A INTCN bit 0-val beállítja, hogy az INT/SQW kimenet beállított frekvenciájú jelet ad ki.
  //címbet a státus regiszter következik, nem kell megcímezni csak írni, és az adat oda kerül
  Wire.write(0b00000000);         //A status regiszterben töröljük az OSF fleg-et, ami 1-el jelzi majd, ha elemes táplálásnál 
                                  //nem működött az oszcillátor, vagyis az óra valószínűleg nem pontos.
                                  //Az EN32Khz bit-et is 0-ra írjuk, azaz letiltjuk a 32Khz-s kimenetet
  Wire.endTransmission();
  //dátum és időpont beállítása
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x00);
  Wire.write(dec_bcd(ds3231.masodperc));
  Wire.write(dec_bcd(ds3231.perc));
  Wire.write(dec_bcd(ds3231.ora) & 0b10111111);
  Wire.write(dec_bcd(ds3231.het_napja)); 
  Wire.write(dec_bcd(ds3231.nap));
  Wire.write(dec_bcd(ds3231.ho));
  Wire.write(dec_bcd(ds3231.ev-2000)); 
  Wire.endTransmission();*/
  //a szimulált óra beállítása
  _masodperc=ds3231.masodperc;
  _perc=ds3231.perc;
  _ora=ds3231.ora;
  _het_napja=datum_hetnapja(ds3231.ev,ds3231.ho,ds3231.nap); 
  _nap=ds3231.nap;
  _ho=ds3231.ho;
  _ev=ds3231.ev; 
}

void getTime24() {
  //ez a programrész működne egy valós DS3231 esetén
  /*//kiolvassa a dátumot és az időpontot 
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 7);
  ds3231.masodperc = bcd_Dec(Wire.read());
  ds3231.perc = bcd_Dec(Wire.read());
  ds3231.ora = bcd_Dec(Wire.read());
  ds3231.het_napja = bcd_Dec(Wire.read());
  ds3231.nap = bcd_Dec(Wire.read());
  ds3231.ho = bcd_Dec(Wire.read() & 0b01111111);
  ds3231.ev = bcd_Dec(Wire.read())+2000;
  //status regiszterb?l az OSF bit kiolvas?sa.
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x0f);
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 1);
  if (Wire.read()& 0b10000000) {ds3231.pontos=0;} else {ds3231.pontos=1;}  //1-el jelezzük, ha az óra valószínűleg pontos*/
  ds3231.masodperc=_masodperc;
  ds3231.perc=_perc;
  ds3231.ora=_ora;
  ds3231.het_napja=_het_napja; 
  ds3231.nap=_nap;
  ds3231.ho=_ho;
  ds3231.ev=_ev; 

}

byte bcd_Dec(byte val) {  // Convertál bcd számból decimálisba
  return ( (val/16*10) + (val%16) );
}
byte dec_bcd(byte val) {  // Convertál decimális számból bcd-be
  return ( (val/10*16) + (val%10) );
} 

bool szokoev(int ev)  {
  if (ev==0) {  return false;}             //a 0. évet nem vesszük szökőévnek 
  bool szoko_ev=false;                
  if (ev%4==0) {                           //ha néggyel osztva nem ad maradékot, akkor szökőév
    szoko_ev=true;
    if (ev%100==0) {                      //ha 100-al osztva nem ad maradékot, akkor nem szökőév
      szoko_ev=false;
      if (ev%400==0) {  szoko_ev=true;}   //ha 400-al osztva nem ad maradékot, akkor mégis sz?k??v 
    }
  }
  return szoko_ev;
}

byte datum_hetnapja(int ev, byte ho, byte nap)
/********************************************************************************************************
 * Ez a függvény ellenőrzi, hogy elérkezett-e a nyári időszámítás átállásának időpontja, s ha igen, és  *       
 * Az óra nincs nyári időszámításban, akkor az aktuális órához hozzáad egyet. Ha elérkezett a nyári     *
 * Időszámítás kikapcsolásának időpontja, akkor pedig levon az órából egyet.                            *
 * Nyári időszámítás bekapcsolása: minden év márciusának utolsó vasárnapján hajnali 2-kor át kell       *
 * állítani az órát 3-ra.                                                                               *
 * Nyári időszámítás kikapcsolása: minden év októberének utolsó vasárnapján hajnali 3-kor vissza        *
 * kell állítani az órát hajnali 2-re.                                                                  *
 *                                                                                                      *
 * A függvény akkor is megoldja az óra állítást, ha az óra nem volt áram alatt, és a DS3231 óra chip    *
 * épp elemről működött. A ds3231 magától nem tud nyári óraállítást végezni.                            *
 ********************************************************************************************************/
{
  if (ho<1) { return 0;}  //hónap napjainak száma nem lehet 0
  //ezt a néhány vizsgálatot inkábba szimulációban kikommenteztem, mert a szimulátor nem boldogult ennyi feltétellel, és nem volt kedvem átírogatni
  //  if (ho!=1 and ho!=3 and ho!=5 and ho!=7 and ho!=8 and ho!=10 and ho!=12 and nap>31) {return 0;}  //több napot adtunk meg a hónapnak, mint amannyi napja van
  //  if (ho!=4 and ho!=6 and ho!=9 and ho!=11 and nap>30) {return 0;}  //több napot adtunk meg a hónapnak, mint amannyi napja van
  //  if (ho==2) {                                                      //ha február van, ellenőrizni kell a szökőév szerinti napokat is
  //    if (szokoev(ev)) {                                              //megmondja, hogy az adott év szökőév-e, mert ha igen, akkor a február 29 napos
  //      if (nap>29) { return 0;}}
  //    else {
  //      if (nap>28) { return 0;}}
  //  }
  int ho_napjai[] = {0,31,59,90,120,151,181,212,243,273,304,334,365};   // az évből eltelt hónapok napjainak száma, nem szökőévebn
  long elmult_nap = ev * 365;                                       // eddig ennyi napja volt az elmúlt éveknek a szökőévek figyelembevétele nélkül 
  long elmult_szokonap=0;                                           //ebbe számoljuk ki a szökőévekből adódó plusz napok számát
  long szn4=(ev-1)/4;                                               //minden negyedik év szökőév (kivéve minden 100. év, de azt mindjátt levonjuk)
                                                                    //az aktuális évet nem szabad beleszámolni, mert az majd az aktuális év napjaiban benne lesz
  long szn100=(ev-1)/100;                                           //minden 100. év nem szökőév, ezt majd levonjuk, kivéve minden 400. év, azt meg mindjárt hozzáadjuk
  long szn400=(ev-1)/400;                                           //Minden 400. év mégiscsak szökőév
  elmult_szokonap=szn4-szn100+szn400;                               //így megkaptuk a szökőévekből adódó plusz napokat
  long akt_ev_nap = ho_napjai[ho-1] + nap;                          // az eddig eltelt hónapok napjainak száma kiderül a tömbből, plusz hozzáadjuk az aktuális hónap napjait, ahol épp járunk
                                                                    //ha az adott év szökőév, és már elmúlt február, akkor még egyet hozzá kell adni,de ezt majd később
  long akt_ev_szokonap=0;
  if (ho>2) {
    if (szokoev(ev)) {  akt_ev_szokonap++;}                         // ha az aktuális évben már elmúlt február, és az év szökőév, akkor még egy napot hozzá kell adni
  }
  long napok=elmult_nap+elmult_szokonap+akt_ev_nap+akt_ev_szokonap; //és ezzel megkaptuk Jézus születésének napja óta eltelt napok számát
  if (napok%7==0) { return 7;}                                      //ha pont vasárnap van, akkor maradék nélkül osztható 7-el, ezért ilyenkor 7-et adunk vissza
  else {  return napok%7;}                                          //a maradék az adott hétben eltelt napok száma (hétfő az 1)
}

void atallas_ell() {                                                //Ha nyári időszakban vagyunk, akkor egy órát hozzáad az aktuális időhöz
                                                                    //ha az aktuális óra 23 óra, akkor 0 órát ad vissza
  byte akt_marc_dat=ho_tabla[(ds3231.ev-2021)*2];                   //a ho_tabla[] többől kiolvassuk, hogy az adott évben hányadikára esik március utolsó vasárnapja
  byte akt_okt_dat=ho_tabla[(ds3231.ev-2021)*2+1];                  //a ho_tabla[] többől kiolvassuk, hogy az adott évben hányadikára esik október utolsó vasárnapja
  byte nyari=0;

  //EEPROM.get(1,nyari);                                            //ha nyari=1, akkor ebben a pillanatban az óra nyári időszámtás szerinti 
                                                                    //állapotban van (egy órával később lesz éjfél, mint a valóságban)
  nyari=eeprom_nyari;                                               //szimulátorban változó helyettesíti az eeprom-ot
  //Ez a programrész akkor fut le, ha az átállás pillanatában a program működik, vagyis a teljes szerkezet áram alatt van, és az Arduino-ban is fut a program.
  if (ds3231.ho==3 && ds3231.nap==akt_marc_dat && ds3231.ora>1 && nyari==0) { //ha márciusban az átállás napján még nincs a nyári időszámításban az óra, és elmúlt éjjel 2 óra, 
                                                                              //előre állítjuk az órát egy órával, vagyis 2 órakor átállunk 3 órára, így az időpont egy órát késik
                                                                              //a tényleges csillagászati időhöz képest, a nap később kel.
    ds3231.ora=ds3231.ora+1;                                        //órát előre állítjuk
    setTime24();                                                    //beálltjuk az órát a hardverben is
    //EEPROM.put(1,(byte)1);                                        //eeprom-ba beírjuk, hogy nyári időszámitás üzemmódban vagyun
    eeprom_nyari=1;
  }

  //Ha az óraállítás pillanatában az óra IC elemről működött, és az Arduino-ben nem futott a program, akkor nem lett átállítva nyári időszámtásba. 
  //Ezért ez első ezt követő bekapcsoláskor észre kell venni, hogy nyári időszámitásba kell állni, de ekkor bármilyen későbbi dátum lehet éppen.
  //Ha márciusban a dátum nagyobb mint az átállás dátuma, vagy a hónap már nagyobb mint március, de a hónap kisebb mint október,
  //vagy október de a nap kisebb mint az októberi átállás dátuma, és még nem vagyunk nyári időszámtásban, akkor előre kell állni egy órával. 
  if (((ds3231.ho==3 && ds3231.nap>akt_marc_dat) || (ds3231.ho>3)) && (ds3231.ho<10 || (ds3231.ho==10 && ds3231.nap<akt_okt_dat)) && nyari==0) {
    //EEPROM.put(1,(byte)1);                                         //beirjuk az eeprom-ba a nyári üzemmódt
    eeprom_nyari=1;

    ds3231.ora=ds3231.ora+1;                                         //előre álltjuk az órát
    if (ds3231.ora==24) {                                            //ha éppen 24 óra lenne a növelés után, akkor valójában egy napot kell hozzáadni és beállítani 0 órára
      ds3231.ora=0;                                                  //0 óra beállítása
      ds3231.nap=ds3231.nap+1;                                       //növeljük a dátumot 1-el.
      ds3231.het_napja=ds3231.het_napja+1;                           //ha a napot növeltük, akkor a hét napját is kell
      if (ds3231.het_napja==8) {  ds3231.het_napja=1;}               //ha épp vasárnap volt, akkor hétfő következik a 8. nap helyett
                                                                     //Ha a nap növelése után az aktuális hónap utolsó napjánál 1-el nagyobb lett a nap, akkor hónapot is kell völtai és a nap=1
      if ((ds3231.ho==3 || ds3231.ho==5 || ds3231.ho==7 || ds3231.ho==8 || ds3231.ho==10) && ds3231.nap>31) { ds3231.nap=1;ds3231.ho=ds3231.ho+1;}   //31 napos hónap esetén a vizsgálat  
      if ((ds3231.ho==6 || ds3231.ho==9) && ds3231.nap>30) {  ds3231.nap=1;ds3231.ho=ds3231.ho+1;}    //30 npos hónap esetén a vizsgálat
    } 
    setTime24();
  } 

  //Ez a feltétele akkor lehet igaz, ha az őszi óraállításkor az Arduino áram alatt van és fut a program. 
  if (ds3231.ho==10 && ds3231.nap==akt_okt_dat && ds3231.ora>2) {     //Ha októberben a téli óraállítás pillanatában éppen nyári időszámításban van a program,
                                                                      //akkor egy órával visszaállítjuk az órát.
    ds3231.ora=ds3231.ora-1;                                          //Az órát eggyel csökkentjük, 3 óra helyett újra 2 óra van, így a mutatott időpont megegyezik a csillagászati idővel
    setTime24();                                                      //Beállítjuk a DS3231 IC-n is az új időpontot
    //EEPROM.put(1,(byte)0);                                          //megjegyezzük eepromban is, hogy téli időszámítás szerinti üzemmódban van az óra,
                                                                      //Egy következő ciklusban már nem fog újra lefutni ez a feltétel.
    eeprom_nyari=0;                                                   //szimulátorban változó helyettesíti az eeprom-ot
  }

  //Ha az óraállítás pillanatában az Arduino nincs áram alatt, és a DS3231 elemről működik, akkor nem történik meg az óra átállítás.
  //Ekkor az ezt követő első bekapcsoláskor kell az időt visszaállítani egy órával. Ha az óra által mutatott időpont a téli időszámítás
  //előtti pillanatban van (de a nyári időszámítás beállítási időpontja után) és az eeprom szerint nincs téli időszámításban, akkor kell
  //beállítani. Viszont ha a bekapcsolás éjfél és egy óra között történik, akkor nem visszaállítani kell az órát, hanem egy nappal előbbre
  //és 23 órára. Az egy nappal előbbre állítás miatt azonban akár hónapot is kell váltani, ha épp 1.-én ált a naptár.
  //Ha október van, de már elmúlt az óraállítás napja, vagy már elmúlt október, vagy már a következő évben vagyunk és március (nyári óraállítás
  //előtt, vagy már márciusban vagyunk de még nem jött el a nyári óraállítás dátuma, és az óra nincs téli időszámítás időpontban, akkor kell 
  //átállítani az időt.
  if (((ds3231.ho==10 && ds3231.nap>akt_okt_dat) || (ds3231.ho>10) || (ds3231.ho<3) || (ds3231.ho==3 && ds3231.nap<akt_marc_dat)) && nyari==1) {
    //EEPROM.put(1,(byte)0);                                         //Az eepromban beállítjuk a téli időszámítást
    eeprom_nyari=0;                                                  //szimulátorban változó helyettesíti az eeprom-ot

    if (ds3231.ora==0) {                                             //Ha még 0 óra van, akkor előző napra kell beállni
      ds3231.ora=23;                                                 //Az előző napon ekkor 23 óra van
      ds3231.nap=ds3231.nap-1;                                       //csökkentjük a napot
      ds3231.het_napja=ds3231.het_napja-1;                           //csökkentkjük a hét napját
      if (ds3231.het_napja==0) {  ds3231.het_napja=7;}               //ha a hét napja 0 lett (hétfőn fordulhat elő), akkor nem 0 nap következik, hanem 7 (vasárnap)
      if (ds3231.nap==0) {                                           //ha 1.-e volt, akkor hónapot is kell váltani
        ds3231.ho=ds3231.ho-1;                                       //csökkentjük a hónapot
        if (ds3231.ho==0) {                                          //ha a hónap január volt, akkor nem a 0. hónap jön, hanem az előző év decembere
          ds3231.ho=12;ds3231.nap=31;                                //az új dátum december 31
          ds3231.ev=ds3231.ev-1;                                     //csökkentjük az évet 
        }
        if (ds3231.ho==1 || ds3231.ho==3 || ds3231.ho==5 || ds3231.ho==7 || ds3231.ho==8 || ds3231.ho==10) {  ds3231.nap=31;}  //ezekben a hónapokban az előző hónap 31 napos, tehát az előzö nap 31.-e
        if (ds3231.ho==4 || ds3231.ho==6 || ds3231.ho==9 || ds3231.ho==11) {  ds3231.nap=30;} //ezekben a hónapokban az előző honap 30 napos, tehát az előző nap 30.-a
        if (ds3231.ho==2 && szokoev(ds3231.ev)) { ds3231.nap=29;}    //február utolsó napja van, ami 02.29, mert szökőévben vagyunk
        if (ds3231.ho==2 && !szokoev(ds3231.ev)) {  ds3231.nap=28;}  //február utolsó napja van, ami 02.28, mert nem szökőévben vagyunk
      }
    } 
    else {  ds3231.ora=ds3231.ora-1;}                                //nem 0 óra volt, így nyugodtan csökkenthetjük az órát 1-el.
    setTime24();                                                     //beállítjuk az órát az új időpontra
  } 
}

Mennyire volt hasznos amit olvastál? Értékelés után szövegesen is leírhatod megjegyzéseidet és véleményedet!

Kattints egy csillagra az értékeléshez!

Szövegesen is leírhatod véleményedet! Ha kérdésed van, ne felejtsd el megadni az email címedet!