// Podprogramy pro praci s vnitrnim RTC //================================================ //---------------------------------------------- void RTC_info(void) { Serial.println(lng174); // Serial.println("Informace o RTC"); Serial.println("---------------"); Serial.print(lng175); // Serial.print("Aktualne je "); if(leto == true) Serial.println(char_leto); // Serial.println("LEto"); else Serial.println(char_zima); // Serial.println("2iMA"); Serial.print(lng176); // Serial.print ("Cas v RTC bez korekci: "); unsigned long tt = rtclock.now(); sek1970_datcas(tt,true); Serial.println(lng177); // Serial.println("Cas posledniho serizeni RTC (data z EEPROM): "); unsigned long pomprom = EEPROM_read_long(0); Serial.print(lng178); // Serial.print("... v sekundach od 1.1.1970: "); Serial.println(pomprom); Serial.print(lng179); // Serial.print("... v citelnem tvaru: "); sek1970_datcas(pomprom,true); unsigned long interval; if (tt > cas_minuleho_nastaveni) interval = tt - cas_minuleho_nastaveni; // interval musi byt vzdycky kladny else interval = cas_minuleho_nastaveni - tt; Serial.print(lng180); // Serial.print("Interval od posledniho nastaveni casu: "); Serial.print(interval); Serial.print(" [s] (= "); Serial.print(interval / 86400.0); Serial.println(" [d])"); Serial.println(lng181); // Serial.println("Korekce casu (data z EEPROM): "); pomprom = EEPROM_read_long(4); Serial.print(lng182); // Serial.print(" ... ulozene cislo v HEX formatu : "); Serial.println(pomprom,HEX); Serial.print(lng183); // Serial.print(" ... sekunda se "); if (pomprom > 0x7FFFFFFFUL) Serial.print(lng184); // Serial.print ("odecita"); else Serial.print(lng185); // Serial.print ("pricita"); Serial.print(lng186); // Serial.print(" kazdych "); unsigned long za_kolik_sek = pomprom & 0x7FFFFFFFUL; Serial.print(za_kolik_sek); Serial.println(lng187); // Serial.println(" sekund od posledniho serizeni."); Serial.print(lng188); // Serial.print(" (to je asi "); if(za_kolik_sek < 180000UL ) // mene nez 50 hodin { Serial.print(za_kolik_sek / 3600.0 ,1); Serial.println(lng189); // Serial.println(" hodin)"); } if(za_kolik_sek >= 180000UL and za_kolik_sek < 31557600UL) // 50 hodin az 1 rok { Serial.print(za_kolik_sek / 86400.0 ,1); Serial.println(lng190); // Serial.println(" dni)"); } if(za_kolik_sek >= 31557600UL) // vic nez rok { Serial.print(za_kolik_sek / 31557600.0 ,1); Serial.println(lng191); // Serial.println(" roku)"); } unsigned long extra_sekundy = interval / (0x7FFFFFFFUL & pomprom); Serial.print(lng192); // Serial.print("Zatim se takto melo pridat/ubrat: "); if (pomprom > 0x7FFFFFFFUL) Serial.print('-'); // zaporna korekce = sekundy se odecitaji else Serial.print('+'); // kladna korekce = sekundy se pricitaji Serial.print(extra_sekundy); Serial.println(lng193); // Serial.println(" extra sekund."); Serial.print(lng194); // Serial.print("Takze zkorigovany cas pro zobrazeni je: "); zobraz_RTC(true,true); } //---------------------------------------------- //---------------------------------------------- // Zobrazeni casu v RTC obvodu vcetne korekce void zobraz_RTC(boolean serkom) { zobraz_RTC(serkom, false); } void zobraz_RTC(boolean serkom, boolean secselc) { unsigned long tt = rtc_korekce(); // aktualni cas v RTC v sekundach od 1.1.1970 (UTC) sek1970_datcas(tt,serkom,secselc); // v promenne tt je UTC cas s korekci } //---------------------------------------------- //---------------------------------------------- // Nastaveni casu v RTC obvodu // Po prvnim znaku 'T', ktery zpusobil skok do tohoto podprogramu, ocekava na seriove lince retezec ve tvaru "yyyymmddhhnnss" void nastav_RTC(void) { boolean chyba = false; // bude provadeno testovani na korektni meze vlozenych cisel. Kdyz dojde k prekroceni mezi, nastavi se znacka 'chyba' na true long odchylka ; // o kolik se lisi zadavany cas a aktualni cas v RTC unsigned long interval; // rozdil casu v sekundach od minuleho nastavovani casu unsigned long tt; unsigned long aktualni_cas_RTC; // aktualni cas v RTC v sekundach od 1.1.1970 delay(100); // pauza na prijeti vsech znaku ze seriove linky if (Serial.available() == 14) // pro nastaveni casu se ocekava 14 znaku: "YYYYMMDDHHNNSS" { i = 0; while (Serial.available() > 0) // vsechny prijate znaky se ulozi do pole { prijato[i] = Serial.read(); i++; } Serial.print(lng195); // Serial.print("Prijato: "); Serial.println(prijato); // rok LOC_rok = prijato_int(0, 4); if (LOC_rok > 2099 || LOC_rok < 2020) chyba = true; // test, ze je rok v rozsahu 2020 az 2099 // mesic LOC_mes = prijato_int(4, 6); if (LOC_mes > 12 || LOC_mes < 1) chyba = true; // test, ze je mesic v rozsahu 1 az 12 // den LOC_den = prijato_int(6, 8); if (LOC_den > 31 || LOC_den < 1) chyba = true; // test, ze je den v rozsahu 1 az 31 (nebere se ohled na to, kolik ma mesic ve skutecnosti dni) // hodina LOC_hod = prijato_int(8, 10); if (LOC_hod > 23 || LOC_hod < 0) chyba = true; // test, ze jsou hodiny v rozsahu 0 az 23 // minuta LOC_min = prijato_int(10, 12); if (LOC_min > 59 || LOC_min < 0) chyba = true; // test, ze jsou minuty v rozsahu 0 az 59 // sekunda LOC_sek = prijato_int(12, 14); if (LOC_sek > 59 || LOC_sek < 0) chyba = true; // test, ze jsou sekundy v rozsahu 0 az 59 if (chyba == true) // kdyz je nejaka hodnota mimo povoleny rozsah, ale prisel spravny pocet znaku ... { Serial.println(lng006); // Serial.println ("Vstup mimo rozsah "); // zahlasi se chyba v zadani Serial.print(lng197); // Serial.print("Rok: "); // a vypisou se zadane udaje Serial.println(LOC_rok); Serial.print(lng198); // Serial.print("Mesic: "); Serial.println(LOC_mes); Serial.print(lng199); // Serial.print("Den: "); Serial.println(LOC_den); Serial.print(lng200); // Serial.print("Hodina: "); Serial.println(LOC_hod); Serial.print(lng201); // Serial.print("Minuta: "); Serial.println(LOC_min); Serial.print(lng202); // Serial.print("Sekunda: "); Serial.println(LOC_sek); } } else { chyba = true; // kdyz po seriove lince dorazil jiny pocet znaku, nez 15, tak se jen vypise chyba Serial.println(lng006); // Serial.println ("Vstup mimo rozsah "); // zahlasi se chyba v zadani } if (chyba == false) // kdyz se zdaji byt vsechny hodnoty v poradku { // pri kazdem spravnem zadani se vypocita korekce na zaklade rozdilu casu od minuleho serizeni aktualni_cas_RTC = rtclock.now(); mtt.year = LOC_rok - 1970; // knihovna je napsana tak, ze se cas pocita od 1.1.1970 mtt.month = LOC_mes; mtt.day = LOC_den; mtt.hour = LOC_hod; mtt.minute = LOC_min; mtt.second = LOC_sek; if (leto == false) tt = rtclock.makeTime(mtt) - (60*60*zimni_posun); // v zime se pri ukladani casu uklada do RTC o hodinu mene (prevod SEC na UTC) else tt = rtclock.makeTime(mtt) - (60*60*letni_posun); // kdyz se nastavuje cas v lete (SELC), do RTC se uklada o dalsi hodinu mene (prevod SELC na SEC) rtclock.setTime(tt); // skutecne prenastaveni casu v RTC na zadanou hodnotu cas_minuleho_nastaveni = EEPROM_read_long(0); if (tt > cas_minuleho_nastaveni) interval = tt - cas_minuleho_nastaveni; // interval musi byt vzdycky kladny else interval = cas_minuleho_nastaveni - tt; odchylka = aktualni_cas_RTC - tt; if (interval < 86400UL) // od predchoziho serizeni ubehlo min nez 24 hodin { Serial.println(lng220); // ("Kratky interval od posledniho serizeni (< 1 den)") if (odchylka > 172800L or odchylka < -172800L ) // rozdil mezi zadavanym casem a casem v RTC je vic, nez 2 dny. To je CHYBA { Serial.println(lng219); // ("Velka odchylka mezi novym casem a casem v RTC") Serial.println(lng205); // ("Automaticka kalibrace RTC zrusena."); korekce = 0x7FFFFFFFUL; } else // "prijatelna odchylka, korekce se ale nepocita - prebira se puvodni" { korekce = EEPROM_read_long(4); } } if (interval > 15768000UL) // od predchoziho serizeni ubehlo vic nez pul roku { Serial.println(lng221); // Serial.println("Dlouhy interval od posledniho serizeni (> pul roku)"); Serial.println(lng205); // Serial.println("Automaticka kalibrace RTC zrusena."); korekce = 0x7FFFFFFFUL; // korekce se rusi } if (interval <= 15768000UL and interval >=86400UL) // od predchoziho serizeni ubehlo vic nez den, ale min nez pul roku { // "spravny interval od posledniho serizeni" if (odchylka > 172800L or odchylka < -172800L ) // rozdil mezi zadavanym casem a casem v RTC je vic, nez 2 dny. To je CHYBA { Serial.println(lng219); // ("Velka odchylka mezi novym casem a casem v RTC") Serial.println(lng205); // ("Automaticka kalibrace RTC zrusena."); korekce = 0x7FFFFFFFUL; } else // "prijatelna odchylka, pocita se korekce" { if (odchylka < 0) korekce = interval / -odchylka; // odchylka je zaporna, sekundy se budou pricitat - (odchylka se prevadi na kladne cislo) if (odchylka > 0) korekce = (0x80000000UL | (interval / odchylka)); // nejvyssi bit je znamenko, korekce se bude odecitat if (odchylka == 0) korekce = 0x7FFFFFFFUL; // cas v RTC je stejny, jako zadany cas - zadna korekce neni potreba (prvni extra sekunda za 68 let) if ((korekce & 0x7FFFFFFFUL) < 300) // sekunda se ma pricitat, nebo odecitat driv, nez za 5 minut - to vypada na chybu RTC { Serial.println(lng204); // "Chyba RTC (sekunda se ma korigovat casteji, nez za 5 minut)." Serial.println(lng205); // "Automaticka kalibrace RTC zrusena." korekce = 0x7FFFFFFFUL; } } } cas_minuleho_nastaveni = tt; // nastaveni globalni promenne, aby se nemulo pri kazdem zjistovani casu sahat do EEPROM EEPROM_write_long(0,tt); // do EEPROM se v kazdem pripade ulozi cas posledniho nastaveni if (korekce != EEPROM_read_long(4)) // do EEPROM se nova korekce uklada jen v pripade, ze se zmenila { EEPROM_write_long(4 , korekce); } } } //---------------------------------------------- //---------------------------------------------- // Prevod poctu sekund od 1.1.1970 na citelny datum a cas. // Vystup datumu a casu se muze smerovat do seriove linky a zaroven nastavuje globalni promenne LOC_xxx void sek1970_datcas(unsigned long parametr, boolean seriovy_vystup) { sek1970_datcas(parametr, seriovy_vystup, false); } void sek1970_datcas(unsigned long parametr, boolean seriovy_vystup, boolean secselc) { rtclock.breakTime(parametr, mtt); LOC_dvt = mtt.weekday + 1; // primo v RTC se den v tydnu uklada v rozsahu 0(Po) az 6(Ne), proto se pro spravne zobrazeni pricita +1 (1=Po....7=Ne) LOC_den = mtt.day; LOC_mes = mtt.month; LOC_rok = mtt.year+1970; LOC_hod = mtt.hour; LOC_min = mtt.minute; LOC_sek = mtt.second; if (seriovy_vystup == true) // vypis zadanych hodnot v citelnem formatu: d.m.yyyy h:nn:ss DVT { Serial.print(LOC_den); Serial.print('.'); Serial.print(LOC_mes); Serial.print('.'); Serial.print(LOC_rok); Serial.print(' '); Serial.print(LOC_hod); Serial.print(':'); if (LOC_min < 10) Serial.print('0'); Serial.print(LOC_min); Serial.print(':'); if (LOC_sek < 10) Serial.print('0'); Serial.print(LOC_sek); Serial.print(' '); if (secselc == true) { if (leto == true) Serial.print(char_leto); else Serial.print(char_zima); Serial.print(' '); } Serial.println(dny[LOC_dvt]); } } //---------------------------------------------- //---------------------------------------------- // Zjisti aktualni cas v RTC (v UTC), pripadne k nemu prida/ubere nejake sekundy z automaticke korekce. // Kdyz je aktualne SEC prida hodinu, kdyz je SELC, prida 2 hodiny // vysledek je zkorigovany pocet sekund od 1.1.1970 unsigned long rtc_korekce(void) { unsigned long rtc_tt = rtclock.now(); // zjisteni aktualniho casu v RTC (v UTC) unsigned long interval; if (rtc_tt > cas_minuleho_nastaveni) interval = rtc_tt - cas_minuleho_nastaveni; // interval musi byt vzdycky kladny else interval = cas_minuleho_nastaveni - rtc_tt; unsigned long extra_sekundy = interval / (0x7FFFFFFFUL & korekce); // vypocet, kolik sekund ma pricist, nebo odecist od casu v RTC if (korekce > 0x7FFFFFFFUL) rtc_tt = rtc_tt - extra_sekundy; else rtc_tt = rtc_tt + extra_sekundy; if (leto == false) rtc_tt = rtc_tt + (60*60*zimni_posun); // v zime se ke UTC pridava hodina else rtc_tt = rtc_tt + (60*60*letni_posun); // v lete se pridava jeste hodina navic return rtc_tt; } //---------------------------------------------- //---------------------------------------------- //Zobrazi na displeji aktualni hodiny a minuty ve formatu " H-MM" nebo "HH-MM" void ho_mi(void) { zobraz_RTC(false); if(LOC_hod < 10) D_pamet[4] = 0; // na pozici desitek hodin zapis mezeru else D_pamet[4] = graf_def[LOC_hod / 10]; // nebo desitky hodin D_pamet[3] = graf_def[LOC_hod % 10]; // na pozici jednotek hodin zapis jednotky hodin D_pamet[2] = 64; // mezi hodiny a minuty se zapise pomlcka D_pamet[1] = graf_def[LOC_min / 10]; // desitky minut D_pamet[0] = graf_def[LOC_min % 10]; // jednotky minut aktualizuj_displej(); } //---------------------------------------------- //Zobrazi na displeji aktualni minuty a sekundy ve formatu "MM-SS" void mi_se(void) { zobraz_RTC(false); D_pamet[4] = graf_def[LOC_min / 10]; // desitky minut D_pamet[3] = graf_def[LOC_min % 10]; // na pozici jednotek minut zapis jednotky minut D_pamet[2] = 64; // mezi minuty a sekundy se zapise pomlcka D_pamet[1] = graf_def[LOC_sek / 10]; // desitky sekund D_pamet[0] = graf_def[LOC_sek % 10]; // jednotky sekund aktualizuj_displej(); } //---------------------------------------------- // pipani tak dlouho, nez se stiskne nejake tlacitko // po stisku tlacitka se ulozi do EEPROM na adresu ciloveho casu 0 a tim se alarm vypne // pipani bude trvat 0.5 sekundy specialnim bzuknutim, ale bude se opakovat pri kazdem interruptu void alarm(void) { zobraz_text(53); // "ALArM" #ifndef omezeni_funkci_4 // logovani na SD kartu je mozne kvuli uspore prostoru v PROGMEM vypnout SD_log(995,1); #endif if (dvouminutovy_bzuk == 0) dvouminutovy_bzuk = millis(); for (byte i = 0; i < 5; i++) { if (millis() - dvouminutovy_bzuk < 120000UL ) // pipat se bude maximalne 120 sekund { tone(pin_bzuk , 500+(i*100) , 90); delay(100); noTone(pin_bzuk); } if (digitalRead(pin_tl_up) == LOW or digitalRead(pin_tl_dn) == LOW or digitalRead(pin_tl_ok) == LOW) { zobraz_text(29); // "-----" EEPROM_write_long( 495 , 0); // funkce odpocet (budik) se vypina ctdwn_end = 0; while (digitalRead(pin_tl_up) == LOW or digitalRead(pin_tl_dn) == LOW or digitalRead(pin_tl_ok) == LOW) { delay(50); // cekani na uvolneni vsech tlacitek } delay(50); break; // predcasne ukonceni tonove smycky (dalsi tony uz se prehravat nebudou) } } }