Időjárás állomás

Tartalom:

  • Hőmérséklet, légnyomás és páratartalom mérés
  • Kijelzés hatalmas, messziről látható 7 szegmenses led kijelzőn, kiegészítve ledmatrix kijelzőkkel
  • Külső led kijelzők fényerőszabályozása fényviszonyok szerint
  • LCD szerviz kijelző műszaki állapot megjelenítéshez, minimum és maximum adatok lekérdezéséhez
  • Adatok rögzítése SD kártyára naponta óránként és éves állományba naponta átlag adatokkal
  • Watcdog használata, adatok átlagolása nem felejtő FRAM-ba
  • Két Arduino nano összekapcsolása

Szerettem volna a kertünkben egy hátsó kis épület falára egy hőmérőt. Mondjuk volt is egy ott, de higanyszálas, amit már nem látok csak szemüveggel. Így azt találtam ki, hogy teszek a falra egy régi hordóból kialakított „disztárgyat”, ami mutatni fogja a hőmérsékletet marhanagy számokkal. A hordó fenekére vágtam egy 20x15cm-es négyezet alakú lyukat, beleapplikáltam egy piros plexi lapot, és ezzel kész is voltam a legnehezebb feladattal. Ezzel megvoltam egy nap alatt, a továbbiakra már csak egy év kellett!

Az első elképzelés az volt, hogy kijelzem a hőmérsékletet, légnyomást és a páratartalmat. Ezekre a feladatokra vettem egy DHT22 hőmérséklet és páratartalom mérőt, mindezt beszereltem egy alumínium lemezből hajtogatott hengerbe, aminek mindkét végére egy-egy bolhapiacon „szerzett” teaszűrőt applikáltam, hogy ne menjenek bele a bogarak. Az egész egység a kisház árnyékos sarkára került. Így néz ki:

A képen beltéri, épület, piszkos, kicsi látható

Automatikusan generált leírás

Vettem még egy BMP180 légnyomásmérőt is, de ezt nem kellet a kültéri dobozba beszerelni, gondoltam ez bárhol lehet, mivel a légnyomás kiegyenlítődik mindenhol, így az Arduino Nano kivezetéseire került közvetlenül a vezérlő dobozában.

A kijelzéshez vásároltam egy csomó 7 szegmenses kijelzőt, amiket 74HC595 léptető regiszterrel szándékoztam meghajtani. Így is lett. A kijelzők hátuljára applikáltam az IC-ket valahogy így (itt még félkész):

A képen beltéri, elektronika, áramkör, asztal látható

Automatikusan generált leírás

Viszont elég furán néz ki a három számcsoport egymás alatt, ha nem látod, mit jelentenek az egyes értékek. Így vettem hozzá 4db MAX7219 meghajtóval működő led mátrix kijelzőt is. Mindegyik számcsoport mögé tettem egyet, illetve a légnyomás adata mögé kettőt, mert a „mbr” (milibár) felirat nem fért el egy kijelzőn. Így nézett ki az első verzió hátulról:

…és előlről:

A képen épület, aláírás, fából készült, ülő látható

Automatikusan generált leírás

Evés közben jön meg az étvágy, rájöttem, hogy a középső számcsoport nem csak a légnyomás kijelzésre lesz jó, mérni szerettem volna a hőmérsékletet a kisházban (ez egy szerszámos kamra szerű kis épület a kertünkben), egy pincében és egy aknában is. Utóbbiakhoz elég nagy távolságra kellett elvinni az érzékelőket, a leghosszabb vezeték 25 méteresre sikerült. Ide már biztosan a Dallas DS18B20 egyvezetékes hőmérő chipre lesz szükség. Ezt nagyon könnyű volt szerelni, mindössze a pince párájától kellett megvédeni valahogy a szenzorokat. Miután kiderült, hogy működik, ragasztópisztolyból kifolyatott műanyag bevonattal láttam el:

A képen beltéri, ülő, asztal, étel látható

Automatikusan generált leírás

Kicsit homályos a felvételen a szenzor, de az a fekete pont a végében a Dallas DS18B20 chip, amit teljesen befed a ráfolyatott műanyag. Ez éppen nem a pincében van, hanem a kisház befőttes üvegei között, de már itt is láttam télen vízcseppet a szenzoron, így biztosan szükséges a pára elleni védelem!

Mivel a házfalra időnként rásüt a nap, mérni kell a megvilágítást és szabályozni a fényerőt. Ezzel sokat kínlódtam, mert a mátrix és a 7 szegmens kijelzők fényereje nagyon más. Kísérletezgetéssel kellett kitalálni, hogy a 74HC595 pwm szabályozott fényereje fokozatonként azonos legyen a MAX7219 tizenhat megfelelő fényerő fokozatának fényerejével.

Ezek voltak az alapvető építőkockák. Kellett még tápegység és a vezérlő egység egy Arduino nano-val. Ezt egy olcsó kis villanyszerelő dobozba szereltem:

A képen zacskó látható

Automatikusan generált leírás

A képen a légnyomásmérő is látszik, a doboz alján lóg a levegőben. Csak úgy fityeg egy vezeték darabon.

Természetesen minden részegységet első verzióban a konyhaasztalon próbáltam ki, megírogattam a vezérlő programokat, és csak a végén került minden a végleges helyére.

A programot nem mutatom meg, mert nem ez lett a végleges verzió. Két év használat során kiderült, hogy a számjegyek kicsik, a lakásunk ablakából nem látszik jól, még nagyobb számjegy kellene. Ráadásul a légnyomás és a páratartalom inkább dicsekvésre alkalmas adat (mármint lehet dicsekedni vele, hogy van), és nem igazán nézegetjük. Így mindhármat egyszerre kijelezni felesleges. Elég a hőmérséklet folyamatos kijelzése, és ezen kívül egyetlen számsor, amin váltakozva jelenítem meg a különböző mért adatokat. Ezért jelentősen átalakítottam a kijelzőt. Az új verzió kinézete:

A képen asztal, ülő, torta, fából készült látható

Automatikusan generált leírás
A képen ülő, aláírás, óra, méter látható

Automatikusan generált leírás

Nem látható a képen, de ez már más tekintetben is korszerűbb verzió. A kijelzőket foglalatba raktam. Ennek oka, hogy az első verzióban nem gondoltam a meleg káros hatására. Amikor nyáron a nap rásüt a berendezésre, belül a plexi mögött iszonyú meleg lesz. Az első verziót egy műanyag lapra szereltem, ami hullámosra „olvadt”:

Nem csak a műanyag lap nem bírta a strapát. A 7 szegmenses kijelzők jelentős részében sorba tönkrementek a szegmensek. A MAX7219 mátrix kijelzőiben is sorban aludtak ki a ledek, de ezt könnyen lehetett cserélni, mert eleve foglalatban volt a mátrix kijelző a saját elektronikája felett. A végén már nem lehetett kitalálni, hogy milyen számot mutat a kijelző. Igaz, ez csak a második nyáron következett be. Ideiglenesen úgy oldottam meg a problémát, hogy a programot átalakítottam, és kihagytam azokat a kijelzőket, amik nem működnek. A végén már csak a középső sor működött.

A 7 szegmens kijelzők foglalatát nyákba forrasztható csatlakozó sorból csináltam. Sajnos elsőre nem lett jó, mert kiderült, hogy a kijelzők kivezetései túl vékonyak ehhez, és nem csatlakoztak biztonságosan. Ha nyomkodtam a kijelzőt, hol egyik, hol másik szegmens aludt ki. A megoldás az lett, hogy a kijelzők kivezetéseihez vékony drótot forrasztottam, ami meg túl vastag lett, de így is bele lehetett ügyeskedni a foglalatba. Még nem kellett kijelzőt cserélni, remélem két három cserét ki fog bírni a foglalat. Vettem tartalékot bőven, hogy még vénebb koromban is cserélgethessem a kipurcant kijelzőket. A mátrix kijelzőkkel semmi baj, ott eleve foglalattal csatlakozott a matrix kijelző a MAX7219 vezérlő panelhoz. Mondjuk ehhez is vettem 10db kijelző mátrixot tartalékba. Nem kell rosszallóan ingatni a fejeket, ali-n 1000Ft-ba került! Csak el ne felejtsem, hogy van, mert esetleg veszek még, ha nem találom meg, és akkor már tényleg drága lesz az üzemeltetés a villanyszámlával együtt. Egyébként kb. 5W-ot fogyaszt az egész kütyü, ami egy év alatt kb 45 Kwh, a jelenlegi árakon ez kb. 2200Ft. Minden nap ránézünk legalább kétszer (ketten vagyunk), vagyis egy hőmérséklet mérés ára 1,5 Ft. Sajnos ez nem egy nyerő adat, az LCD kijelzős fali hőmérőnk költsége kb. évi 100Ft, mert abban csak egy elem kell egy-két évente, így ha azt nézegetnénk akkor 0,07Ft-ba kerülne (bocsi, de egy komoly projekt gazdasági számításokat is tartalmaz, ezt most letudtam)!

Az új fejlesztésben máshoz is kedvet kaptam, illetve másra is kényszert éreztem. Említettem, hogy nem nagyon nézegettük a légnyomás és páratartalom adatot. Ezek pillanatnyi értéke ugyanis nem sokat mond egy átlagembernek. A változás az már igen, de ki emlékszik arra, hogy mennyi volt tegnap a légnyomás. Ezért szerettem volna a mért adatokat rögzíteni egy SD kártyán. Ez komoly nehézségeket okozott. No nem azért, mert bonyolult az SD kártya írása! Sajnos az SD kártya kezelő könyvtárak mindegyike kb. 10Kbyte memóriát vett el a Nano-ban rendelkezésre álló 32K-ból. Egész egyszerűen kifogytam a memóriából, nem fért el a program. Nagyszerű ötletem támadt, két Nano kell, az egyik mér és kijelez, a másik SD kártyára írja az adatokat. Ugrott újabb 1000Ft.

De az SD kártyára írásnak van még egy következménye: kellett egy működő óra ahhoz, hogy utólag értelmesen felhasználhassam az adatokat. Ezzel nincs probléma, de ha van benne RTC óra, akkor kelleni fog egy LCD kijelző, mert időnként be kell állítani az órát. Nem egyszerű ennyi cuccot egybeépíteni! Még annyi változás történt, hogy a DHT22 szenzort egy másik típusra cseréltem (BME280), ezzel csökkent az alkatrészek száma, mert hőmérséklet, légnyomás és páratartalom mérés is benne van. Mivel I2C buszt használ, nem vett el további kivezetéseket a Nano-ból. Ez egyébként csak az egyszerűbb szerelés miatt volt szempont.

Végül néhány fotó a majdnem kész központi vezérlő egységről:

A képen beltéri, monitor, ülő, számítógép látható

Automatikusan generált leírás
A képen számítógép, áramkör látható

Automatikusan generált leírás

A beltéri központi vezérlőn látható az LCD, amin folyamatosan kijelzem a dátumot, időt, és váltogatom a szenzorok mért értékeit kb. 2másodpercenként.

Az alsó sorban látható W:22 azt jelenti, hogy 22 perc múlva fogok legközelebb írni az SD kártyára. Ez azért kellett, mert az SD kártyát időnként kiveszem, és laptopban kiolvasom az adatokat, aztán visszahelyezem, és így látom mennyi időm van, hogy ne veszítsek adatot. A kártyáról nem törlök, megtelni nem fog, mert csak 16Gb-os kártyát kaptam a boltban. 3 hónap alatt 171Kb helyet használtam el, tehát még 93 ezer évig regisztrálhatom. Talán James T. Kirk kapitány erre jár, és adataimmal megmentheti a földet!

Néhány szerelési tapasztalat még a végére. Az első verzióban sokat szívtam azzal, hogy a kábeleket az egyik végén beforrasztottam (a kijelzőnél). A másik végét egy csavarkötéses nano foglalatba kötöttem be. Nem nyerő megoldás. Sok volt a vezeték, nem lehetett áttekinteni a kábelek bekötését. Nagyon nehéz volt szerelni. Egyébként a csavarkötéses foglalat tök jó, csak ebben az esetben nem vált be, mert legalább 10-szer kellett ki be szerelnem az egészet, mert elsőre semmi nem működött jól. Tulajdonképpen az volt a baj, hogy már nagyon akartam látni a kész kütyüt, és túl hamar tettem ki a falra. Még nem volt minden készen, és egy falra felszerelt cuccot nehezebb fejleszteni, mint próbapanelen! Az új generációs megoldásban vettem gyárilag előre szerelt csatlakozókat. 2-3-5 eresek mindegyikéből 10-10 db-ot kaptam 300Ft-ért. Ez egy összedugható csatlakozó mindkét végén színes vezetékekkel. Ezek azok a színes kábelek a vezérlő belsejéről készült fotón. A vezetékeket előre beforrasztottam a nyáklemezre, és a szerelési oldalon műanyag ragasztóból folyattam rá anyagot, hogy ne lehessen túl könnyen kiszakítani.

DS18B20 hőmérőkkel is sokat kellett vesződnöm, bár leginkább egy figyelmetlenség miatt. Amikor kezdtem vele a kísérletezgetést, 10K-s ellenállás akadt a kezembe, és ezt használtam felhúzó ellenállásnak. Ez túl nagy érték, de a 10cm-es vezetékkel jól működött a 4db hőmérő. Aztán beszereltem a hosszabb vezetékeket, és persze nem működött. Arra emlékeztem a leírásokból, hogy lehet csökkenteni az ellenállás értékeket, és le is csökkentettem 4,7K-ra. Na ezzel már ment egy-egy hőmérő, de egy vezetékre többet nem lehetett rákötni. Így minden Dallas hőmérőt külön Nano kivezetéshez kötöttem, ami elvett 4 kivezetést, de jótékony hatása volt a szerelhetőségre is, mert mint kiderült az egy vezeték – egy csatlakozó megoldás jobb mint a sok vezeték – egy csatlakozó megoldás. Így néz ki a szenzorok csatlakozó sora a panelen:

A képen áramkör látható

Automatikusan generált leírás

A második verziónál ezért eleve külön kivezetést terveztem minden Dallas hőmérőnek. Szerelgetés közben, amikor újra olvastam egy leírást, észrevettem, hogy eleve 4,7K felhúzó ellenállást írt a cikk, és azt lehet csökkenteni. Le is csökkentettem 1,5K-ra. Remekül mentek is a hőmérők, még hosszabb vezetékkel is, és mind a négyet lehetett egy bemenetre kötni párhuzamosan. Azonban már nem változtattam a kialakításon, mert így egyszerűbb volt szerelni a vezetékeket.

DHT22 szenzort mint említettem lecseréltem egy BME280-ra, így annak a csatlakozója végül feleslegessé vált, most üresen tátong a lyuk!

A program is megfelelően bonyolult lett a végére. Lássunk egy leltárt, mi is került bele:

Az egyik Nano a master ezekkel a funkciókkal:

  • BME280 szenzor kiolvasása
  • Dallas DS18B20 szenzorok kiolvasása
  • RTC3231 óra modul kezelése
  • 2×16 karakteres LCD kijelző vezérlése
  • Egy nyomógomb kezelése, amivel az LCD-n megjelenő adatokat lehet váltogatni, és órát beállítani.
  • Egy hibajelző led villogtatása a hiba jellegétől függő ritmusban
  • A slave Nano felé adattovábbítás, és annak lekérdezése
  • Mért értékek átlagolása
  • 7 Szegmens led kijelzők meghajtása 74HC595 shift regiszterekkel
  • MAX7219 mátrix kijelzők meghajtása
  • Fénymérő fotótranzisztor lekérdezgetése, fényérték triggerelés, hogy ne villogjon a kijelző fényerő váltás határokon.
  • Fényerő állítás 7 szegmens és led mátrix kijelzőkön.

A másik slave Nano feladatai:

  • Fogadja az adatokat a master Nano-tól
  • SD kártya írása
  • SD kártya írási hibák visszajelzése master-nak.

Mindez így igen egyszerűnek látszik, az is, de egyben már dögösebb program. A program minden fontosabb részletét meg tudod ismerni a modulokról szóló menüpontban. Ahhoz, hogy ezt a szerkezetet meg tudjam építeni kb 5 év tapasztalatára volt szükségem. Ha valaki arra adná a fejét, hogy csináljon valami hasonlót, akkor a leírásaim alapján vélhetőleg kevesebb időre lesz szüksége, a nagy szívások jelentős részét leírtam ezen a weblapon. Persze most a kezdőkről beszélek, a gyakorlott profiknak ez ujjgyakorlat.

Kapcsolási rajzot még mindig nem tudok prezentálni, mert még mindig nem tanultam meg egyik erre szolgáló program használatát sem. Azonban annyira kommersz modulokat használtam, és annyira semmi extra nincs benne, hogy a forráskód kommentjeiből összeáll a kép. Kötve hiszem, hogy valaki egy-az egyben szeretné produkálni a szerkezetet, hiszen ehhez rá kellene vennie édesapámat, hogy adja neki a mások boroshordóját, hogy abból megcsinálhassa a külső „dobozt”. Nem hiszem, hogy menni fog! Esetleg az öcsémnek adná oda!

De ha mégis meg akarná valaki érteni a program működését, még néhány infót elárulok. Az egyszem nyomógomb működése a következő:

  • Első megnyomásra bekapcsolja az LCD háttérvilágítását
  • Második megnyomásra mutatja a DS1-DS4 Dallas szenzorok állapotát (OK vagy nem, működés közben kihúzható és vissza dugható)
  • Harmadik megnyomásra mutatja az SD kártyára írás állapotát, és a légnyomásmérő (külső hőmérő és pártartalommérő) állapotát.
  • Negyedik megnyomásra mutatja az utolsó SD kártya állományok írási időpontját (napi egyszer írok egy állományba éjfélkor egy napi átlagot, valamint egész óránként egy másik naponta külön kezdett állományba az egy órás átlagot)
  • 5-11. megnyomásra sorban mutatja az óra pillanatnyi dátumát és időpontját, és ha hosszan nyomom a gombot, lépteti az éppen mutatott adatot. Ha megfelelő értékhez ért, elengedem a gombot, és beállítja az órában. Kicsit macerás a beállítás, mert pl. a percek beállításánál jó sokáig pörgeti a számot 0-59-ig, és ha nem figyelsz, nyomhatod még egy kört. Az év-nél ha jól emlékszem csak 2050-ig lehet pörgetni a számot, ezt követően vissza áll 2020-ra és onnan indul a számlálás újra.

Ez kb. így néz ki a kijelzőn nyomogatás közben:

Ha befejeztem az összes érték állítását (év, hónap, nap, hét nap, óra, perc) várni kell 5 másodpercet, és visszaáll az alap kijelzésre. Mutatja a dátumot, időpontot és pörgeti ciklikusan a szenzorok mért pillanatnyi adatait.

A led kijelző villogással jelzi, ha valamelyik szenzort nem tudja lekérdezni a program. Ha az SD kártya nincs a helyén, vagy nem elérhető, akkor ezt az infót a slave Nano visszaadja a masternak 10 másodpercenként egyszer, és ekkor is villog a led. Ha több hiba is van egyszerre, akkor gyorsabban villog.

Ha már ilyen sok képet beraktam, következzen még néhány a fő kijelzőről, amint váltogatja a mért adatokat:

Elméletileg minden szenzort le lehet húzni a csatlakozóról menet közben. Ha visszadugom, felismeri, és megy minden tovább. Ha nincs szenzor feldugva, vagy nem működik, akkor a mért érték helyett a hőmérsékletnél 99fok, a páratartalomnál -99, a légnyomásnál 888 kerül kijelzésre, mert ezek láthatóan nem valós értékek.

SD kártyára kétféle állományt készítek. Van egy év file, ennek neve pl. „EV2020.CSV” valamint van egy nap file. Ebből minden nap egy újat csinálok, neve pl. „NP200506.CSV” (az évnek csak az utolsó két számjegye szerepel). Ebbe az állományban egy nap 24-szer írok, óránként. A rögzített adatok az elmúlt egy óra átlag értékei. Az év állományban az elmúlt nap átlag értékei találhatók. A külső hőmérséklet minimumát és maximumát is rögzítem mindkét állományban.

Ime egy példa az év állományból:

Datum;Ido;Homerseklet;Homerseklet_min;Homerseklet_max;Paratartalom;Legnyomas;Kishaz;Akna also;Akna felso;Pince;
2020.02.11;23:59:00;23.35;22.55;24.30;45.15;982.37;23.39;22.58;-99.90;21.95;
2020.02.12;23:59:00;23.62;23.08;24.09;47.01;994.89;22.90;21.94;-99.89;22.01;
2020.02.13;23:59:00;23.00;21.45;23.46;45.18;994.80;22.15;22.08;-99.90;23.51;
2020.02.14;23:59:00;24.76;23.79;25.25;44.44;998.73;22.10;99.89;23.88;22.21;
2020.02.15;23:59:00;23.41;22.08;24.49;44.49;1004.63;22.21;22.84;23.11;22.32;


…és egy nap állomány:

Datum;Ido;Homerseklet;Homerseklet_min;Homerseklet_max;Paratartalom;Legnyomas;Kishaz;Akna also;Akna felso;Pince;
2020.06.05;01:00:00;18.09;17.93;18.29;67.22;977.27;19.46;11.08;5101.57;13.85;
2020.06.05;02:00:00;17.94;17.84;18.08;65.31;977.14;19.25;11.09;836.09;13.86;
2020.06.05;03:00:00;17.87;17.50;18.08;65.44;977.00;19.05;11.07;464.34;13.87;
2020.06.05;04:00:00;17.39;17.35;17.45;68.61;976.60;18.88;11.08;322.19;13.87;
2020.06.05;05:00:00;17.19;16.94;17.36;67.54;976.46;18.69;11.09;248.12;13.87;
2020.06.05;06:00:00;16.96;16.85;17.09;66.86;976.45;18.48;11.10;1533.11;13.87;
2020.06.05;07:00:00;17.33;17.08;17.70;60.87;976.43;18.34;11.08;630.51;13.87;
2020.06.05;08:00:00;17.85;17.51;18.11;58.44;976.74;18.31;11.10;402.98;13.87;
2020.06.05;09:00:00;18.56;18.09;18.73;55.44;977.15;18.31;11.09;296.60;13.87;
2020.06.05;10:00:00;18.78;18.24;19.61;60.68;977.59;18.32;11.09;6272.83;13.87;
2020.06.05;11:00:00;18.98;18.69;19.41;66.24;977.67;18.43;11.09;947.25;13.87;
2020.06.05;12:00:00;18.52;18.18;18.78;70.76;978.03;18.29;11.11;517.77;13.88;
2020.06.05;13:00:01;18.94;18.59;19.19;69.59;977.96;18.39;11.12;358.79;13.89;
2020.06.05;14:00:00;19.67;19.14;20.29;63.54;977.85;18.62;11.11;277.07;13.91;
2020.06.05;15:00:00;21.80;19.48;22.75;57.16;977.41;19.23;11.12;1747.54;13.92;
2020.06.05;16:00:01;22.66;22.40;23.04;53.24;977.30;20.12;11.12;706.81;13.93;
2020.06.05;17:00:00;23.07;22.56;23.73;55.14;977.37;20.51;11.12;446.63;13.93;
2020.06.05;18:00:00;21.47;19.92;22.62;66.24;977.36;20.28;11.12;328.37;13.93;
2020.06.05;19:00:00;19.32;18.65;19.87;78.46;978.58;19.71;11.12;7706.46;13.93;
2020.06.05;20:00:00;18.19;17.76;18.65;80.22;979.54;19.43;11.12;1062.11;13.94;
2020.06.05;21:00:00;17.52;17.20;17.92;82.47;980.37;19.04;11.12;575.95;13.95;
2020.06.05;22:00:00;17.05;16.84;17.26;84.55;981.30;19.00;11.12;397.68;13.96;
2020.06.05;23:00:00;16.93;16.83;16.99;85.55;981.93;18.77;11.12;305.16;13.97;
2020.06.05;00:00:00;16.73;16.68;16.81;86.26;982.39;18.56;11.12;1974.38;13.97;


Most vettem észre, hogy az akna alsó értékben valami marhaság van, úgy tűnik van programhiba, amit nem vettem észre. Bocsi, javítani fogom.

A master programja:

/**************************************************************************************************
 * Kivezetések gyüjteménye:
 * A0 véglegesben pince DS18b20 hőmérő panelen DS1 felirat
 * A1 véglegesben akna felső DS18b20 hőmérő panelen DS2 felirat 
 * A2 véglegesben akna alsó DS18b20 hőmérő panelen DS3 felirat
 * A3 véglegesben kisház DS18b20 hőmérő panelen DS3 felirat
 * A4 - SDA jelvezeték I2C kommunikációhoz
 * A5 - SLC jelvezeték I2C kommunikációhoz
 * A6 - véglegesben fénymérő
 * D2 - latch pin (ST_CP)  74HC595
 * D3 - clockPin (SH_CP) 74HC595  
 * D4 - dataPin (DS) 74HC595 
 * D5 - ChipEnable (CE)74HC595   
 * D6 - LOAD (CS) MAX7219 ledmatrix      
 * D7 - CLK MAX7219 ledmatrix 
 * D8 - DataIn MAX7219 ledmatrix
 * D9 - DHT22/DHT11 Data
 * D10 - kijelzo ki/be nyomógomb bemenet (fejlesztéskor használtam, hogy éjszaka ne világítson
 */

#include<avr/wdt.h> //WatchDog header betöltése

//I2C busz kezelése 
#include <Wire.h>


//Fram cím adatai és cella típus felsorolása
byte A0A1=0b00;
byte _i2cAddress= (0b101000 | A0A1)<<1;
enum cella_tipus { MIN, MAX, SUM, AVG, STO };
//napi átlaghoz tároló cellák címeinek felsorolása
/*const byte v_kulso_n=0;
const byte v_kulso_n_min=1;
const byte v_kulso_n_max=2;
const byte v_para_n=3;
const byte v_para_n_min=4;
const byte v_para_n_max=5;
const byte v_legny_n=6;
const byte v_legny_n_min=7;
const byte v_legny_n_max=8;
const byte v_pince_n=9;
const byte v_aknaa_n=10;
const byte v_aknaf_n=11;
const byte v_kishaz_n=12;
const byte v_kishaz_n_min=13;
const byte v_kishaz_n_max=14;*/
//orankenti átlaghoz tároló cellák címeinek felsorolása
const byte v_kulso_o=15;
const byte v_kulso_o_min=16;
const byte v_kulso_o_max=17;
const byte v_para_o=18;
const byte v_para_o_min=19;
const byte v_para_o_max=20;
const byte v_legny_o=21;
const byte v_legny_o_min=22;
const byte v_legny_o_max=23;
const byte v_pince_o=24;
const byte v_aknaa_o=25;
const byte v_aknaf_o=26;
const byte v_kishaz_o=27;
const byte v_kishaz_o_min=28;
const byte v_kishaz_o_max=29;
long kuldendo1; //segédváltozó az adatküldéshez, első lépésben ebbe olvassuk be a memória cella tartalmát, mert az is i2c-t használ     
long kuldendo2; //segédváltozó az adatküldéshez, első lépésben ebbe olvassuk be a memória cella tartalmát, mert az is i2c-t használ     
long kuldendo3; //segédváltozó az adatküldéshez, első lépésben ebbe olvassuk be a memória cella tartalmát, mert az is i2c-t használ     
long kuldendo4; //segédváltozó az adatküldéshez, első lépésben ebbe olvassuk be a memória cella tartalmát, mert az is i2c-t használ     
long kuldendo5; //segédváltozó az adatküldéshez, első lépésben ebbe olvassuk be a memória cella tartalmát, mert az is i2c-t használ     

//mérési eredményekhez
float kulso_homerseklet=0;
float paratartalom=0;
float legnyomas=1000;
float pince_homerseklet=0;
float akna_homerseklet_also=0;
float akna_homerseklet_felso=0;
float kishaz_homerseklet=0;

//BME280 érzékelőhöz
//#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C

//LCD kijelző kezelése
#include <LiquidCrystal_I2C.h>  //I2C LCD kezelő könyvtár
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  //LCD paraméterek megadása, a 4 soros LCD-m címe 3F, kétsors címe 27

//óra modul programjai és változó deklarációi
//==========================================
#include <DS3231.h>
DS3231 Clock;
bool Century=false;
bool h12=true;
bool PM;
byte ev=0;
byte ho=0;
byte nap=0;
byte ora=0;
byte perc=0;
byte masodperc=0;
String str_tmp;
String utolso_nap_iras="Nap file:Nemvolt";
String utolso_ev_iras="Ev file:Nem volt";
byte sd_hiba=2; //A slvae küldi vissza ezt az értéket az adat fogadás után, és visszajelzi, hogy sikerült-e az SD írás 0=ok, 1=hiba, 2=nincs adat

// DALLAS hőmérő chip-ek bekötése, használatuk előkészítése
//=========================================================
    // Dallas onwire hőmérő chip (felülrőlnézve balról jobbra haladva)
    //  18B20 kivezetés   Vezeték            Arduino UNO/NANO kivezetés
    //  GDD               kék vezeték        GND
    //  DATA              sárga vezeték      A3, A1, A6 kivezetéseken 
    //  VDD               piros vezeték      +5V
  #include <OneWire.h>          //Dallas 18b20 hőmérő kezeléshez one-wire busz
  #define chip_max_num 2        //2 chipet kezelünk egy vezeteken maximum
  byte dallas_addr[8];                 //aktuális chip címének a tárolására
  byte dallas1_addr_t[chip_max_num][8]; //chip címek tárolására
  byte dallas2_addr_t[chip_max_num][8]; //chip címek tárolására
  byte dallas3_addr_t[chip_max_num][8]; //chip címek tárolására
  byte dallas4_addr_t[chip_max_num][8]; //chip címek tárolására
  byte dallas_chip_num=0;              //aktuális chip sorszáma
  byte dallas_data[9];                 //kiolvasott adtok tárolására
  OneWire  ds1(A0);              // a A0. kivezetéshez kell kapcsolni pince hőmérőjét 
  OneWire  ds2(A1);              // a A1. kivezetéshez kell kapcsolni az akna felső hőmérőjét 
  OneWire  ds3(A2);              // a A2. kivezetéshez kell kapcsolni az akna alsó hőmérőjét 
  OneWire  ds4(A3);              // a A3. kivezetéshez kell kapcsolni az kisház hőmérőjét 
  
//fénymérés TEPT4400 fototranzisztorral. A rövidebb láb a kollektor, ez megy a tápfesz 5V-ra
//A hosszabb láb az emitter, ez egy 1Kohm ellenálláson keresztül megy a földre. Az emitterből
//vezetem a mérendő feszültséget az A6 bemenetre. Sötétben a mért fesz 0 körül, napsütésben 
//1000 körül. Megvilágítva nyit ki a tranzisztor és felhúzza a jelvezetéket a tápfeszre.
//A méréskor a tápfeszt veszem referenciának!int mert_fenyero[10]={0,0,0,0,0,0,0,0,0,0}; //az utolso 10 mért fenyero erteke
int fenyertek=0; //az utolso 10 mért fenyerő érték átlaga


//MAX7219-4DM 8x8 led matrix modul************************
//--------------------------------------------------------
    // Led matrix (matrix feliratú kábel):
    //  MAX7219 kivezetés   Vezeték           Arduino UNO/NANO kivezetés
    //  DataIn             (piros vezeték)    D8 (pin13)
    //  CLK                (fekete vezeték)   D7 (pin12)
    //  LOAD (CS)          (zöld vezeték)     D6 (pin11) 

#include "LedControl.h"       
LedControl lc=LedControl(8,7,6,3); //kimeneteket beállítja magának
// karakterképek tárolása tömbökben
//fok celsius karakterkép egy modulon
//const byte lc_celsius[8]={B01100000,B10010000,B01100000,B00000000,B01111100,B10000010,B10000010,B01000100};   
//  Milibar   Százalék   Pince     Akna   Akna felső Akna alsó   ház
// B..11111. B11...1.. B00000000 B00000000 B00111110 B00000000 B00000000
// B..1..... B11..1... B00000000 B00000000 B01001000 B00111110 B00000000
// B...1111. B...1.... B00000000 B00000000 B01001000 B01001000 B00000000
// B..1..... B..1..11. B01111110 B00111110 B00111110 B01001000 B01111110
// B...1111. B.1...11. B01001000 B01001000 B00000000 B00111110 B00011000
// B........ B........ B01001000 B01001000 B01110000 B00000000 B00011000
// B1111111. B........ B00110000 B00000000 B00000000 B00001110 B01111110
// B..1...1. B........ B00000000 B00111110 B00000000 B00000000 B00000000
// B..1...1. Fényerő * Celsius
// B...111.. B01000100 
// B........ B00101000 
// B..11111. B00111000 
// B...1.... B11111110 
// B..1..... B00111000 
// B..1..... B00101000 
//           B01000100 
// led matrix vezérlő parancsok mintapéldák:
// lc.setRow(index,sor,B10100000);
// lc.setLed(index,sor,oszlop,true); fénypont bekapcsolása
// lc.setLed(index,sor,oszlop,false);  fénypont kikapcsolása
// lc.setColumn(0,oszlop,B10100000);

//hétszegmens kijelző vezérlés előkészítés
//----------------------------------------
// 7 szegmens kijelzó (7szegmens feliratú kábel) 74CH595 chip meghajtóval
// 10 modul sorma kötve, soros bitenkénti (modulonkénti 8 bit)beléptetéssel
//  74CH595 kivezetés  Vezeték           Arduino UNO/NANO kivezetés
//  latch pin (ST_CP)  kék vezeték       D2
//  clockPin (SH_CP)   fehér vezeték     D3
//  dataPin (DS)       sárga vezeték     D4
//  ChipEnable (CE)    zöld vezeték      D5

// 7 szegmens karakterkép előállításhoz segédlet
// --A--
// F   B
// --G--
// E   C 
// --D-- P (P=tizedespont)
// számjegyek kijelzéséhez szükséges aktív szegmensek:
// 0=ABCDEF,1=BC,2=ABGED,3=ABGCD,4=BCFG,5=ACDFG,6=ACDEFG,7=ABC,8=ABCDEFG,9=ABCDFG
// Mask: ABFGDPCE (a 8 bites bitfolyamban ebben a sorrendben lett vezetékezve
//       a 74CH595 IC kivezetése hozzákötve a kijelző modul egyes szegmenseihez 
//      tizedespont balról a 6. bit
//karakterképek definiálása: 0-9-ig számjegyek, 10-üres, 11-minuszjel, 12-dupla aláhúzás
const byte karakterkep[13]={B11101011,  //0
                      B10000001,  //1
                      B01110011,  //2
                      B11010011,  //3
                      B10011001,  //4
                      B11011010,  //5
                      B11111010,  //6
                      B10000011,  //7
                      B11111011,  //8
                      B11011011,  //9
                      B00000000,  //ÜRES
                      B00010000,  //MINUSZ
                      B00010010}; //DUPLA ALÁHUZAS
// próbáltam spóromli a memóriával, ezért direktben írtam be a programba, de nem ált be
//const int latchPin = 2;   //pin2 (ST_CP) 74HC595 
//const int clockPin = 3;   //clock pin (SH_CP) 74HC595
//const int dataPin = 4;    //Data in (DS) 74HC595
//const int ChipEnable = 5; //CE kivezetés 74HC95                          


// a mért értéket karakterképének bitsorozta a 7 segment kijelzőbe léptetéshez (4 számjegy)
byte bitsor0[4];  //0 - külső hőmérséklet
byte bitsor1[4];  //1 - páratartalom
byte bitsor2[4];  //2 - légnyomás
byte bitsor3[4];  //3 - pince hőmérséklet
byte bitsor4[4];  //4 - akna hőmérséklet also
byte bitsor5[4];  //4 - akna hőmérséklet felso
byte bitsor6[4];  //5 - kisház hőmérséklet
byte eszkoz_num=0;     //az aktuálisan lekérdezett eszköz indexe, megeggyezik a bitsor változó számjegyével
long meres_ido=millis(); //15 másodpercenkénti mérés időzítéséhez segédváltozó 
long kijelzovaltas_ido=millis(); //az alsó sor értékeinek váltogatásának időzítéséhez
long fenyero_ido_tmp=millis();  //a fényerő beállításának időzítéséhez (1 másodpercenként)
long sd_lekerd_ido=millis();  //az SD kártya ellenőrzésének időzítéséhez (I2C buszin kérdezzük le a slave-től)
bool tarolas=false;
bool tarolasnap=false;



//a kijelzo nyomógombbal történő ki és bekapcsolásához kellenek
bool elengedve=LOW; //a nyomógomb elengedett állapotát jelzi, akkor HIGH, ha egy nyomvatartás után (nyomva=HIGH) elősször megszakad a ontaktus
long elenged_ido=millis(); //az elengedés prellmenetsítéséhez az időmérésre
bool nyomva=LOW;  //ha HIG, akkor nyomva van a nyomógomb, az első kontaktus HIGH-re állítja, elengedés után lesz LOW-ra visszaállítva
long nyomva_ido=millis();  //az megnyomás prellmentesítéséhez időmérésre
bool lcd_vilagitas=LOW;
bool kijelzo_kapcsolas=LOW; //ha 1, akkor éppen végrehajtottunk egy kijelző állapotváltást, és nyomógomb elengedésig megakadályozza, hogy ez megismétlődjön
bool kijelzo_ki_be=HIGH; //a kijelzo ki és bakapcsolt állapotát tárolja
long adatkuldes_ido=millis();
bool ora_setup=LOW;
long ora_setup_ido=millis();
byte setup_num=0;
byte ora_setup_ertek=0;
byte ora_setup_ujertek=0;
bool setup_num_novel=HIGH; //ha növelni lehet egy elengedés után a setup_num-ot, akkor HIGH. Érték változtatás után lesz LOW, hogy ne növekedjen a setup_num értéke
bool mert_ertek_kijelzes=HIGH; //mérési eredmények lcd-re írásának engedélyezés HIGH értékkel
byte kijelzes_num=1;   //az aktuálisan kijelzett érték indexe, megeggyezik a bitsor változó számjegyével
long adatfogadas_ido=millis()+6000; //percenként fogadjuk a mert adatokat a slave-tól, ugyaekkor mérjuk a légnyomást is
long lcd_frissit_ido_tmp=millis()+1000;  //az lcd adatkiírás frissítéshez és a fényerő beállításának időzítéséhez (1 másodpercenként)
long lcd_kijelzo_ido=millis();
byte lcd_eszkoz_num=0;     //az aktuálisan kijelzett eszköz indexe az lcd kijelzőn frissített mert adathoz

bool ds1_on=LOW; //DS1 hűmérő incializálva lett-e, HIGH esetén igen
bool ds2_on=LOW; //DS2 hűmérő incializálva lett-e, HIGH esetén igen
bool ds3_on=LOW; //DS3 hűmérő incializálva lett-e, HIGH esetén igen
bool ds4_on=LOW; //DS4 hűmérő incializálva lett-e, HIGH esetén igen
bool ds1_crc_hiba=LOW; //High esetén DS1 Dallas chip CRC hibát eredményezett olvasáskor
bool ds2_crc_hiba=LOW; //High esetén DS1 Dallas chip CRC hibát eredményezett olvasáskor
bool ds3_crc_hiba=LOW; //High esetén DS1 Dallas chip CRC hibát eredményezett olvasáskor
bool ds4_crc_hiba=LOW; //High esetén DS1 Dallas chip CRC hibát eredményezett olvasáskor
bool bme280_on=LOW; //bme280 légnyomás, páratrtalom és hőmérséklet mérő inicializálva lett-e, HIGH esetén igen

void setup()
{
  wdt_enable(WDTO_4S);  //engedélyezük a watcdog-ot 4 sekundum várakozással 
                        //4sec után a chip ujaindítja magát, ha nincs közben
                        // wdt_reset() függvényhívás, ami ujraindítja a timert

  
  //74HC595 előkészítése
  pinMode(2,OUTPUT); //latch pin 74HC595
  pinMode(4,OUTPUT); //data pin (DS) 74HC595
  pinMode(3,OUTPUT); //Clock pin 74HC595
  pinMode(5,OUTPUT);  //chipenabla (CE) 74HC595
  //kijelző önteszt
  analogWrite(5,128);  //kezdő fényerő beállítás a hétszegmen kijelzőn. Csak a bekapcsolási folyamat alatt 
  digitalWrite(2, LOW); //shift regiszter kimenetek lezárása (latchPin=0)
  shiftOut(4, 3, MSBFIRST, B11111111);            //külső hőmérséklet szazas
  shiftOut(4, 3, MSBFIRST, B11111111);            //külső hőmérséklet tizes
  shiftOut(4, 3, MSBFIRST, B11111111);            //külső hőmérséklet egyes
  shiftOut(4, 3, MSBFIRST, B11111111);            //külső hőmérséklet tizedes
  shiftOut(4, 3, MSBFIRST, B11111111);            //páratartalom ezres (mindíg üres)
  shiftOut(4, 3, MSBFIRST, B11111111);            //páratartalom szazas (mindíg üres)
  shiftOut(4, 3, MSBFIRST, B11111111);            //páratartalom tizes
  shiftOut(4, 3, MSBFIRST, B11111111);            //páratartalom egyes
  digitalWrite(2, HIGH); //shift regiszter kimeneteire a beléptetett infó kiírása (latchPin=1)
  // 8x8 matrix felebresztese
  lc.shutdown(0,false);lc.shutdown(1,false);lc.shutdown(2,false);
  lc.setIntensity(0,8);lc.setIntensity(1,8);lc.setIntensity(2,8);
  // matrix kijelző önteszt
  for (int i=0;i<3;i++) { for (int j=0;j<8;j++) {lc.setRow(i,j,B11111111);} }

  Wire.begin(); //I2C inicializálása
  //***************************************Ezt csak egyszer kell lefuttatni, aztán ki kell kommentezni***************************
  /*/FRAM cellak elokeszítése naponkénti átlaghoz
  multimemo(v_kulso_n,AVG);multimemo(v_kulso_n_min,MIN);multimemo(v_kulso_n_max,MAX);
  multimemo(v_para_n,AVG);multimemo(v_para_n_min,MIN);  multimemo(v_para_n_max,MAX);
  multimemo(v_legny_n,AVG);multimemo(v_legny_n_min,MIN);multimemo(v_legny_n_max,MAX);
  multimemo(v_pince_n,AVG);multimemo(v_aknaa_n,AVG);multimemo(v_aknaf_n,AVG);
  multimemo(v_kishaz_n,AVG);multimemo(v_kishaz_n_min,MIN);multimemo(v_kishaz_n_max,MAX);
  //FRAM cellak elokeszítése orankenti átlaghoz
  multimemo(v_kulso_o,AVG);multimemo(v_kulso_o_min,MIN);multimemo(v_kulso_o_max,MAX);
  multimemo(v_para_o,AVG);multimemo(v_para_o_min,MIN);multimemo(v_para_o_max,MAX);
  multimemo(v_legny_o,AVG);multimemo(v_legny_o_min,MIN);multimemo(v_legny_o_max,MAX);
  multimemo(v_pince_o,AVG);multimemo(v_aknaa_o,AVG);multimemo(v_aknaf_o,AVG);
  multimemo(v_kishaz_o,AVG);multimemo(v_kishaz_o_min,MIN);multimemo(v_kishaz_o_max,MAX);
  multimemo(30,STO);multimemo(31,STO);multimemo(32,STO);
  //Ezt pedig célszerű második lépésben kikommentezni, ha már történt néhány mérés, mert akkor azok adatait
  //fogja tárolni és az előző napi átlag és min max lekérdezéshez nem nullát fog írni. Egyébként az előző
  //napi adatok minden nap egyszer, éjfélkor kerülnek tárolásra, tehát egy nap múlva lesz benne valós adat
  long szam=multimemo(v_kulso_n);multimemo(30,szam);
  szam=multimemo(v_kulso_n_min);multimemo(31,szam);
  szam=multimemo(v_kulso_n_max);multimemo(32,szam);*/
  //*********************************************************************************************************************************

  //LCD inicializálása
  lcd.begin(16,2);
  lcd.clear();
  lcd.backlight();      //háttérvilágítás bekapcsolása
  
  //Serial.begin(9600);
 
  bme280_lekerdez();
  pince_homerseklet=onewire_meres(1);
  akna_homerseklet_felso=onewire_meres(2);
  akna_homerseklet_also=onewire_meres(3);
  kishaz_homerseklet=onewire_meres(4);

  //ide jönnek majd az első mérések, és egy 0. változó feltöltés, hogy rögtön indulhasson az értékek kijelzése
  szamjegybontas(kulso_homerseklet,0,0); //kulső hőmérséklet karakterképe bitsor0 tömbbe
  szamjegybontas(paratartalom,1,1); //páratartalom karakterképe bitsor1 tömbbe
  szamjegybontas(legnyomas,2,1); //legnyomás karakterképe bitsor2 tömbbe
  szamjegybontas(pince_homerseklet,3,0); //pince hőmérséklet karakterképe bitsor3 tömbbe
  szamjegybontas(akna_homerseklet_also,4,0); //akna hőmérséklet karakterképe bitsor4 tömbbe
  szamjegybontas(kishaz_homerseklet,5,0); //kisház hőmérséklet karakterképe bitsor5 tömbbe 

  //felső sor matrix kijelzőjére "°C" felirat
  lc.setRow(2,0,B00000000);
  lc.setRow(2,1,B01000110);
  lc.setRow(2,2,B10101001);
  lc.setRow(2,3,B10101000);
  lc.setRow(2,4,B01001000);
  lc.setRow(2,5,B00001000);
  lc.setRow(2,6,B00001001);
  lc.setRow(2,7,B00000110);
  
  lcd.noBacklight();      //LCD háttérvilágítás kikapcsolása

  pinMode(10,INPUT);  //nyomógomb erre a bemenetre van kötve

  // átküldjük a slave-ra 6-os kóddal a pillanatnyi időt és dátumot
  // A slave SD-re írja az elindulás dátumát és időpontját START.CSV nevű állományba.
  // Ezzel rögzítjük, ha reset, bekapcsolás, vagy watcdog újraindítja a rendszert
  ev=Clock.getYear();
  ho=Clock.getMonth(Century);
  nap=Clock.getDate();
  ora=Clock.getHour(h12,PM);
  perc=Clock.getMinute();  
  masodperc=Clock.getSecond();
  Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
  Wire.write(8);
  Wire.write(ev);
  Wire.write(ho);
  Wire.write(nap);
  Wire.write(ora);
  Wire.write(perc);
  Wire.write(masodperc);
  Wire.endTransmission();     // vége az átvitelnek
  Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé  

}

void loop()
{
TWBR = 255; //I2C buszsebesség 30Khz
  
  /*****************************************************************************
   * 10 másodpercenként lekérdezzük, hogy működik-e az SD kártya. Az SD kártya
   * írás állapotát az LCD-n le lehet kérdezni (OK=sikerül, ERR=nem sikerült).  
   * Elküldjük az erzekelökről, hogy van-e hiba. Ha van érzékelő hiba
   * akkor villogni fog a led a kijelző panelen. Az LCD kijelzőn is kiírjuk
   * a hiba állapotot érzékelőnként (SD1a,SD1b,SD2,SD3: OK=működik,
   *                                           OFF=nem található,
   *                                           CRC=crc hiba az érzékelő olvasásakor
   *****************************************************************************/
  if (millis()>sd_lekerd_ido+10000)
  {
    Wire.requestFrom(8,1);      // a master kér 1 byte-ot a slave-től
    sd_hiba= Wire.read();       //beolvassuk a slave által küldött byte-ot    
    sd_lekerd_ido=millis();
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(9); //a 9-es küldési kód jelzi a hiba átvitelt
    if (ds1_crc_hiba or ds2_crc_hiba or ds3_crc_hiba or !bme280_on or !ds1_on or !ds2_on or !ds3_on or !ds4_on) //ha bármelyik érzékelő hibás, akkor villogjon a led 
      {Wire.write(1);}  //valamelyik érzékelővel hiba van
    else
      {Wire.write(0);} //nincs hiba az érzékelőkkel
    Wire.endTransmission();     // vége az átvitelnek
  } 
  /****************************************************************************
   *másodpercenként frissítjük a kijelzőn az időt
   ****************************************************************************/
  if (millis()>lcd_frissit_ido_tmp+1000)
    {
      // Mivel ezt a programrészt másodpercenkét futtatjuk, felhasználhatjuk arra, hogy másodpercenként 
      // reseteljük a wotchdog számlálóját. Ha a program lefagy, és nem hajtódik végre a wdt_reset, akkor
      // 4 másodperc után újraindul az Arduino nano programja, mintha resetet nyomtunk volna
      wdt_reset(); //alaphelyzetbe állítjuk a a watcdog timer-t

      fenyero_beallitas(); //fenymérés és fényerő beállítás 
      if (ora_setup==LOW) 
      {
        if (ora==0 and perc==0 and (masodperc==0 or masodperc==1))
        {
          str_tmp="";
          ev=Clock.getYear();
          ho=Clock.getMonth(Century);
          nap=Clock.getDate();
          if (ho<10) {str_tmp=str_tmp+"0"+String(ho)+"/";} else {str_tmp=str_tmp+String(ho)+"/";}
          if (nap<10) {str_tmp=str_tmp+"0"+String(nap);} else {str_tmp=str_tmp+String(nap)+" ";}
          lcd.setCursor(0,0);lcd.print(str_tmp);
        }
        ora=Clock.getHour(h12,PM);
        perc=Clock.getMinute();  //percenként fogunk mérni és ez kell a perc változás észrevételéhez
        masodperc=Clock.getSecond();
        if (ora<10) {str_tmp=" 0"+String(ora)+":";} else {str_tmp=" "+String(ora)+":";}
        if (perc<10) {str_tmp=str_tmp+"0"+String(perc)+":";} else {str_tmp=str_tmp+String(perc)+":";}
        if (masodperc<10) {str_tmp=str_tmp+"0"+String(masodperc)+"  ";} else {str_tmp=str_tmp+String(masodperc)+"  ";}
        lcd.setCursor(5,0);lcd.print(str_tmp);
        lcd.setCursor(0,1);lcd.print("W:   ");
        if (60-perc<10) {lcd.setCursor(2,1);lcd.print(String(60-perc)+" ");} else {lcd.setCursor(2,1);lcd.print(String(60-perc));}
        if (masodperc>10) {tarolas=true;tarolasnap=true;}  //azrt kell, hogy a tarolas csak egyszer fusson le az adott percben
      }
      lcd_frissit_ido_tmp=millis();
    }
  
  /*********************************************************************************************************************************
   * A nyomógomb megnyomásával váltogatjuk a kijelző tartalmát
   *********************************************************************************************************************************/
  //megnyomta a nyomógombot, de még lehet, hogy prelles
  if (digitalRead(10)==LOW and nyomva==LOW) {nyomva_ido=millis();nyomva=HIGH;lcd.backlight();}    //megynomta a setup gombot
  //ha 50msec mulva is nyomva tartja,akkor ez már nem prelles, biztosn nyomva van, lehet belépni a setup folyamatba
  if (digitalRead(10)==LOW and millis()>nyomva_ido+50 and nyomva==HIGH) {ora_setup_ido=millis();ora_setup=HIGH;}
  //elengedte a nyomógombot, de még lehet, hogy prelles
  if (digitalRead(10)==HIGH and elengedve==LOW and nyomva==HIGH) {elenged_ido=millis();elengedve=HIGH;}
  //már 70msec óta elenged, biztosan nem prelles, beállítási értéket váltunk, lehet várni az új megnyomásra
  if (digitalRead(10)==HIGH and elengedve==HIGH and millis()>elenged_ido+50) 
  {
    nyomva=LOW;
    elengedve=LOW;
    if (ora_setup==HIGH) //setup módban vagyunk, lehet beállítani a következő setup értéket és várakozni a váltásra vagy nyomva tartás esetén a beállításra
    {
      if (setup_num_novel==HIGH) {setup_num=setup_num+1;if (setup_num==15){setup_num=9;}}
      setup_num_novel=HIGH; //ha változtatás után nem kellett növelni, legözelebb már kell
      switch (setup_num) {
        case 1: //csak a világítást kapcsoljuk be a kijelzőn, és egy percig így is marad
          mert_ertek_kijelzes=HIGH; //mehet tovább a mérési eredmények kijlzése
          lcd_vilagitas=HIGH;  //ha éppen világit az LCD, akkor nem akarja majd újra bekapcsolni az első lenyomással, helyette
                               //rögtön a setup_num értéke 2 lesz, tehát kijelzi az érzékelők állapotát
          break;
       case 2: //átlag érték kijelzés
          lcd.setCursor(0,0);lcd.print("Tegnapi atlag:  ");
          lcd.setCursor(0,1);lcd.print("                ");
          lcd.setCursor(7,1);lcd.print((float)multimemo(30)/100);
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
       case 3: //átlag érték kijelzés
          lcd.setCursor(0,0);lcd.print("Tegnapi min/max:");
          lcd.setCursor(0,1);lcd.print("                ");
          lcd.setCursor(0,1);lcd.print((float)multimemo(31)/100);
          lcd.setCursor(7,1);lcd.print("/");
          lcd.setCursor(9,1);lcd.print((float)multimemo(32)/100);
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
       case 4: //átlag érték kijelzés
          lcd.setCursor(0,0);lcd.print("Jelenlegi atlag:");
          lcd.setCursor(0,1);lcd.print("                ");
          lcd.setCursor(7,1);lcd.print((float)multimemo(0)/100);
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
       case 5: //átlag érték kijelzés
          lcd.setCursor(0,0);lcd.print("Jelenl. min/max:");
          lcd.setCursor(0,1);lcd.print("                ");
          lcd.setCursor(0,1);lcd.print((float)multimemo(1)/100);
          lcd.setCursor(7,1);lcd.print("/");
          lcd.setCursor(9,1);lcd.print((float)multimemo(2)/100);
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
        case 6: //onewire hőmérők állapot visszajelzée
          lcd.setCursor(0,0);lcd.print("DS1:OK  DS2:OK  ");
          lcd.setCursor(0,1);lcd.print("DS3:OK  DS4:OK  ");
          lcd.setCursor(4,0);
          if (ds1_crc_hiba) {lcd.print("CRC");} if (!ds1_on) {lcd.print("OFF");} 
          lcd.setCursor(12,0);
          if (ds2_crc_hiba) {lcd.print("CRC");} if (!ds2_on) {lcd.print("OFF");} 
          lcd.setCursor(4,1);
          if (ds3_crc_hiba) {lcd.print("CRC");} if (!ds3_on) {lcd.print("OFF");} 
          lcd.setCursor(12,1);
          if (ds4_crc_hiba) {lcd.print("CRC");} if (!ds4_on) {lcd.print("OFF");} 
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
        case 7: //SD működés, és légnyomásmérő működés visszajelzés
          lcd.setCursor(0,0);lcd.print("SD:              ");
          lcd.setCursor(0,1);lcd.print("Legny.mero:      ");
          lcd.setCursor(3,0);
          switch (sd_hiba) 
          {
            case 0:
              lcd.print("OK         ");break;
            case 1:
              lcd.print("Error      ");break;
            case 2:
              lcd.print("nincs adat ");break;
          }
         lcd.setCursor(12,1);
         switch (bme280_on) 
          {
            case 0:
              lcd.print("OFF   ");break;
            case 1:
              lcd.print("ON     ");break;
          }
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
        case 8: //az utolsó napi állomány írási időpontját írjuk ki. Ha hiba volt, akkor nem dátum, hanem error jelzés van a változóban
          lcd.setCursor(0,0);lcd.print(utolso_nap_iras);
          lcd.setCursor(0,1);lcd.print(utolso_ev_iras);
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
        case 9:
          lcd.setCursor(0,0);lcd.print("Ora beallitas:  ");
          lcd.setCursor(0,1);lcd.print("Ev:    20"+String(Clock.getYear())+"     ");
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
        case 10:
         lcd.setCursor(0,1);lcd.print("Ho:      "+String(Clock.getMonth(Century))+"     ");
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
        case 11:
          lcd.setCursor(0,1);lcd.print("Nap:     "+String(Clock.getDate())+"     ");
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
        case 12:
          lcd.setCursor(0,1);lcd.print("Hetnapja:");
          lcd.setCursor(9,1);
          switch (Clock.getDoW()) 
            {
              case 1:
                lcd.print("Hetfo");break;
              case 2:
                lcd.print("Kedd ");break;
              case 3:
                lcd.print("Szerd");break;
              case 4:
                lcd.print("Csut ");break;
              case 5:
                lcd.print("Pent ");break;
              case 6:
                lcd.print("Szomb");break;
              case 7:
                lcd.print("Vasar");break;
            }
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
        case 13:
          lcd.setCursor(0,1);lcd.print("Ora:     "+String(Clock.getHour(h12,PM))+"     ");
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
        case 14:
          lcd.setCursor(0,1);lcd.print("Perc:    "+String(Clock.getMinute())+"     ");
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
      }
    }
  } 
  //ha 5 másodpercre elengedi a nyomógombpt  setup folyamaton belül, akkor visszaállítjuk az eredeti állapotot
  if (digitalRead(10)==HIGH and millis()>ora_setup_ido+5000 and ora_setup) 
  {
    ora_setup=LOW;nyomva=LOW;
//    setup_num=0;
    if (lcd_vilagitas==LOW) {setup_num=0;} else {setup_num=1;} //ha nem világit a kijelző, akkor első megnyomásar be kell kapcsolni
                                                               //ha világít, akkor első lenyomásar már tartalmat kell váltani
    str_tmp="";  // be kell frissíteni a dátumot az lcd kijelzőn, mert lehet, hogy változott, és egyébként csak óránként frissítem
    if (Clock.getMonth(Century)<10) {str_tmp=str_tmp+"0"+String(Clock.getMonth(Century))+"/";} else {str_tmp=str_tmp+String(Clock.getMonth(Century))+"/";}
    if (Clock.getDate()<10) {str_tmp=str_tmp+"0"+String(Clock.getDate());} else {str_tmp=str_tmp+String(Clock.getDate());}
    lcd.setCursor(0,0);lcd.print(str_tmp);
    mert_ertek_kijelzes=HIGH; //mehet tovább a mérési eredmények kijlzése
  }
  //ha 60 másodperce elengedte a nyomógombpt akkor a háttérvilágítást is kikapcsoljuk
  if (digitalRead(10)==HIGH and millis()>ora_setup_ido+60000 and ora_setup==LOW) 
  {
    lcd_vilagitas=LOW;
    lcd.noBacklight();
  }
  //egy másodpercig nyomvatartotta, változtatjuk az adott értéket, elengedéskor az állapotot beállítjuk az órába
  if (digitalRead(10)==LOW and ora_setup==HIGH and nyomva==HIGH and millis()>nyomva_ido+1000) 
  {
     switch (setup_num) {
        case 9:
          ora_setup_ertek=Clock.getYear();
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,19,40);
          Clock.setYear(ora_setup_ujertek);
          break;
        case 10:
          ora_setup_ertek=Clock.getMonth(Century);
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,1,12);
          Clock.setMonth(ora_setup_ujertek);
          break;
        case 11:
          ora_setup_ertek=Clock.getDate();
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,1,31);
          Clock.setDate(ora_setup_ujertek);
          break;
        case 12:
          ora_setup_ertek=Clock.getDoW();
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,1,7);
          Clock.setDoW(ora_setup_ujertek);
          break;
        case 13:
          ora_setup_ertek=Clock.getHour(h12,PM);
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,0,23);
          Clock.setHour(ora_setup_ujertek);
          break;
        case 14:
          ora_setup_ertek=Clock.getMinute();
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,0,59);
          Clock.setMinute(ora_setup_ujertek);
          Clock.setSecond(0);
          break;
      }
      ora_setup_ido=millis();
  }
  /*********************************************************************************************************************
   * egy másodpercenként kiolvassuk az órát, frissítjük az ora, perc és masodperc változókat, kiírjuk az lcd-re        *
   * az időt, a dátumot csak óránként frissítjük. Ugyanekkor megmérjük a fényerőt és ehhez igazítjuk a kijelzők fényrejét *
   *********************************************************************************************************************/
    //kétmásodpercenként más eszköz mérési eredményét jelenítjük meg az LCD kijelzőn, hogy ott is láthatóak legyenek az adatok
    if (millis()>lcd_kijelzo_ido+2000 and mert_ertek_kijelzes==HIGH)  
    {
      lcd.setCursor(5,1);
      switch (lcd_eszkoz_num) {
        case 0:   
          lcd.print(" Kulso:     ");
          lcd.setCursor(12,1);lcd.print(kulso_homerseklet);
          lcd_eszkoz_num++;
          break;
        case 1:     
          lcd.print("  Para:   % ");
          lcd.setCursor(12,1);lcd.print((byte)paratartalom);
          lcd_eszkoz_num++;
          break;
        case 2:   
          lcd.print(" Legny:     ");
          lcd.setCursor(12,1);lcd.print((int)legnyomas);
          lcd_eszkoz_num++;
          break;
        case 3:  
          lcd.print(" Pince:      ");
          lcd.setCursor(12,1);lcd.print(pince_homerseklet);
          lcd_eszkoz_num++;
          break;
        case 4:   
          lcd.print("Akna A:      ");
          lcd.setCursor(12,1);lcd.print(akna_homerseklet_also);
          lcd_eszkoz_num++;
          break;
        case 5:   
          lcd.print("Akna F:      ");
          lcd.setCursor(12,1);lcd.print(akna_homerseklet_felso);
          lcd_eszkoz_num++;
          break;
        case 6:   
          lcd.print("Kishaz:      ");
          lcd.setCursor(12,1);lcd.print(kishaz_homerseklet);
          lcd_eszkoz_num++;
          break;
        case 7:   
          lcd.print("  Feny:      ");
          lcd.setCursor(12,1);lcd.print(analogRead(A6));
          lcd_eszkoz_num++;
          break;
      }
      if (lcd_eszkoz_num>7) { lcd_eszkoz_num=0;}
      lcd_kijelzo_ido=millis();
    }

 
  /*********************************************************************************************************
   * Ez a programrész 15 másodpercenként végez el egy mérést mindíg más senzoron. a teljes mérési ciklus    *
   * minden eszköz végig mérésével 5x15=75 sec, ennyi időközönként kérdezünk le egy-egy szenzort            *
   *********************************************************************************************************/
  if (millis()>meres_ido+1500)  //15 másodpercenként mindig más eszközből olvassuk ki az aktuális meresi eredményt
  {
    switch (eszkoz_num) {
      case 0:   //külső hőmérséklet, páratartalom és légnyomás mérés és értékek kijelzés előkészítése
        bme280_lekerdez();
        if (bme280_on)
        {
          //minden tárolt értéknek a 100 szorosát használjuk, mert így majd a végén 100-al osztva újra tizedes értékben
          //kapjuk meg az eredményt (long változót tárolunk, ami nem tud tizedes értéket tárolni, viszont a hőmérséklet
          //tezedes jegyet is tartalmaz. AZ osztást az SD kártyára tároláskor végezzük egységesen minden adatra, azért a
          //páratartalom és a légnyomás esetén is szorzunk 100-al, ott nem kellene egyébként, mert egész értékek.

          if (kulso_homerseklet>-50 and kulso_homerseklet<50) {  //időnként valami fals érték jöhetett be méréskor, mert a napi átalgokban 
                                                                 //vad értékeket tárolt az SD kártya. Ezért a vizsgálat, ha baromság jön be azt 
                                                                 //inkább kihagyom
            multimemo(v_kulso_o,kulso_homerseklet*100);
            multimemo(v_kulso_o_min,kulso_homerseklet*100);
            multimemo(v_kulso_o_max,kulso_homerseklet*100);
            multimemo(0,kulso_homerseklet*100);
            multimemo(1,kulso_homerseklet*100);
            multimemo(2,kulso_homerseklet*100);
          }

          multimemo(v_para_o,paratartalom*100);
          multimemo(v_para_o_min,paratartalom*100);
          multimemo(v_para_o_max,paratartalom*100);
          multimemo(3,paratartalom*100);
          multimemo(4,paratartalom*100);
          multimemo(5,paratartalom*100);

          multimemo(v_legny_o,legnyomas*100);
          multimemo(v_legny_o_min,legnyomas*100);
          multimemo(v_legny_o_max,legnyomas*100);
          multimemo(6,legnyomas*100);
          multimemo(7,legnyomas*100);
          multimemo(8,legnyomas*100);
          szamjegybontas(kulso_homerseklet,0,0); //kulső hőmérséklet karakterképe bitsor0 tömbbe
          szamjegybontas(paratartalom,1,1); //páratartalom karakterképe bitsor1 tömbbe
          szamjegybontas(legnyomas,2,1); //legnyomás karakterképe bitsor2 tömbbe
          eszkoz_num++;
        }
        break;
      case 1:   //pince hőmérséklet
        if (ds1_on and !ds1_crc_hiba)
        {
          pince_homerseklet=onewire_meres(1);
          multimemo(v_pince_o,pince_homerseklet*100);
          multimemo(9,pince_homerseklet*100);
        }
        eszkoz_num++;
        szamjegybontas(pince_homerseklet,3,0); //pince hőmérséklet karakterképe bitsor3 tömbbe
      case 2:   //akna hőmérséklet_felso
        if (ds2_on and !ds2_crc_hiba)
        {
          akna_homerseklet_felso=onewire_meres(2);
          multimemo(v_aknaf_o,akna_homerseklet_felso*100);
          multimemo(11,akna_homerseklet_felso*100);
        }
        szamjegybontas(akna_homerseklet_felso,5,0); //akna hőmérséklet karakterképe bitsor5 tömbbe
        eszkoz_num++;
        break;
      case 3:   //akna hőmérséklet_alsó
        if (ds3_on and !ds3_crc_hiba)
        {
          akna_homerseklet_also=onewire_meres(3);
          multimemo(v_aknaa_o,akna_homerseklet_also*100);
          multimemo(10,akna_homerseklet_also*100);
        }
        szamjegybontas(akna_homerseklet_also,4,0); //akna hőmérséklet karakterképe bitsor4 tömbbe
        eszkoz_num++;
        break;
      case 4:   //kisház hőmérséklet
        if (ds4_on and !ds4_crc_hiba)
        {
          kishaz_homerseklet=onewire_meres(4);
          multimemo(v_kishaz_o,kishaz_homerseklet*100);
          multimemo(v_kishaz_o_min,kishaz_homerseklet*100);
          multimemo(v_kishaz_o_max,kishaz_homerseklet*100);
          multimemo(12,kishaz_homerseklet*100);
          multimemo(13,kishaz_homerseklet*100);
          multimemo(14,kishaz_homerseklet*100);
        }
        szamjegybontas(kishaz_homerseklet,6,0); //kisház hőmérséklet karakterképe bitsor6 tömbbe
        eszkoz_num++;
        break;
   }
    if (eszkoz_num>4) { eszkoz_num=0;}
    meres_ido=millis();
  }
  /**********************************************************************************************************************
   * Ez a programrész 2 másodpercenként már értéket küld az alső hétszegmens kijelző sorra, é az alsó matrix kijelzőre  *
   **********************************************************************************************************************/
  if (millis()>kijelzovaltas_ido+2000) {  //2 másodpercenként váltjuk a kijelző also sorában kijelzett értékeket
    //adatok kijelzőre írása
    digitalWrite(2, LOW); //shift regiszter kimenetek lezárása (latchPin=0)
    shiftOut(4, 3, MSBFIRST, bitsor0[0]);            //külső hőmérséklet szazas
    shiftOut(4, 3, MSBFIRST, bitsor0[1]);            //külső hőmérséklet tizes
    shiftOut(4, 3, MSBFIRST, bitsor0[2]);            //külső hőmérséklet egyes
    shiftOut(4, 3, MSBFIRST, bitsor0[3]);            //külső hőmérséklet tizedes
    switch (kijelzes_num) {
      case 1:   //páratartalom
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00000000);
        lc.setRow(0,3,B00000000);
        lc.setRow(0,4,B00000000);
        lc.setRow(0,5,B00000000);
        lc.setRow(0,6,B00000000);
        lc.setRow(0,7,B00000000);
        lc.setRow(1,0,B00000000);
        lc.setRow(1,1,B00110000);
        lc.setRow(1,2,B00110010);
        lc.setRow(1,3,B00000100);
        lc.setRow(1,4,B00001000);
        lc.setRow(1,5,B00010000);
        lc.setRow(1,6,B00100110);
        lc.setRow(1,7,B00000110);
        shiftOut(4, 3, MSBFIRST, bitsor1[0]);            //páratartalom ezres (mindíg üres)
        shiftOut(4, 3, MSBFIRST, bitsor1[1]);            //páratartalom szazas (mindíg üres)
        shiftOut(4, 3, MSBFIRST, bitsor1[2]);            //páratartalom tizes
        shiftOut(4, 3, MSBFIRST, bitsor1[3]);            //páratartalom egyes
        kijelzes_num++;
        break;
      case 2:   //légnyomás
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00000000);
        lc.setRow(0,3,B11001011);
        lc.setRow(0,4,B00101100);
        lc.setRow(0,5,B00101000);
        lc.setRow(0,6,B00101000);
        lc.setRow(0,7,B11001000);
        lc.setRow(1,0,B00000000);
        lc.setRow(1,1,B00000001);
        lc.setRow(1,2,B00000001);
        lc.setRow(1,3,B01101001);
        lc.setRow(1,4,B01010101);
        lc.setRow(1,5,B01010101);
        lc.setRow(1,6,B01010101);
        lc.setRow(1,7,B01010101);
        shiftOut(4, 3, MSBFIRST, bitsor2[0]);            //légnyomás ezres
        shiftOut(4, 3, MSBFIRST, bitsor2[1]);            //légnyomás szazas
        shiftOut(4, 3, MSBFIRST, bitsor2[2]);            //légnyomás tizes
        shiftOut(4, 3, MSBFIRST, bitsor2[3]);            //légnyomás egyes
        kijelzes_num++;
        break;
      case 3:   //pince hőmérséklet
        //P betű a 0-ás kijelzőre
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00011100);
        lc.setRow(0,3,B00010010);
        lc.setRow(0,4,B00010010);
        lc.setRow(0,5,B00011100);
        lc.setRow(0,6,B00010000);
        lc.setRow(0,7,B00010000);
        lc.setRow(1,0,B00000000);
        //°C felirat az 1-es kijelzőre
        lc.setRow(1,1,B01000110);
        lc.setRow(1,2,B10101001);
        lc.setRow(1,3,B10101000);
        lc.setRow(1,4,B01001000);
        lc.setRow(1,5,B00001000);
        lc.setRow(1,6,B00001001);
        lc.setRow(1,7,B00000110);
        shiftOut(4, 3, MSBFIRST, bitsor3[0]);            //pince hőmérséklet szazas
        shiftOut(4, 3, MSBFIRST, bitsor3[1]);            //pince hőmérséklet tizes
        shiftOut(4, 3, MSBFIRST, bitsor3[2]);            //pince hőmérséklet egyes
        shiftOut(4, 3, MSBFIRST, bitsor3[3]);            //pince hőmérséklet tizedes
        kijelzes_num++;
        break;
      case 4:   //akna hőmérséklet also
        //Akna also felirat 0-as kijzőre
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00110000);
        lc.setRow(0,3,B01001000);
        lc.setRow(0,4,B01001000);
        lc.setRow(0,5,B01111000);
        lc.setRow(0,6,B01001011);
        lc.setRow(0,7,B01001011);
        shiftOut(4, 3, MSBFIRST, bitsor4[0]);            //akna hőmérséklet szazas
        shiftOut(4, 3, MSBFIRST, bitsor4[1]);            //akna hőmérséklet tizes
        shiftOut(4, 3, MSBFIRST, bitsor4[2]);            //akna hőmérséklet egyes
        shiftOut(4, 3, MSBFIRST, bitsor4[3]);            //akna hőmérséklet tizedes
        kijelzes_num++;
        break;
      case 5:   //akna hőmérséklet felso
        //Akna felső felirat 0-as kijzőre
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00110011);
        lc.setRow(0,3,B01001011);
        lc.setRow(0,4,B01001000);
        lc.setRow(0,5,B01111000);
        lc.setRow(0,6,B01001000);
        lc.setRow(0,7,B01001000);
        shiftOut(4, 3, MSBFIRST, bitsor5[0]);            //akna hőmérséklet szazas
        shiftOut(4, 3, MSBFIRST, bitsor5[1]);            //akna hőmérséklet tizes
        shiftOut(4, 3, MSBFIRST, bitsor5[2]);            //akna hőmérséklet egyes
        shiftOut(4, 3, MSBFIRST, bitsor5[3]);            //akna hőmérséklet tizedes
        kijelzes_num++;
        break;
      case 6:   //kisház hőmérséklet
        //H betű a 0-ás kijelzőre
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00010010);
        lc.setRow(0,3,B00010010);
        lc.setRow(0,4,B00011110);
        lc.setRow(0,5,B00011110);
        lc.setRow(0,6,B00010010);
        lc.setRow(0,7,B00010010);
        shiftOut(4, 3, MSBFIRST, bitsor6[0]);            //kisház hőmérséklet szazas
        shiftOut(4, 3, MSBFIRST, bitsor6[1]);            //kisház hőmérséklet tizes
        shiftOut(4, 3, MSBFIRST, bitsor6[2]);            //kisház hőmérséklet egyes
        shiftOut(4, 3, MSBFIRST, bitsor6[3]);            //kisház hőmérséklet tizedes
        kijelzes_num++;
        break;
    }
    digitalWrite(2, HIGH);  //beléptetett érték kiengedése a shiftregiszter kimenetére (latchPin=1)
    if (kijelzes_num>6) { kijelzes_num=1;}
    kijelzovaltas_ido=millis();
  } 

  
  /*****************************************************************************************************************
   *  Óránként egy alkalommal átküldjük a slave-nak a mért eredményeket (min és max értékkel)
   *  Ha sikerült az átküldés után feltételezzük, hogy sikerült az írás az SD kártyára, és nullázzuk
   *  az átlagértékek segéd változói (összeg és mérésszám). Ha nem volt SD írási hiba, akkor megjegyezzük
   *  az utolsó sd írás időpontját, ha volt hiba akkor a hiba tényét (utolso_nap_iras változóba).
   *****************************************************************************************************************/
  //óránként egyszer átküldjük az órás átlag adatokat a slavenak. Küldés után utan töröljük a változókat, hogy ujra kezdődhessen az átlagolás
  if (perc==0 and masodperc<10 and tarolas)  
  //if (masodperc<10 and tarolas)  
  {
    adatkuldes(0);
    tarolas=false;
    //töröljuk az orankénti átlagoláshoz használt FRAM cellákat
    multimemo(v_kulso_o,AVG);
    multimemo(v_kulso_o_min,MIN);
    multimemo(v_kulso_o_max,MAX);
    multimemo(v_para_o,AVG);
    multimemo(v_para_o_min,MIN);
    multimemo(v_para_o_max,MAX);
    multimemo(v_legny_o,AVG);
    multimemo(v_legny_o_min,MIN);
    multimemo(v_legny_o_max,MAX);
    multimemo(v_pince_o,AVG);
    multimemo(v_aknaa_o,AVG);
    multimemo(v_aknaf_o,AVG);
    multimemo(v_kishaz_o,AVG);
    multimemo(v_kishaz_o_min,MIN);
    multimemo(v_kishaz_o_max,MAX);
    if (sd_hiba==0)
    {
      //összeállítjuk az utolsó nap file dátumának szövegét az LCD-n történő kiíráshoz
      if (Clock.getHour(h12, PM)<10) {str_tmp="0"+String(Clock.getHour(h12, PM))+":";} else {str_tmp=String(Clock.getHour(h12, PM))+":";}
      if (Clock.getMinute()<10) {str_tmp=str_tmp+"0"+String(Clock.getMinute())+":";} else {str_tmp=str_tmp+String(Clock.getMinute());}
      //if (Clock.getSecond()<10) {str_tmp=str_tmp+"0"+String(Clock.getSecond());} else {str_tmp=str_tmp+String(Clock.getSecond());}
      utolso_nap_iras="  Nap file:"+str_tmp;
    }
    else
    {
      utolso_nap_iras="Nap file:SD error";
    }
  }

 
  /*****************************************************************************************************************
   *  Minden nap 23.50-kor átküldjük a slave-nak a mért eredményeket (min és max értékkel)
   *  Ha sikerült az átküldés után feltételezzük, hogy sikerült az írás az SD kártyára, és nullázzuk
   *  az átlagértékek segéd változói (összeg és mérésszám). Ha nem volt SD írási hiba, akkor megjegyezzük
   *  az utolsó sd írás időpontját, ha volt hiba akkor a hiba tényét (utolso_ev_iras változóba).
   *****************************************************************************************************************/
  if ((ora==23 and perc==59) and masodperc<10 and tarolasnap)  
  //if ((perc==35) and masodperc<10 and tarolasnap)  
  {
    adatkuldes(1);
    long szam=multimemo(0);multimemo(30,szam);
    szam=multimemo(1);multimemo(31,szam);
    szam=multimemo(2);multimemo(32,szam);
    tarolasnap=false;
    //töröljuk az naponkénti átlagoláshoz használt FRAM cellákat
    multimemo(0,AVG);
    multimemo(1,MIN);
    multimemo(2,MAX);
    multimemo(3,AVG);
    multimemo(4,MIN);
    multimemo(5,MAX);
    multimemo(6,AVG);
    multimemo(7,MIN);
    multimemo(8,MAX);
    multimemo(9,AVG);
    multimemo(10,AVG);
    multimemo(11,AVG);
    multimemo(12,AVG);
    multimemo(13,MIN);
    multimemo(14,MAX);
    if (sd_hiba==0)
    {
      //összeállítjuk az utolsó év file dátumának szövegét az LCD-n történő kiíráshoz
      if (Clock.getHour(h12, PM)<10) {str_tmp="0"+String(Clock.getHour(h12, PM))+":";} else {str_tmp=String(Clock.getHour(h12, PM))+":";}
      if (Clock.getMinute()<10) {str_tmp=str_tmp+"0"+String(Clock.getMinute())+":";} else {str_tmp=str_tmp+String(Clock.getMinute());}
      //if (Clock.getSecond()<10) {str_tmp=str_tmp+"0"+String(Clock.getSecond());} else {str_tmp=str_tmp+String(Clock.getSecond());}
      utolso_ev_iras="  Ev file: "+str_tmp;
    }
    else
    {
      utolso_ev_iras="Ev file:SD error";
    }
  } 

}


/***************************************************************************************
 * Csak 32 byte-ot lehet egyszerre egy menetben átvinni, a következő beyte-ok sérülnek *
 * nem tudom miért. Ezért két menetre bontottam az órás illetve a napi átlag küldésétt *
 * status a legelso byte:     1-datum idő átvitel 7 byte
 *                            2-az órás adatok 1 mért adatok 30 byte
 *                            3-az órás adatok 2 mért adatok 30 byte
 *                            4-a napi mért adatok 1 30 byte
 *                            5-a napi mért adatok 2 30 byte
 * elősször mindig a dátumot és az időt, és utánna az órás vagy napi mért adaokat küldöm át                           
 ***************************************************************************************/
void adatkuldes(bool allomany)
{
    
//    Serial.println("kuldes");
  Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
  Wire.write(1);
  Wire.write(ev);
  Wire.write(ho);
  Wire.write(nap);
  Wire.write(ora);
  Wire.write(perc);
  Wire.write(masodperc);
  Wire.endTransmission();     // vége az átvitelnek
  if (allomany==0)
  {
    kuldendo1=multimemo(v_kulso_o);
    kuldendo2=multimemo(v_kulso_o_min);
    kuldendo3=multimemo(v_kulso_o_max);
    kuldendo4=multimemo(v_para_o);
    kuldendo5=multimemo(v_para_o_min);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(2);
    kuld_4byte(kuldendo1);  //100-al már szorozunk a tároláskor, és most az átküldéskor is 100-al kéne, így most nem szorzunk, de nem is osztunk
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4); 
    kuld_4byte(kuldendo5); 
    Wire.endTransmission();     // vége az átvitelnek
    /**********************************************************/
    kuldendo1=multimemo(v_para_o_max);
    kuldendo2=multimemo(v_legny_o);
    kuldendo3=multimemo(v_legny_o_min);
    kuldendo4=multimemo(v_legny_o_max);
    kuldendo5=multimemo(v_kishaz_o);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(3);
    kuld_4byte(kuldendo1);
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4);
    kuld_4byte(kuldendo5);
    Wire.endTransmission();     // vége az átvitelnek
    /**********************************************************/
    kuldendo1=multimemo(v_kishaz_o_min);
    kuldendo2=multimemo(v_kishaz_o_max);
    kuldendo3=multimemo(v_aknaa_o);
    kuldendo4=multimemo(v_aknaf_o);
    kuldendo5=multimemo(v_pince_o);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(4);
    kuld_4byte(kuldendo1);
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4);
    kuld_4byte(kuldendo5);
  }
  else
  {
    kuldendo1=multimemo(0);
    kuldendo2=multimemo(1);
    kuldendo3=multimemo(2);
    kuldendo4=multimemo(3);
    kuldendo5=multimemo(4);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(5);
    kuld_4byte(kuldendo1);  //100-al már szorozunk a tároláskor, és most az átküldéskor is 100-al kéne, így most nem szorzunk, de nem is osztunk
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4); 
    kuld_4byte(kuldendo5); 
    Wire.endTransmission();     // vége az átvitelnek
    /**********************************************************/
    kuldendo1=multimemo(5);
    kuldendo2=multimemo(6);
    kuldendo3=multimemo(7);
    kuldendo4=multimemo(8);
    kuldendo5=multimemo(12);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(6);
    kuld_4byte(kuldendo1);
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4);
    kuld_4byte(kuldendo5);
    Wire.endTransmission();     // vége az átvitelnek
    /**********************************************************/
    kuldendo1=multimemo(13);
    kuldendo2=multimemo(14);
    kuldendo3=multimemo(10);
    kuldendo4=multimemo(11);
    kuldendo5=multimemo(9);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(7);
    kuld_4byte(kuldendo1);
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4);
    kuld_4byte(kuldendo5);
  }
  Wire.endTransmission();     // vége az átvitelnek
  delay(50); //várunk 50msec-et, hogy a slave befejezhesse az SD írást, és kiderüljön sikerült-e
  Wire.requestFrom(8,1);      // a master kér 1 byte-ot a slave-től
  sd_hiba= Wire.read();       //beolvassuk a slave által küldött byte-ot    
}

void kuld_4byte(long kuldendo)
{
    byte out1=(kuldendo & 0xFF);
    byte out2=((kuldendo >> 8) & 0xFF);
    byte out3=((kuldendo >> 16) & 0xFF);
    byte out4=((kuldendo >> 24) & 0xFF);
    Wire.write(out1);               
    Wire.write(out2);
    Wire.write(out3);
    Wire.write(out4);
}


/****************************************************************************************************
 * Ha óra beállításkor nyomva tartja a nyomógombot, akkor folyamatosan számoltatja felfelé 
 * az éppen beállított adat értékét. Ha elérte a maximumot, akkor nullázza az értéket.
 ****************************************************************************************************/
byte ertekporgetes(byte o_ert, byte o_min, byte o_max)
{
  do
  {
    wdt_reset(); //alaphelyzetbe állítjuk a a watcdog timer-t. Erre itt is szükség van, különben az óra beállítás
                 //alatt is resetet generál a watchdog, mert a fő ciklus nem fut miközben ebben a függvényvben tartozkodik
                 //a program
    o_ert=o_ert+1;setup_num_novel=LOW;
    if (o_ert>o_max) {o_ert=o_min;}
    lcd.setCursor(9,1); 
    if (setup_num==8)
    {
      switch (o_ert) 
      {
        case 1:
          lcd.print("Hetfo");break;
        case 2:
          lcd.print("Kedd ");break;
        case 3:
          lcd.print("Szerd");break;
        case 4:
          lcd.print("Csut ");break;
        case 5:
          lcd.print("Pent ");break;
        case 6:
          lcd.print("Szomb");break;
        case 7:
          lcd.print("Vasar");break;
      }
    } 
    else
    {
      lcd.print(String(o_ert)+"  ");
    }
    delay(700);
  } while (digitalRead(10)==LOW);
  return o_ert;
} 


/****************************************************************************************************
 * Ez a funkció 4 byte-ból csinál egy long változót és visszadja az eredményt
 ****************************************************************************************************/
long byteToLong(long inp1, long inp2, long inp3, long inp4)
{
  //4 byte long változóvá alakítása
  return ((inp1 << 0) & 0xFF) + ((inp2 << 8) & 0xFFFF) + ((inp3 << 16) & 0xFFFFFF) + ((inp4 << 24) & 0xFFFFFFFF);
}

/****************************************************************************************************
 * inicializálja és lekérdezi a BME280 senzort. Ha a senzor inicializálása nem sikerül
 * akkor a függvény újbóli meghívásakor ismét megkisérli az inicializálást, Ha sikerül, akkor 
 * rögtön mér is egyet.
 * Ha már inincializálva van, akkor csak mér. Ha közben megszakad a BME280-al a kapcsolat
 * akkor a hőmérséklet lekérdezés -145.75 fokod ad vissza tapasztalatom szerint, ezért ekkor
 * a mérési eredméynek hamisak, és legközelebb újra megpróbáljuk inicializálni
 ****************************************************************************************************/
void bme280_lekerdez()
{
  if (!bme280_on)
  {
    if (bme.begin(0x76, &Wire)) 
    {         
      bme280_on=HIGH;  //bme280 inicializálása sikerült
      //rögtön mérünk is egyet
      kulso_homerseklet=bme.readTemperature();
      paratartalom=bme.readHumidity();
      legnyomas=bme.readPressure()/100; 
    } 
    else
    {
      kulso_homerseklet=99.9;paratartalom=99;legnyomas=0; 
    }
  }
  else
  {
    kulso_homerseklet=bme.readTemperature();
    paratartalom=bme.readHumidity();
    legnyomas=bme.readPressure()/100; 
    if (kulso_homerseklet<-100) 
    {
      bme280_on=LOW;  //ha nincs bme280 csatlakoztatva, akkor -145 fokot ad vissza, legközelebb megpróbáljuk ujra inincializálni
      kulso_homerseklet=99.9;paratartalom=99;legnyomas=0;
    }
  }
}


/**************************************************************************************************************
 * Dallas onewire hőmérők felderítése és mérése. A legeslegelső függvényhíváskor felderítjük az egyes 
 * bemenetekre kapcsolt dallas chip-ek címeit, és letároljuk egy tömbbe. Ha nem sikerül a címfelderítés
 * akkor a kövtekező függvényhívások során újra és újra próbálkozunk. Így az adatvonalak vezetékeit
 * akár menetközben ki lehet húzni, a csatlakoztatást követő  ütemezett méréskor újra felderítjük a címet. Így pl
 * lehet chip-et cserélni működés közben. 
 * HA a címfelderítés sikerült, akkor ténylegesen mérünk is egyet. Minden függvényhíváskor csak egy eszközt 
 * kérdezünk le, és ennek kiválasztásához bemenő paraméter a ds_index változó, ami négy értéket vehet fel.
 * index   Chip    mérési helyszín
 * 1       DS1     pince hőmérő 
 * 2       DS2     akna felső hőmérő
 * 3       DS3     akna alsó hőmérő
 * 4       DS4     kisház hőmérő
 **************************************************************************************************************/
float onewire_meres(byte ds_index)
{
  // DS1 felderítse és címének tárolása, ha még nem történt meg  
  if(!ds1_on) 
  {
    dallas_chip_num=0;  //aktuális chip sorszáma
    ds1_on=LOW;
    while(ds1.search(dallas_addr)) //kisház hőmérő
    {
      //elmásoljuk a kiderített chip ROM címet
      for (byte j=0;j<8;j++) {dallas1_addr_t[dallas_chip_num][j]=dallas_addr[j];} 
      dallas_chip_num++;
      ds1_on=HIGH; //megtaláltuk az eszközt, lehet mérni, amig nincs meg, próbálkozunk a kereséssel
    }  
  }
  // DS2 felderítse és címének tárolása, ha még nem történt meg  
  if(!ds2_on) 
  {
    dallas_chip_num=0;  //aktuális chip sorszáma
    ds2_on=LOW;
    while(ds2.search(dallas_addr)) //kisház hőmérő
    {
      //elmásoljuk a kiderített chip ROM címet
      for (byte j=0;j<8;j++) {dallas2_addr_t[dallas_chip_num][j]=dallas_addr[j];} 
      dallas_chip_num++;
      ds2_on=HIGH; //megtaláltuk az eszközt, lehet mérni, amig nincs meg, próbálkozunk a kereséssel
    }  
  }
  // DS3 felderítse és címének tárolása, ha még nem történt meg 
  if(!ds3_on) 
  {
    dallas_chip_num=0;  //aktuális chip sorszáma
    ds3_on=LOW;
    while(ds3.search(dallas_addr)) //kisház hőmérő
    {
      //elmásoljuk a kiderített chip ROM címet
      for (byte j=0;j<8;j++) {dallas3_addr_t[dallas_chip_num][j]=dallas_addr[j];} 
      dallas_chip_num++;
      ds3_on=HIGH; //megtaláltuk az eszközt, lehet mérni, amig nincs meg, próbálkozunk a kereséssel
    }  
  }
  // DS4 felderítse és címének tárolása, ha még nem történt meg 
  if(!ds4_on) 
  {
    dallas_chip_num=0;  //aktuális chip sorszáma
    ds4_on=LOW;
    while(ds4.search(dallas_addr)) //kisház hőmérő
    {
      //elmásoljuk a kiderített chip ROM címet
      for (byte j=0;j<8;j++) {dallas4_addr_t[dallas_chip_num][j]=dallas_addr[j];} 
      dallas_chip_num++;
      ds4_on=HIGH; //megtaláltuk az eszközt, lehet mérni, amig nincs meg, próbálkozunk a kereséssel
    }  
  }
  //***************************************************************************************************************
  switch (ds_index)
  {
    case 1:
      if (ds1_on) //DS1 csatlakoztatva van
      {
        //Serial.println("ds1 meres indul");
        for (byte j=0;j<8;j++) {dallas_addr[j]=dallas1_addr_t[0][j];} //Másoljuk az aktuális ROM címet az dallas_addr tömbbe
        ds1.reset();ds1.select(dallas_addr);ds1.write(0x44, 1);delay(1000); //eszöz megcímzése és mérés indítása
        ds1.reset();ds1.select(dallas_addr);ds1.write(0xBE);  // Chip memóriájánbak olvasása
        for ( byte l = 0; l < 9; l++) {dallas_data[l] = ds1.read();}    // 9 bytot olvasunk ki
          if ( OneWire::crc8( dallas_data, 8) != dallas_data[8]) {ds1_crc_hiba=HIGH;return 88.8;}
          else {ds1_crc_hiba=LOW;return (float) (((dallas_data[1] << 8) | dallas_data[0])/16.0);}  //mert ertek visszaadása CRC rendben
       }
        else {return 99.99;}
       break;
      //***************************************************************************************************************
    case 2:
      if (ds2_on)
      {
        for (byte j=0;j<8;j++) {dallas_addr[j]=dallas2_addr_t[0][j];} //Másoljuk az aktuális ROM címet az dallas_addr tömbbe
        ds2.reset();ds2.select(dallas_addr);ds2.write(0x44, 1);delay(800); 
        ds2.reset();ds2.select(dallas_addr);ds2.write(0xBE); 
        for ( byte l = 0; l < 9; l++) {dallas_data[l] = ds2.read();}   
        if ( OneWire::crc8( dallas_data, 8) != dallas_data[8]) {ds2_crc_hiba=HIGH;return 88.8;}
        else {ds2_crc_hiba=LOW;return (float) (((dallas_data[1] << 8) | dallas_data[0])/16.0);}
      }
      else {return 99.9;}
      break;
      //***************************************************************************************************************
    case 3:
      if (ds3_on)
      {
        for (byte j=0;j<8;j++) {dallas_addr[j]=dallas3_addr_t[0][j];} //Másoljuk az aktuális ROM címet az dallas_addr tömbbe
        ds3.reset();ds3.select(dallas_addr);ds3.write(0x44, 1);delay(800);
        ds3.reset();ds3.select(dallas_addr);ds3.write(0xBE);
        for ( byte l = 0; l < 9; l++) {dallas_data[l] = ds3.read();} 
        if ( OneWire::crc8( dallas_data, 8) != dallas_data[8]) {ds3_crc_hiba=HIGH;return 88.8;}
        else {ds3_crc_hiba=LOW;return (float) (((dallas_data[1] << 8) | dallas_data[0])/16.0);}
      }
      else {return 99.9;}
      break;
    case 4:
      if (ds4_on)
      {
        for (byte j=0;j<8;j++) {dallas_addr[j]=dallas4_addr_t[0][j];} //Másoljuk az aktuális ROM címet az dallas_addr tömbbe
        ds4.reset();ds4.select(dallas_addr);ds4.write(0x44, 1);delay(800);
        ds4.reset();ds4.select(dallas_addr);ds4.write(0xBE);
        for ( byte l = 0; l < 9; l++) {dallas_data[l] = ds4.read();} 
        if ( OneWire::crc8( dallas_data, 8) != dallas_data[8]) {ds4_crc_hiba=HIGH;return 88.8;}
        else {ds4_crc_hiba=LOW;return (float) (((dallas_data[1] << 8) | dallas_data[0])/16.0);}
      }
      else {return 99.9;}
      break;
  }
}


/****************************************************************************************************
 * Megméri az A6 bemenetre kötött fototrnzisztor és ellenállásosztóban az ellenállás 
 * feszültségét. Ellenállás értéke 1Kohm. A fototranzisztor kb 5000Lux, nál teljesen kinyit
 * ekkor az ellenálláson közel 5V feszültség mérhető. Sötétben a feszültség 0V
 ****************************************************************************************************/
void fenyero_beallitas(){
    int ledmatfeny=0;
    int hszegfeny=0;
    for (byte j=9;j>0;j--) {mert_fenyero[j]=mert_fenyero[j-1];}
    int fenyero=analogRead(A6);
    mert_fenyero[0]=fenyero;
    fenyertek=(mert_fenyero[0]+mert_fenyero[1]+mert_fenyero[2]+mert_fenyero[3]+mert_fenyero[4]+mert_fenyero[5]+mert_fenyero[6]+mert_fenyero[7]+mert_fenyero[8]+mert_fenyero[9])/10;
    if (fenyertek<=20) {hszegfeny=245;ledmatfeny=0;}
    if (fenyertek<=40 & fenyertek>20) {hszegfeny=245;ledmatfeny=1;}  
    if (fenyertek<=70 & fenyertek>40) {hszegfeny=220;ledmatfeny=2;}  
    if (fenyertek<=110 & fenyertek>70) {hszegfeny=198;ledmatfeny=3;}  
    if (fenyertek<=150 & fenyertek>110) {hszegfeny=175;ledmatfeny=4;}  
    if (fenyertek<=180 & fenyertek>150) {hszegfeny=158;ledmatfeny=5;}  
    if (fenyertek<=230 & fenyertek>180) {hszegfeny=140;ledmatfeny=6;}  
    if (fenyertek<=285 & fenyertek>230) {hszegfeny=123;ledmatfeny=7;}  
    if (fenyertek<=320 & fenyertek>285) {hszegfeny=105;ledmatfeny=8;}  
    if (fenyertek<=380 & fenyertek>320) {hszegfeny=88;ledmatfeny=9;}  
    if (fenyertek<=440 & fenyertek>380) {hszegfeny=70;ledmatfeny=10;}  
    if (fenyertek<=500 & fenyertek>440) {hszegfeny=53;ledmatfeny=11;}  
    if (fenyertek<=560 & fenyertek>500) {hszegfeny=35;ledmatfeny=12;}  
    if (fenyertek<=630 & fenyertek>560) {hszegfeny=24;ledmatfeny=13;}  
    if (fenyertek<=700 & fenyertek>630) {hszegfeny=12;ledmatfeny=14;}  
    if (fenyertek>700) {hszegfeny=0;ledmatfeny=15;} 
    analogWrite(5,hszegfeny);
    // fényerő beállítás 0 minimum, 15 maximum 
    lc.setIntensity(0,ledmatfeny);lc.setIntensity(1,ledmatfeny);
    lc.setIntensity(2,ledmatfeny);lc.setIntensity(3,ledmatfeny);
} 


/****************************************************************************************************
 * A függvénynek átadott számértéket annak típusától függően feldolgozza és bitsorozattá
 * alakítja a 74HC595 IC-be történő beléptetéshez. MInden szenzor által mért adatnak külön
 * tömbbe kerülnek az adatai. A légnyomás és a páratartalom csak egész érték lehet, a többi
 * tizedes, tehát a tizedespontot is ki be kell kapcsolni. A vezető nullákat kioltja és
 * kirakja a minusz jelet is
 ****************************************************************************************************/
void szamjegybontas(float szamertek,int ertekindex, int egeszertek){
/*ez a függvány a mérési eredményt négy számjegyre bontja a 7 szegmenses LED kijelzőkbe léptetéses formában
  átvett változók jelentése:
    szamertek : az átalakításra váró mért érték
    ertekindex : az er edmény tárolására szolgáló tömb indexe
    egeszertek : ha értéke 1, akkor lénynomás vagy páratartalom értékét kell átalakítani, ami csak pozitív szám lehet, és nem kell tizedesjegy kijelzés
  Az indexértékkel kiválasztott nevű tömböt tölt a számjegyek bitképével. A tömbök nevei: bitsor0=külső hőmérséklet.....
  A tömbök indexértékeinek jelentése:
    bitsorX[0] -> balrol az első számjegy
    bitsorX[1] -> balrol az második számjegy
    bitsorX[2] -> balrol az harmadik számjegy
    bitsorX[3] -> balrol az negyedik számjegy
  amennyiben a kijelzésre kerülő számjegy nagyobb mint 100 (ez a légnyomás érék), előjel kijelzés nem lehetséges és nincs tizedes érték
  amennyiben a kijelzére kerülő szám egyjegyű, a vezető nullát kioltjuk, illetve helyére kerül a minuszjel ha van. */ 
  float eszamertek=szamertek; //eredeti szamertek tárolására
  float proba;
  int tizedes;
  int ezres=0;    
  int szazas=0;
  int tizes=0;
  int egyes=0;
  boolean tizedespont=false;
  if (egeszertek==1) {  //ez csak a legnyomás lehet vagy paratartalom
    ezres=szamertek/1000;
    szazas=(szamertek-(ezres*1000))/100;
    tizes=(szamertek-(ezres*1000)-(szazas*100))/10;
    egyes=szamertek-(ezres*1000)-(szazas*100)-(tizes*10);
    if (szamertek<100) {  szazas=10;} //vezető nulla kioltása az szazas számjegyben
    if (szamertek<1000) { ezres=10;} //vezető nulla kioltása az ezres szamjegyben
  }
  else {  //az átalakítandó szám lehet pozitiv és negatív, és tizedesjegy értéket kell kijelezni
    if (szamertek<0) {  szazas=11;szamertek=0-szamertek;} else {  szazas=10;}
    tizes=szamertek/10;
    egyes=szamertek-(tizes*10);
    //vezető nullák kioltása (az 10-es érték üres kijelzés), illetve minusz előjel (11-es érték minusz jel)
    if (tizes==0 && eszamertek>=0) {  tizes=10;}
    if (szamertek<10 && eszamertek<0) { tizes=11;szazas=10;} //minusz előjel berakása a százas helyett a tizesbe
    proba=(szamertek-(int)szamertek);
    proba=(proba*10)+0.001;
    tizedes=(int)proba;
    tizedespont=true;
  }
  switch (ertekindex) {
    case 0:   //0 - külső hőmérséklet 
      bitsor0[0]=karakterkep[szazas];
      bitsor0[1]=karakterkep[tizes];
      bitsor0[2]=karakterkep[egyes]|B00000100;
      bitsor0[3]=karakterkep[tizedes];
      break;
    case 1:   //1 - páratartalom
      bitsor1[0]=karakterkep[ezres];
      bitsor1[1]=karakterkep[szazas];
      bitsor1[2]=karakterkep[tizes];
      bitsor1[3]=karakterkep[egyes];
      break;
    case 2:   //2 - légnyomás
      bitsor2[0]=karakterkep[ezres];
      bitsor2[1]=karakterkep[szazas];
      bitsor2[2]=karakterkep[tizes];
      bitsor2[3]=karakterkep[egyes];
      break;
    case 3:   //3 - pince hőmérséklet
      bitsor3[0]=karakterkep[szazas];
      bitsor3[1]=karakterkep[tizes];
      bitsor3[2]=karakterkep[egyes]|B00000100;
      bitsor3[3]=karakterkep[tizedes];
      break;
    case 4:   //4 - akna hőmérséklet
      bitsor4[0]=karakterkep[szazas];
      bitsor4[1]=karakterkep[tizes];
      bitsor4[2]=karakterkep[egyes]|B00000100;
      bitsor4[3]=karakterkep[tizedes];
      break;
    case 5:   //5 - kisház hőmérséklet
      bitsor5[0]=karakterkep[szazas];
      bitsor5[1]=karakterkep[tizes];
      bitsor5[2]=karakterkep[egyes]|B00000100;
      bitsor5[3]=karakterkep[tizedes];
      break;
    case 6:   //5 - kisház hőmérséklet
      bitsor6[0]=karakterkep[szazas];
      bitsor6[1]=karakterkep[tizes];
      bitsor6[2]=karakterkep[egyes]|B00000100;
      bitsor6[3]=karakterkep[tizedes];
      break;
  } 
}

long multimemo(byte cim) {
/***************************************************************************************************************
 * Ez a multimemo függvény akkor hívódik meg, ha csak egyetlen paramétert adtunk meg a függvény                *
 * meghívásakor (csak olvasni akarunk a tároló cellából)                                                       *
 * A három paraméteres multimemo függvényt hívja meg, de default értékkel tölti fel a maradék két paramétert   *
 * A megadott tároló cella címről adtot fogunk olvasni.                                                        *
 ***************************************************************************************************************/
  long adat=0;
  bool iras=0;
  return(multimemo(cim,adat,iras));
}


long multimemo(byte cim, long adat) {
/***************************************************************************************************************
 * Ez a multimemo függvény akkor hívódik meg, ha két paramétert adunk meg, a cella címét és a beírandó         *
 * adatot, vagyis írni akarunk a cellába. A tároló cella formázását és alaphelyzetbe állítását végző           *
 * két paraméteres multimemo függvénytől az különbözteti meg, hogy ennek második paramétere long típusú.       *
 * A három paraméteres multimemo függvényt hívja meg, de a harmadik paramétert (iras vagy olvasás) default     *
 * értékkel tölti fel (iras=1, azaz írunk). A megadott tároló cella címébe fogjuk az adtot beírni.             *
 ***************************************************************************************************************/
  bool iras=1;
  return(multimemo(cim,adat,iras));
}

long multimemo(byte cim, long adat, bool iras) {
/*****************************************************************************************************************************************************************
 * Ez a multimemo függvény akkor hívódik meg, ha három paraméterrel hívjuk. Ez végzi a tárolandó adat feldolgozását, tárolását, és visszaadja az eredményt       *  
 * visszatérő értékként. A tároló cella típusát az első tárolt byte adja meg, ezt az a multimemo függvény írja, melynek két paramétere van, és a második         *
 * cella_tipus (enum-al definiált felsorolás) típusú adatot vár.                                                                                                 *
 * A függvény bemenő paraméterei:                                                                                                                                *
 *    cim: 0-73 memória cella, egy cella 7 byte,                                                                                                                 *
 *    adat: long típusú 4 byte-os adat, amit beírunk a kijelölt memória cellába                                                                                  *
 *    iras: ez mondja meg, hogy írunk vagy olvasunk a tároló cellából. 0-olvasunk, 1-írunk                                                                       *
 * A tároló cella szerkezete:                                                                                                                                    *
 *    0. byte típus: 0=minimum cella, 1=maximum cella, 2=summa cella, 3=átlag cella, 4=tároló cella                                                              *
 *    1-4. byte adat long adattípus, ez a tényleges tárolt long adat 4 byte-on                                                                                   *
 *    5-6. byte átlag esetén az összegzett adatok száma int adattípusú Csak az átlagoló tároló cella használja, ebben számolja az írások számát.                 *
 *****************************************************************************************************************************************************************/
  int xcim=cim*7;
  byte page=0;
  byte adat0;
  byte adat1;
  byte adat2;
  byte adat3;
  if (xcim<256) {page=0;} else {page=1;xcim=xcim-256;}
  Wire.beginTransmission(_i2cAddress | (page&1));
  Wire.write(xcim);
  Wire.endTransmission(); 
  Wire.requestFrom(_i2cAddress | (page&1),7);
  byte xtipus=Wire.read();  //elkérjük az első byte-ot, ami a tárolt dat típusát adja meg
  long xadat=long(Wire.read()) | long(Wire.read())<<8 | long(Wire.read())<<16 | long(Wire.read())<<24 ; //elkérjük és betöltjük az adat aktuális értékét
  int xdb=int(Wire.read()) | int(Wire.read())<<8;  //elkérjük és betöltjük az adatok számát
  
  if (iras==0 and xtipus!=3) {return(xadat);}  //ha olvasás és nem átlagot kértünkvolt a művelet, akkor visszadjuk a kiolvasott long értéket
  if (iras==0 and xtipus==3) {if (xdb>0) {return((long)(xadat/xdb));} else {return(0);}}  //ha olvasás és átlagot kértünk, akkor osztani is kell, de csak ha xdb nem 0
  
  if (xtipus==0 and iras==1){ //ha írás és minimum cella
      if (xadat>adat) { //csak akkor írjuk be az új adatot, ha az eddig tárolt adatnál kissebb
        multimemo_adatiras(page,xcim,adat); //visszaírjuk az új adatot a tároló cellába
        return(adat);
      }
      else {return(xadat);} //visszadjuk a cellában tárolt minimum értéket
    }  
      
  if (xtipus==1 and iras==1){  //ha írás és maximum cella
      if (xadat<adat) {  //csak akkor írjuk be az új adatot, ha az eddig tárolt adatnál nagyobb
         multimemo_adatiras(page,xcim,adat); //visszaírjuk az új adatot a tároló cellába
        return(adat);
      }
      else {return(xadat);} //visszadjuk a cellában tárolt maximum értéket
    }  
      
  if (xtipus==2 and iras==1){  //ha írás és summa cella
    adat=xadat+adat;  //összeadjuk az új adatot ez eddig beírt adatok (tárolt) összegével
    multimemo_adatiras(page,xcim,adat);  //visszaírjuk az új adatot a tároló cellába
    return(adat); //visszadjuk az új cella értéket
  } 

  if (xtipus==3 and iras==1){  //ha írás és átlag cella
    adat=xadat+adat;  //összeadjuk az új adatot ez eddig beírt adatok (tárolt) összegével
    xdb=xdb+1; //növeljük a beírások számát 1-el
    Wire.beginTransmission(_i2cAddress | (page&1));Wire.write(xcim+1); //a cella első byte-ját már nem kell írni, azt beállított a cella reset, azért cim+1-től írunk
    Wire.write(adat & 0xFF);Wire.write((adat>>8) & 0xFF);Wire.write((adat>>16) & 0xFF);Wire.write((adat>>24) & 0xFF); //beírjuk az új összegzett adatot
    Wire.write(xdb & 0xFF);Wire.write((xdb>>8) & 0xFF);  //beírjuk az írások számát
    Wire.endTransmission(); 
    return((long)(adat/xdb));  //visszadjuk az új átlag értéket
  } 

  if (xtipus==4 and iras==1){  //ha írás és sima tároló cella
    multimemo_adatiras(page,xcim,adat);
    return(adat);
  } 
}

void multimemo_adatiras(byte page, byte xcim, long adat) {
// az átlag cella kivételével mindet ugyanúgy kell beírni, ezért a konkrét írás ebben a közösen használt függvényben lett megvalósítva
  Wire.beginTransmission(_i2cAddress | (page&1));Wire.write(xcim+1); //a cella első byte-ját már nem kell írni, azt beállított a cella reset, azért cim+1-től írunk
  Wire.write(adat & 0xFF);Wire.write((adat>>8) & 0xFF);Wire.write((adat>>16) & 0xFF);Wire.write((adat>>24) & 0xFF);
  Wire.endTransmission(); 
}

long multimemo(byte cim, cella_tipus tipus) {
/*******************************************************************************************************************************************************************  
 * Ez a multimemó függvény akkor hívódik meg, ha két paraméterrel hívjuk, és a második cella_tipus típusú változó, amit enum-al hoztunk létre a program elején.    *
 * A függvény elvégzi egy cella típusának beállítását (a cella első byte-ja), és alaphelyzetbe állítja a tárolt adatokat.                                          *
 * Bemenő paraméterek:                                                                                                                                             *
 *    cim: 0-73 db memória cella, egy cella 7 byte,                                                                                                                *
 *    típus: felsorolás típusú (enum) paraméter, ami meghatározza a cella tárolási módját. Lehetséges értékei 0-4 között.                                          *
 * Típus által képzett cella típusok, és azok tárolási módja, az elvégzett műveletek leírása:                                                                      *
 *  MIN: Az íráskor megkapott adatot csak akkor tárolja, ha az kissebb mint az éppen tárolt adat. Mielőtt elkezdjük a minimumot gyüjteni, be kell írni             *
 *       a lehető legnagyobb long értéket, különben nem biztos, hogy megjegyzi a legelső értéket. A számláló cellarészt nem használja.                             *
 *  MAX: Az íráskor megkapott adatot csak akkor tárolja, ha az nagyobb mint az éppen tárolt adat. Mielőtt elkezdjük a maximumott gyüjteni, be kell írni            *
 *       a lehető legkissebb long értéket, különben nem biztos, hogy megjegyzi a legelső értéket.                                                                  *
 *  SUM: Képzi a beírt adatok összegét. Alapértelmezetten a tartalma 0.                                                                                            *
 *  AVG: képzi a beírt adatok átlagát. Minden beít értéket szummáz az adat mezőben, számolja a beírások számát, és kiolvasáskor osztja az adatot a beírás számmal  *
 *       Alpértelmezetten az adat és a számláló is 0.                                                                                                              *
 *  STO: csak úgy simán tárolja az adatot, nem csinál vele semmit, ha volt bent előtte adat, azt felülírja. Alepértelmezett tartalma 0.                            *
 *******************************************************************************************************************************************************************/
  int xcim=cim*7;
  byte page;
  if (xcim<256) {page=0;} else {page=1;xcim=xcim-256;}
  Wire.beginTransmission(_i2cAddress | (page&1));
  Wire.write(xcim);
  if (tipus==MIN){
      // 2147483647 kezdő értéket írunk a tároló cellába, mert nincs nagyobb szám long esetén, így csak ennél kisebbek jöhetnek.
      Wire.write(0);Wire.write((long)2147483647 & 0xFF);Wire.write(((long)2147483647>>8) & 0xFF);Wire.write(((long)2147483647>>16) & 0xFF);Wire.write(((long)2147483647>>24) & 0xFF);
      Wire.write(0);Wire.write(0);
      Wire.endTransmission(); 
      return(0);
    }    
  if (tipus==MAX){
      // -2147483648 kezdő értéket írunk a tároló cellába, mert nincs kisebb szám long esetén, így csak ennél kisebbek jöhetnek.
      Wire.write(1);Wire.write((long)-2147483648 & 0xFF);Wire.write(((long)-2147483648>>8) & 0xFF);Wire.write(((long)-2147483648>>16) & 0xFF);Wire.write(((long)-2147483648>>24) & 0xFF);
      Wire.write(0);Wire.write(0);
      Wire.endTransmission(); 
      return(0);
    }    
  if (tipus==SUM or tipus==AVG or tipus==STO) {
      //össegző mező esetén csak simán törölni kell mindent
      Wire.write(tipus);Wire.write(0);Wire.write(0);Wire.write(0);Wire.write(0);
      Wire.write(0);Wire.write(0);
      Wire.endTransmission(); 
      return(0);
    }  
    Wire.endTransmission(); 
}

Ennek a programnak a mérete a fordító szerint 30380byte és így 340byte flash marad szabadon. A ram-ból 1498byte-ot használ, és így 550byte marad szabadon. Elkezdtem a programot optimalizálni. Megszüntettem a Dallas hőmérők kezelésére írt külön függvényt, így megszűnt az 1 másodperces delay() használat is. Helyette a mérésk időzítésébe tettem be a chip-ek vezérlését. A mérés indítást mindig egy előző szenzor mérése előtt indítom. Mivel minden chip külön Arduino bemeneten van, nem használom a Dallas chip-ek címzését, ez eddig is felesleges volt, csak nem vettem észre. Íme a kisebb és optimálisabb program:

/**************************************************************************************************
 * Kivezetések gyüjteménye:
 * A0 véglegesben pince DS18b20 hőmérő panelen DS1 felirat
 * A1 véglegesben akna felső DS18b20 hőmérő panelen DS2 felirat 
 * A2 véglegesben akna alsó DS18b20 hőmérő panelen DS3 felirat
 * A3 véglegesben kisház DS18b20 hőmérő panelen DS3 felirat
 * A4 - SDA jelvezeték I2C kommunikációhoz
 * A5 - SLC jelvezeték I2C kommunikációhoz
 * A6 - véglegesben fénymérő
 * D2 - latch pin (ST_CP)  74HC595
 * D3 - clockPin (SH_CP) 74HC595  
 * D4 - dataPin (DS) 74HC595 
 * D5 - ChipEnable (CE)74HC595   
 * D6 - LOAD (CS) MAX7219 ledmatrix      
 * D7 - CLK MAX7219 ledmatrix 
 * D8 - DataIn MAX7219 ledmatrix
 * D9 - DHT22/DHT11 Data
 * D10 - kijelzo ki/be nyomógomb bemenet (fejlesztéskor használtam, hogy éjszaka ne világítson
 */

#include<avr/wdt.h> //WatchDog header betöltése

//I2C busz kezelése 
#include <Wire.h>


//Fram cím adatai és cella típus felsorolása
byte A0A1=0b00;
byte _i2cAddress= (0b101000 | A0A1)<<1;
enum cella_tipus { MIN, MAX, SUM, AVG, STO };
//napi átlaghoz tároló cellák címeinek felsorolása
/*const byte v_kulso_n=0;
const byte v_kulso_n_min=1;
const byte v_kulso_n_max=2;
const byte v_para_n=3;
const byte v_para_n_min=4;
const byte v_para_n_max=5;
const byte v_legny_n=6;
const byte v_legny_n_min=7;
const byte v_legny_n_max=8;
const byte v_pince_n=9;
const byte v_aknaa_n=10;
const byte v_aknaf_n=11;
const byte v_kishaz_n=12;
const byte v_kishaz_n_min=13;
const byte v_kishaz_n_max=14;*/
//orankenti átlaghoz tároló cellák címeinek felsorolása
const byte v_kulso_o=15;
const byte v_kulso_o_min=16;
const byte v_kulso_o_max=17;
const byte v_para_o=18;
const byte v_para_o_min=19;
const byte v_para_o_max=20;
const byte v_legny_o=21;
const byte v_legny_o_min=22;
const byte v_legny_o_max=23;
const byte v_pince_o=24;
const byte v_aknaa_o=25;
const byte v_aknaf_o=26;
const byte v_kishaz_o=27;
const byte v_kishaz_o_min=28;
const byte v_kishaz_o_max=29;
long kuldendo1; //segédváltozó az adatküldéshez, első lépésben ebbe olvassuk be a memória cella tartalmát, mert az is i2c-t használ     
long kuldendo2; //segédváltozó az adatküldéshez, első lépésben ebbe olvassuk be a memória cella tartalmát, mert az is i2c-t használ     
long kuldendo3; //segédváltozó az adatküldéshez, első lépésben ebbe olvassuk be a memória cella tartalmát, mert az is i2c-t használ     
long kuldendo4; //segédváltozó az adatküldéshez, első lépésben ebbe olvassuk be a memória cella tartalmát, mert az is i2c-t használ     
long kuldendo5; //segédváltozó az adatküldéshez, első lépésben ebbe olvassuk be a memória cella tartalmát, mert az is i2c-t használ     

//mérési eredményekhez
float kulso_homerseklet=0;
float paratartalom=0;
float legnyomas=1000;
float pince_homerseklet=0;
float akna_homerseklet_also=0;
float akna_homerseklet_felso=0;
float kishaz_homerseklet=0;

//BME280 érzékelőhöz
//#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C

//LCD kijelző kezelése
#include <LiquidCrystal_I2C.h>  //I2C LCD kezelő könyvtár
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  //LCD paraméterek megadása, a 4 soros LCD-m címe 3F, kétsors címe 27

//óra modul programjai és változó deklarációi
//==========================================
#include <DS3231.h>
DS3231 Clock;
bool Century=false;
bool h12=true;
bool PM;
byte ev=0;
byte ho=0;
byte nap=0;
byte ora=0;
byte perc=0;
byte masodperc=0;
String str_tmp;
String utolso_nap_iras="Nap file:Nemvolt";
String utolso_ev_iras="Ev file:Nem volt";
byte sd_hiba=2; //A slvae küldi vissza ezt az értéket az adat fogadás után, és visszajelzi, hogy sikerült-e az SD írás 0=ok, 1=hiba, 2=nincs adat

// DALLAS hőmérő chip-ek bekötése, használatuk előkészítése
//=========================================================
    // Dallas onwire hőmérő chip (felülrőlnézve balról jobbra haladva)
    //  18B20 kivezetés   Vezeték            Arduino UNO/NANO kivezetés
    //  GDD               kék vezeték        GND
    //  DATA              sárga vezeték      A3, A1, A6 kivezetéseken 
    //  VDD               piros vezeték      +5V
  #include <OneWire.h>          //Dallas 18b20 hőmérő kezeléshez one-wire busz

  byte ds_data[9];               //kiolvasott adtok tárolására
  OneWire  ds1(A0);              // a A0. kivezetéshez kell kapcsolni pince hőmérőjét 
  OneWire  ds2(A1);              // a A1. kivezetéshez kell kapcsolni az akna felső hőmérőjét 
  OneWire  ds3(A2);              // a A2. kivezetéshez kell kapcsolni az akna alsó hőmérőjét 
  OneWire  ds4(A3);              // a A3. kivezetéshez kell kapcsolni az kisház hőmérőjét 

//fénymérés TEPT4400 fototranzisztorral. A rövidebb láb a kollektor, ez megy a tápfesz 5V-ra
//A hosszabb láb az emitter, ez egy 1Kohm ellenálláson keresztül megy a földre. Az emitterből
//vezetem a mérendő feszültséget az A6 bemenetre. Sötétben a mért fesz 0 körül, napsütésben 
//1000 körül. Megvilágítva nyit ki a tranzisztor és felhúzza a jelvezetéket a tápfeszre.
//A méréskor a tápfeszt veszem referenciának!
int mert_fenyero[10]={0,0,0,0,0,0,0,0,0,0}; //az utolso 10 mért fenyero erteke
int fenyertek=0; //az utolso 10 mért fenyerő érték átlaga


//MAX7219-4DM 8x8 led matrix modul************************
//--------------------------------------------------------
    // Led matrix (matrix feliratú kábel):
    //  MAX7219 kivezetés   Vezeték           Arduino UNO/NANO kivezetés
    //  DataIn             (piros vezeték)    D8 (pin13)
    //  CLK                (fekete vezeték)   D7 (pin12)
    //  LOAD (CS)          (zöld vezeték)     D6 (pin11) 

#include "LedControl.h"       
LedControl lc=LedControl(8,7,6,3); //kimeneteket beállítja magának
// karakterképek tárolása tömbökben
//fok celsius karakterkép egy modulon
//const byte lc_celsius[8]={B01100000,B10010000,B01100000,B00000000,B01111100,B10000010,B10000010,B01000100};   
//  Milibar   Százalék   Pince     Akna   Akna felső Akna alsó   ház
// B..11111. B11...1.. B00000000 B00000000 B00111110 B00000000 B00000000
// B..1..... B11..1... B00000000 B00000000 B01001000 B00111110 B00000000
// B...1111. B...1.... B00000000 B00000000 B01001000 B01001000 B00000000
// B..1..... B..1..11. B01111110 B00111110 B00111110 B01001000 B01111110
// B...1111. B.1...11. B01001000 B01001000 B00000000 B00111110 B00011000
// B........ B........ B01001000 B01001000 B01110000 B00000000 B00011000
// B1111111. B........ B00110000 B00000000 B00000000 B00001110 B01111110
// B..1...1. B........ B00000000 B00111110 B00000000 B00000000 B00000000
// B..1...1. Fényerő * Celsius
// B...111.. B01000100 
// B........ B00101000 
// B..11111. B00111000 
// B...1.... B11111110 
// B..1..... B00111000 
// B..1..... B00101000 
//           B01000100 
// led matrix vezérlő parancsok mintapéldák:
// lc.setRow(index,sor,B10100000);
// lc.setLed(index,sor,oszlop,true); fénypont bekapcsolása
// lc.setLed(index,sor,oszlop,false);  fénypont kikapcsolása
// lc.setColumn(0,oszlop,B10100000);

//hétszegmens kijelző vezérlés előkészítés
//----------------------------------------
// 7 szegmens kijelzó (7szegmens feliratú kábel) 74CH595 chip meghajtóval
// 10 modul sorma kötve, soros bitenkénti (modulonkénti 8 bit)beléptetéssel
//  74CH595 kivezetés  Vezeték           Arduino UNO/NANO kivezetés
//  latch pin (ST_CP)  kék vezeték       D2
//  clockPin (SH_CP)   fehér vezeték     D3
//  dataPin (DS)       sárga vezeték     D4
//  ChipEnable (CE)    zöld vezeték      D5

// 7 szegmens karakterkép előállításhoz segédlet
// --A--
// F   B
// --G--
// E   C 
// --D-- P (P=tizedespont)
// számjegyek kijelzéséhez szükséges aktív szegmensek:
// 0=ABCDEF,1=BC,2=ABGED,3=ABGCD,4=BCFG,5=ACDFG,6=ACDEFG,7=ABC,8=ABCDEFG,9=ABCDFG
// Mask: ABFGDPCE (a 8 bites bitfolyamban ebben a sorrendben lett vezetékezve
//       a 74CH595 IC kivezetése hozzákötve a kijelző modul egyes szegmenseihez 
//      tizedespont balról a 6. bit
//karakterképek definiálása: 0-9-ig számjegyek, 10-üres, 11-minuszjel, 12-dupla aláhúzás
const byte karakterkep[13]={B11101011,  //0
                      B10000001,  //1
                      B01110011,  //2
                      B11010011,  //3
                      B10011001,  //4
                      B11011010,  //5
                      B11111010,  //6
                      B10000011,  //7
                      B11111011,  //8
                      B11011011,  //9
                      B00000000,  //ÜRES
                      B00010000,  //MINUSZ
                      B00010010}; //DUPLA ALÁHUZAS
// próbáltam spóromli a memóriával, ezért direktben írtam be a programba, de nem ált be
//const int latchPin = 2;   //pin2 (ST_CP) 74HC595 
//const int clockPin = 3;   //clock pin (SH_CP) 74HC595
//const int dataPin = 4;    //Data in (DS) 74HC595
//const int ChipEnable = 5; //CE kivezetés 74HC95                          


// a mért értéket karakterképének bitsorozta a 7 segment kijelzőbe léptetéshez (4 számjegy)
byte bitsor0[4];  //0 - külső hőmérséklet
byte bitsor1[4];  //1 - páratartalom
byte bitsor2[4];  //2 - légnyomás
byte bitsor3[4];  //3 - pince hőmérséklet
byte bitsor4[4];  //4 - akna hőmérséklet also
byte bitsor5[4];  //4 - akna hőmérséklet felso
byte bitsor6[4];  //5 - kisház hőmérséklet
byte eszkoz_num=0;     //az aktuálisan lekérdezett eszköz indexe, megeggyezik a bitsor változó számjegyével
long meres_ido=millis(); //15 másodpercenkénti mérés időzítéséhez segédváltozó 
long kijelzovaltas_ido=millis(); //az alsó sor értékeinek váltogatásának időzítéséhez
long fenyero_ido_tmp=millis();  //a fényerő beállításának időzítéséhez (1 másodpercenként)
long sd_lekerd_ido=millis();  //az SD kártya ellenőrzésének időzítéséhez (I2C buszin kérdezzük le a slave-től)
bool tarolas=false;
bool tarolasnap=false;



//a kijelzo nyomógombbal történő ki és bekapcsolásához kellenek
bool elengedve=LOW; //a nyomógomb elengedett állapotát jelzi, akkor HIGH, ha egy nyomvatartás után (nyomva=HIGH) elősször megszakad a ontaktus
long elenged_ido=millis(); //az elengedés prellmenetsítéséhez az időmérésre
bool nyomva=LOW;  //ha HIG, akkor nyomva van a nyomógomb, az első kontaktus HIGH-re állítja, elengedés után lesz LOW-ra visszaállítva
long nyomva_ido=millis();  //az megnyomás prellmentesítéséhez időmérésre
bool lcd_vilagitas=LOW;
bool kijelzo_kapcsolas=LOW; //ha 1, akkor éppen végrehajtottunk egy kijelző állapotváltást, és nyomógomb elengedésig megakadályozza, hogy ez megismétlődjön
bool kijelzo_ki_be=HIGH; //a kijelzo ki és bakapcsolt állapotát tárolja
long adatkuldes_ido=millis();
bool ora_setup=LOW;
long ora_setup_ido=millis();
byte setup_num=0;
byte ora_setup_ertek=0;
byte ora_setup_ujertek=0;
bool setup_num_novel=HIGH; //ha növelni lehet egy elengedés után a setup_num-ot, akkor HIGH. Érték változtatás után lesz LOW, hogy ne növekedjen a setup_num értéke
bool mert_ertek_kijelzes=HIGH; //mérési eredmények lcd-re írásának engedélyezés HIGH értékkel
byte kijelzes_num=1;   //az aktuálisan kijelzett érték indexe, megeggyezik a bitsor változó számjegyével
long adatfogadas_ido=millis()+6000; //percenként fogadjuk a mert adatokat a slave-tól, ugyaekkor mérjuk a légnyomást is
long lcd_frissit_ido_tmp=millis()+1000;  //az lcd adatkiírás frissítéshez és a fényerő beállításának időzítéséhez (1 másodpercenként)
long lcd_kijelzo_ido=millis();
byte lcd_eszkoz_num=0;     //az aktuálisan kijelzett eszköz indexe az lcd kijelzőn frissített mert adathoz

bool ds1_on=LOW; //DS1 hűmérő incializálva lett-e, HIGH esetén igen
bool ds2_on=LOW; //DS2 hűmérő incializálva lett-e, HIGH esetén igen
bool ds3_on=LOW; //DS3 hűmérő incializálva lett-e, HIGH esetén igen
bool ds4_on=LOW; //DS4 hűmérő incializálva lett-e, HIGH esetén igen
bool ds1_crc_hiba=LOW; //High esetén DS1 Dallas chip CRC hibát eredményezett olvasáskor
bool ds2_crc_hiba=LOW; //High esetén DS1 Dallas chip CRC hibát eredményezett olvasáskor
bool ds3_crc_hiba=LOW; //High esetén DS1 Dallas chip CRC hibát eredményezett olvasáskor
bool ds4_crc_hiba=LOW; //High esetén DS1 Dallas chip CRC hibát eredményezett olvasáskor
bool bme280_on=LOW; //bme280 légnyomás, páratrtalom és hőmérséklet mérő inicializálva lett-e, HIGH esetén igen

void setup()
{
  wdt_enable(WDTO_4S);  //engedélyezük a watcdog-ot 4 sekundum várakozással 
                        //4sec után a chip ujaindítja magát, ha nincs közben
                        // wdt_reset() függvényhívás, ami ujraindítja a timert

  
  //74HC595 előkészítése
  pinMode(2,OUTPUT); //latch pin 74HC595
  pinMode(4,OUTPUT); //data pin (DS) 74HC595
  pinMode(3,OUTPUT); //Clock pin 74HC595
  pinMode(5,OUTPUT);  //chipenabla (CE) 74HC595
  //kijelző önteszt
  analogWrite(5,128);  //kezdő fényerő beállítás a hétszegmen kijelzőn. Csak a bekapcsolási folyamat alatt 
  digitalWrite(2, LOW); //shift regiszter kimenetek lezárása (latchPin=0)
  shiftOut(4, 3, MSBFIRST, B11111111);            //külső hőmérséklet szazas
  shiftOut(4, 3, MSBFIRST, B11111111);            //külső hőmérséklet tizes
  shiftOut(4, 3, MSBFIRST, B11111111);            //külső hőmérséklet egyes
  shiftOut(4, 3, MSBFIRST, B11111111);            //külső hőmérséklet tizedes
  shiftOut(4, 3, MSBFIRST, B11111111);            //páratartalom ezres (mindíg üres)
  shiftOut(4, 3, MSBFIRST, B11111111);            //páratartalom szazas (mindíg üres)
  shiftOut(4, 3, MSBFIRST, B11111111);            //páratartalom tizes
  shiftOut(4, 3, MSBFIRST, B11111111);            //páratartalom egyes
  digitalWrite(2, HIGH); //shift regiszter kimeneteire a beléptetett infó kiírása (latchPin=1)
  // 8x8 matrix felebresztese
  lc.shutdown(0,false);lc.shutdown(1,false);lc.shutdown(2,false);
  lc.setIntensity(0,8);lc.setIntensity(1,8);lc.setIntensity(2,8);
  // matrix kijelző önteszt
  for (int i=0;i<3;i++) { for (int j=0;j<8;j++) {lc.setRow(i,j,B11111111);} }

  Wire.begin(); //I2C inicializálása
  //***************************************Ezt csak egyszer kell lefuttatni, aztán ki kell kommentezni***************************
  /*/FRAM cellak elokeszítése naponkénti átlaghoz
  multimemo(v_kulso_n,AVG);multimemo(v_kulso_n_min,MIN);multimemo(v_kulso_n_max,MAX);
  multimemo(v_para_n,AVG);multimemo(v_para_n_min,MIN);  multimemo(v_para_n_max,MAX);
  multimemo(v_legny_n,AVG);multimemo(v_legny_n_min,MIN);multimemo(v_legny_n_max,MAX);
  multimemo(v_pince_n,AVG);multimemo(v_aknaa_n,AVG);multimemo(v_aknaf_n,AVG);
  multimemo(v_kishaz_n,AVG);multimemo(v_kishaz_n_min,MIN);multimemo(v_kishaz_n_max,MAX);
  //FRAM cellak elokeszítése orankenti átlaghoz
  multimemo(v_kulso_o,AVG);multimemo(v_kulso_o_min,MIN);multimemo(v_kulso_o_max,MAX);
  multimemo(v_para_o,AVG);multimemo(v_para_o_min,MIN);multimemo(v_para_o_max,MAX);
  multimemo(v_legny_o,AVG);multimemo(v_legny_o_min,MIN);multimemo(v_legny_o_max,MAX);
  multimemo(v_pince_o,AVG);multimemo(v_aknaa_o,AVG);multimemo(v_aknaf_o,AVG);
  multimemo(v_kishaz_o,AVG);multimemo(v_kishaz_o_min,MIN);multimemo(v_kishaz_o_max,MAX);
  multimemo(30,STO);multimemo(31,STO);multimemo(32,STO);
  //Ezt pedig célszerű második lépésben kikommentezni, ha már történt néhány mérés, mert akkor azok adatait
  //fogja tárolni és az előző napi átlag és min max lekérdezéshez nem nullát fog írni. Egyébként az előző
  //napi adatok minden nap egyszer, éjfélkor kerülnek tárolásra, tehát egy nap múlva lesz benne valós adat
  long szam=multimemo(v_kulso_n);multimemo(30,szam);
  szam=multimemo(v_kulso_n_min);multimemo(31,szam);
  szam=multimemo(v_kulso_n_max);multimemo(32,szam);*/
  //*********************************************************************************************************************************

  //LCD inicializálása
  lcd.begin(16,2);
  lcd.clear();
  lcd.backlight();      //háttérvilágítás bekapcsolása
  
  //Serial.begin(9600);
 
  bme280_lekerdez();
  pince_homerseklet=0.0;
  akna_homerseklet_felso=0.0;
  akna_homerseklet_also=0.0;
  kishaz_homerseklet=0.0;

  //ide jönnek majd az első mérések, és egy 0. változó feltöltés, hogy rögtön indulhasson az értékek kijelzése
  szamjegybontas(kulso_homerseklet,0,0); //kulső hőmérséklet karakterképe bitsor0 tömbbe
  szamjegybontas(paratartalom,1,1); //páratartalom karakterképe bitsor1 tömbbe
  szamjegybontas(legnyomas,2,1); //legnyomás karakterképe bitsor2 tömbbe
  szamjegybontas(pince_homerseklet,3,0); //pince hőmérséklet karakterképe bitsor3 tömbbe
  szamjegybontas(akna_homerseklet_also,4,0); //akna hőmérséklet karakterképe bitsor4 tömbbe
  szamjegybontas(kishaz_homerseklet,5,0); //kisház hőmérséklet karakterképe bitsor5 tömbbe 

  //felső sor matrix kijelzőjére "°C" felirat
  lc.setRow(2,0,B00000000);
  lc.setRow(2,1,B01000110);
  lc.setRow(2,2,B10101001);
  lc.setRow(2,3,B10101000);
  lc.setRow(2,4,B01001000);
  lc.setRow(2,5,B00001000);
  lc.setRow(2,6,B00001001);
  lc.setRow(2,7,B00000110);
  
  lcd.noBacklight();      //LCD háttérvilágítás kikapcsolása

  pinMode(10,INPUT);  //nyomógomb erre a bemenetre van kötve

  // átküldjük a slave-ra 6-os kóddal a pillanatnyi időt és dátumot
  // A slave SD-re írja az elindulás dátumát és időpontját START.CSV nevű állományba.
  // Ezzel rögzítjük, ha reset, bekapcsolás, vagy watcdog újraindítja a rendszert
  ev=Clock.getYear();
  ho=Clock.getMonth(Century);
  nap=Clock.getDate();
  ora=Clock.getHour(h12,PM);
  perc=Clock.getMinute();  
  masodperc=Clock.getSecond();
  Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
  Wire.write(8);
  Wire.write(ev);
  Wire.write(ho);
  Wire.write(nap);
  Wire.write(ora);
  Wire.write(perc);
  Wire.write(masodperc);
  Wire.endTransmission();     // vége az átvitelnek
  Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé  

}

void loop()
{
TWBR = 128; //I2C buszsebesség 58Khz
  
  /*****************************************************************************
   * 10 másodpercenként lekérdezzük, hogy működik-e az SD kártya. Az SD kártya
   * írás állapotát az LCD-n le lehet kérdezni (OK=sikerül, ERR=nem sikerült).  
   * Elküldjük az erzekelökről, hogy van-e hiba. Ha van érzékelő hiba
   * akkor villogni fog a led a kijelző panelen. Az LCD kijelzőn is kiírjuk
   * a hiba állapotot érzékelőnként (SD1a,SD1b,SD2,SD3: OK=működik,
   *                                           OFF=nem található,
   *                                           CRC=crc hiba az érzékelő olvasásakor
   *****************************************************************************/
  if (millis()>sd_lekerd_ido+10000)
  {
    Wire.requestFrom(8,1);      // a master kér 1 byte-ot a slave-től
    sd_hiba= Wire.read();       //beolvassuk a slave által küldött byte-ot    
    sd_lekerd_ido=millis();
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(9); //a 9-es küldési kód jelzi a hiba átvitelt
    if (ds1_crc_hiba or ds2_crc_hiba or ds3_crc_hiba or !bme280_on or !ds1_on or !ds2_on or !ds3_on or !ds4_on) //ha bármelyik érzékelő hibás, akkor villogjon a led 
      {Wire.write(1);}  //valamelyik érzékelővel hiba van
    else
      {Wire.write(0);} //nincs hiba az érzékelőkkel
    Wire.endTransmission();     // vége az átvitelnek
  } 
  /****************************************************************************
   *másodpercenként frissítjük a kijelzőn az időt
   ****************************************************************************/
  if (millis()>lcd_frissit_ido_tmp+1000)
    {
      // Mivel ezt a programrészt másodpercenkét futtatjuk, felhasználhatjuk arra, hogy másodpercenként 
      // reseteljük a wotchdog számlálóját. Ha a program lefagy, és nem hajtódik végre a wdt_reset, akkor
      // 4 másodperc után újraindul az Arduino nano programja, mintha resetet nyomtunk volna
      wdt_reset(); //alaphelyzetbe állítjuk a a watcdog timer-t

      fenyero_beallitas(); //fenymérés és fényerő beállítás 
      if (ora_setup==LOW) 
      {
        if (ora==0 and perc==0 and (masodperc==0 or masodperc==1))
        {
          str_tmp="";
          ev=Clock.getYear();
          ho=Clock.getMonth(Century);
          nap=Clock.getDate();
          if (ho<10) {str_tmp=str_tmp+"0"+String(ho)+"/";} else {str_tmp=str_tmp+String(ho)+"/";}
          if (nap<10) {str_tmp=str_tmp+"0"+String(nap);} else {str_tmp=str_tmp+String(nap)+" ";}
          lcd.setCursor(0,0);lcd.print(str_tmp);
        }
        ora=Clock.getHour(h12,PM);
        perc=Clock.getMinute();  //percenként fogunk mérni és ez kell a perc változás észrevételéhez
        masodperc=Clock.getSecond();
        if (ora<10) {str_tmp=" 0"+String(ora)+":";} else {str_tmp=" "+String(ora)+":";}
        if (perc<10) {str_tmp=str_tmp+"0"+String(perc)+":";} else {str_tmp=str_tmp+String(perc)+":";}
        if (masodperc<10) {str_tmp=str_tmp+"0"+String(masodperc)+"  ";} else {str_tmp=str_tmp+String(masodperc)+"  ";}
        lcd.setCursor(5,0);lcd.print(str_tmp);
        lcd.setCursor(0,1);lcd.print("W:   ");
        if (60-perc<10) {lcd.setCursor(2,1);lcd.print(String(60-perc)+" ");} else {lcd.setCursor(2,1);lcd.print(String(60-perc));}
        if (masodperc>10) {tarolas=true;tarolasnap=true;}  //azrt kell, hogy a tarolas csak egyszer fusson le az adott percben
      }
      lcd_frissit_ido_tmp=millis();
    }
  
  /*********************************************************************************************************************************
   * A nyomógomb megnyomásával váltogatjuk a kijelző tartalmát
   *********************************************************************************************************************************/
  //megnyomta a nyomógombot, de még lehet, hogy prelles
  if (digitalRead(10)==LOW and nyomva==LOW) {nyomva_ido=millis();nyomva=HIGH;lcd.backlight();}    //megynomta a setup gombot
  //ha 50msec mulva is nyomva tartja,akkor ez már nem prelles, biztosn nyomva van, lehet belépni a setup folyamatba
  if (digitalRead(10)==LOW and millis()>nyomva_ido+50 and nyomva==HIGH) {ora_setup_ido=millis();ora_setup=HIGH;}
  //elengedte a nyomógombot, de még lehet, hogy prelles
  if (digitalRead(10)==HIGH and elengedve==LOW and nyomva==HIGH) {elenged_ido=millis();elengedve=HIGH;}
  //már 70msec óta elenged, biztosan nem prelles, beállítási értéket váltunk, lehet várni az új megnyomásra
  if (digitalRead(10)==HIGH and elengedve==HIGH and millis()>elenged_ido+50) 
  {
    nyomva=LOW;
    elengedve=LOW;
    if (ora_setup==HIGH) //setup módban vagyunk, lehet beállítani a következő setup értéket és várakozni a váltásra vagy nyomva tartás esetén a beállításra
    {
      if (setup_num_novel==HIGH) {setup_num=setup_num+1;if (setup_num==15){setup_num=9;}}
      setup_num_novel=HIGH; //ha változtatás után nem kellett növelni, legözelebb már kell
      switch (setup_num) {
        case 1: //csak a világítást kapcsoljuk be a kijelzőn, és egy percig így is marad
          mert_ertek_kijelzes=HIGH; //mehet tovább a mérési eredmények kijlzése
          lcd_vilagitas=HIGH;  //ha éppen világit az LCD, akkor nem akarja majd újra bekapcsolni az első lenyomással, helyette
                               //rögtön a setup_num értéke 2 lesz, tehát kijelzi az érzékelők állapotát
          break;
       case 2: //átlag érték kijelzés
          lcd.setCursor(0,0);lcd.print("Tegnapi atlag:  ");
          lcd.setCursor(0,1);lcd.print("                ");
          lcd.setCursor(7,1);lcd.print((float)multimemo(30)/100);
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
       case 3: //átlag érték kijelzés
          lcd.setCursor(0,0);lcd.print("Tegnapi min/max:");
          lcd.setCursor(0,1);lcd.print("                ");
          lcd.setCursor(0,1);lcd.print((float)multimemo(31)/100);
          lcd.setCursor(7,1);lcd.print("/");
          lcd.setCursor(9,1);lcd.print((float)multimemo(32)/100);
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
       case 4: //átlag érték kijelzés
          lcd.setCursor(0,0);lcd.print("Jelenlegi atlag:");
          lcd.setCursor(0,1);lcd.print("                ");
          lcd.setCursor(7,1);lcd.print((float)multimemo(0)/100);
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
       case 5: //átlag érték kijelzés
          lcd.setCursor(0,0);lcd.print("Jelenl. min/max:");
          lcd.setCursor(0,1);lcd.print("                ");
          lcd.setCursor(0,1);lcd.print((float)multimemo(1)/100);
          lcd.setCursor(7,1);lcd.print("/");
          lcd.setCursor(9,1);lcd.print((float)multimemo(2)/100);
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
        case 6: //onewire hőmérők állapot visszajelzée
          lcd.setCursor(0,0);lcd.print("DS1:OK  DS2:OK  ");
          lcd.setCursor(0,1);lcd.print("DS3:OK  DS4:OK  ");
          lcd.setCursor(4,0);
          if (ds1_crc_hiba) {lcd.print("CRC");} if (!ds1_on) {lcd.print("OFF");} 
          lcd.setCursor(12,0);
          if (ds2_crc_hiba) {lcd.print("CRC");} if (!ds2_on) {lcd.print("OFF");} 
          lcd.setCursor(4,1);
          if (ds3_crc_hiba) {lcd.print("CRC");} if (!ds3_on) {lcd.print("OFF");} 
          lcd.setCursor(12,1);
          if (ds4_crc_hiba) {lcd.print("CRC");} if (!ds4_on) {lcd.print("OFF");} 
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
        case 7: //SD működés, és légnyomásmérő működés visszajelzés
          lcd.setCursor(0,0);lcd.print("SD:              ");
          lcd.setCursor(0,1);lcd.print("Legny.mero:      ");
          lcd.setCursor(3,0);
          switch (sd_hiba) 
          {
            case 0:
              lcd.print("OK         ");break;
            case 1:
              lcd.print("Error      ");break;
            case 2:
              lcd.print("nincs adat ");break;
          }
         lcd.setCursor(12,1);
         switch (bme280_on) 
          {
            case 0:
              lcd.print("OFF   ");break;
            case 1:
              lcd.print("ON     ");break;
          }
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
        case 8: //az utolsó napi állomány írási időpontját írjuk ki. Ha hiba volt, akkor nem dátum, hanem error jelzés van a változóban
          lcd.setCursor(0,0);lcd.print(utolso_nap_iras);
          lcd.setCursor(0,1);lcd.print(utolso_ev_iras);
          mert_ertek_kijelzes=LOW; //nem mehet tovább a mérési eredmények kijelzése, 5 sec mulva fog visszakapcsolni ezek kijelzése
          break;
        case 9:
          lcd.setCursor(0,0);lcd.print("Ora beallitas:  ");
          lcd.setCursor(0,1);lcd.print("Ev:    20"+String(Clock.getYear())+"     ");
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
        case 10:
         lcd.setCursor(0,1);lcd.print("Ho:      "+String(Clock.getMonth(Century))+"     ");
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
        case 11:
          lcd.setCursor(0,1);lcd.print("Nap:     "+String(Clock.getDate())+"     ");
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
        case 12:
          lcd.setCursor(0,1);lcd.print("Hetnapja:");
          lcd.setCursor(9,1);
          switch (Clock.getDoW()) 
            {
              case 1:
                lcd.print("Hetfo");break;
              case 2:
                lcd.print("Kedd ");break;
              case 3:
                lcd.print("Szerd");break;
              case 4:
                lcd.print("Csut ");break;
              case 5:
                lcd.print("Pent ");break;
              case 6:
                lcd.print("Szomb");break;
              case 7:
                lcd.print("Vasar");break;
            }
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
        case 13:
          lcd.setCursor(0,1);lcd.print("Ora:     "+String(Clock.getHour(h12,PM))+"     ");
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
        case 14:
          lcd.setCursor(0,1);lcd.print("Perc:    "+String(Clock.getMinute())+"     ");
          mert_ertek_kijelzes=LOW; //a meresi eredmények kijelzését a setup idejére leállítjuk
          break;
      }
    }
  } 
  //ha 5 másodpercre elengedi a nyomógombpt  setup folyamaton belül, akkor visszaállítjuk az eredeti állapotot
  if (digitalRead(10)==HIGH and millis()>ora_setup_ido+5000 and ora_setup) 
  {
    ora_setup=LOW;nyomva=LOW;
//    setup_num=0;
    if (lcd_vilagitas==LOW) {setup_num=0;} else {setup_num=1;} //ha nem világit a kijelző, akkor első megnyomásar be kell kapcsolni
                                                               //ha világít, akkor első lenyomásar már tartalmat kell váltani
    str_tmp="";  // be kell frissíteni a dátumot az lcd kijelzőn, mert lehet, hogy változott, és egyébként csak óránként frissítem
    if (Clock.getMonth(Century)<10) {str_tmp=str_tmp+"0"+String(Clock.getMonth(Century))+"/";} else {str_tmp=str_tmp+String(Clock.getMonth(Century))+"/";}
    if (Clock.getDate()<10) {str_tmp=str_tmp+"0"+String(Clock.getDate());} else {str_tmp=str_tmp+String(Clock.getDate());}
    lcd.setCursor(0,0);lcd.print(str_tmp);
    mert_ertek_kijelzes=HIGH; //mehet tovább a mérési eredmények kijlzése
  }
  //ha 60 másodperce elengedte a nyomógombpt akkor a háttérvilágítást is kikapcsoljuk
  if (digitalRead(10)==HIGH and millis()>ora_setup_ido+60000 and ora_setup==LOW) 
  {
    lcd_vilagitas=LOW;
    lcd.noBacklight();
  }
  //egy másodpercig nyomvatartotta, változtatjuk az adott értéket, elengedéskor az állapotot beállítjuk az órába
  if (digitalRead(10)==LOW and ora_setup==HIGH and nyomva==HIGH and millis()>nyomva_ido+1000) 
  {
     switch (setup_num) {
        case 9:
          ora_setup_ertek=Clock.getYear();
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,19,40);
          Clock.setYear(ora_setup_ujertek);
          break;
        case 10:
          ora_setup_ertek=Clock.getMonth(Century);
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,1,12);
          Clock.setMonth(ora_setup_ujertek);
          break;
        case 11:
          ora_setup_ertek=Clock.getDate();
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,1,31);
          Clock.setDate(ora_setup_ujertek);
          break;
        case 12:
          ora_setup_ertek=Clock.getDoW();
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,1,7);
          Clock.setDoW(ora_setup_ujertek);
          break;
        case 13:
          ora_setup_ertek=Clock.getHour(h12,PM);
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,0,23);
          Clock.setHour(ora_setup_ujertek);
          break;
        case 14:
          ora_setup_ertek=Clock.getMinute();
          ora_setup_ujertek=ertekporgetes(ora_setup_ertek,0,59);
          Clock.setMinute(ora_setup_ujertek);
          Clock.setSecond(0);
          break;
      }
      ora_setup_ido=millis();
  }
  /*********************************************************************************************************************
   * egy másodpercenként kiolvassuk az órát, frissítjük az ora, perc és masodperc változókat, kiírjuk az lcd-re        *
   * az időt, a dátumot csak óránként frissítjük. Ugyanekkor megmérjük a fényerőt és ehhez igazítjuk a kijelzők fényrejét *
   *********************************************************************************************************************/
    //kétmásodpercenként más eszköz mérési eredményét jelenítjük meg az LCD kijelzőn, hogy ott is láthatóak legyenek az adatok
    if (millis()>lcd_kijelzo_ido+2000 and mert_ertek_kijelzes==HIGH)  
    {
      lcd.setCursor(5,1);
      switch (lcd_eszkoz_num) {
        case 0:   
          lcd.print(" Kulso:     ");
          lcd.setCursor(12,1);lcd.print(kulso_homerseklet);
          lcd_eszkoz_num++;
          break;
        case 1:     
          lcd.print("  Para:   % ");
          lcd.setCursor(12,1);lcd.print((byte)paratartalom);
          lcd_eszkoz_num++;
          break;
        case 2:   
          lcd.print(" Legny:     ");
          lcd.setCursor(12,1);lcd.print((int)legnyomas);
          lcd_eszkoz_num++;
          break;
        case 3:  
          lcd.print(" Pince:      ");
          lcd.setCursor(12,1);lcd.print(pince_homerseklet);
          lcd_eszkoz_num++;
          break;
        case 4:   
          lcd.print("Akna A:      ");
          lcd.setCursor(12,1);lcd.print(akna_homerseklet_also);
          lcd_eszkoz_num++;
          break;
        case 5:   
          lcd.print("Akna F:      ");
          lcd.setCursor(12,1);lcd.print(akna_homerseklet_felso);
          lcd_eszkoz_num++;
          break;
        case 6:   
          lcd.print("Kishaz:      ");
          lcd.setCursor(12,1);lcd.print(kishaz_homerseklet);
          lcd_eszkoz_num++;
          break;
        case 7:   
          lcd.print("  Feny:      ");
          lcd.setCursor(12,1);lcd.print(analogRead(A6));
          lcd_eszkoz_num++;
          break;
      }
      if (lcd_eszkoz_num>7) { lcd_eszkoz_num=0;}
      lcd_kijelzo_ido=millis();
    }

 
  /*********************************************************************************************************
   * Ez a programrész 15 másodpercenként végez el egy mérést mindíg más senzoron. a teljes mérési ciklus    *
   * minden eszköz végig mérésével 5x15=75 sec, ennyi időközönként kérdezünk le egy-egy szenzort            *
   *********************************************************************************************************/
  if (millis()>meres_ido+15000)  //15 másodpercenként mindig más eszközből olvassuk ki az aktuális meresi eredményt
  {
    switch (eszkoz_num) {
      case 0:   //külső hőmérséklet, páratartalom és légnyomás mérés és értékek kijelzés előkészítése
        //Indítunk egy mérést a ds1 dallas chip-en, hogy a következő mérési eszkönél már legyen mért eredményünk
        //Közben eltelik 15 másodperc, elkészül az eredmény a chip-ben, és így várni sem kell 750mses-et az eredméynre delay()-el
        ds1_on=false;
        if (ds1.reset()==1) {    //itt 1-el jelez, ha a reset jelre válaszol egy DS18b20, tehát van a vonalon chip. Ha nincs a vonalon DS18b20, akkor ez 0.
           ds1.skip();           //ezzel azt mondjuk a chip-nek, hogy egyedül van a vonalon, nem adunk meg eszköz címet, mindenképpen csinálja amira utasítást kap
           ds1.write(0x44,1);    //elinditunk egy mérést a chip-ben
           ds1_on=true;         //ezzel jelezzük, hogy elindítottunk egy mérést, 750msec múlva ki lehet olvasni a mért hőmérsékletet
         }
         else {pince_homerseklet=99.9;}  //ds1_on változót nem állítjuk true-ra, így várunk amíg lesz chip a vonalon, 
                                         //a kijelzőn a 99,9 fok jelzi, hogy nincs chip a vonalon

        bme280_lekerdez();
        if (bme280_on)
        {
          //minden tárolt értéknek a 100 szorosát használjuk, mert így majd a végén 100-al osztva újra tizedes értékben
          //kapjuk meg az eredményt (long változót tárolunk, ami nem tud tizedes értéket tárolni, viszont a hőmérséklet
          //tezedes jegyet is tartalmaz. AZ osztást az SD kártyára tároláskor végezzük egységesen minden adatra, azért a
          //páratartalom és a légnyomás esetén is szorzunk 100-al, ott nem kellene egyébként, mert egész értékek.

          if (kulso_homerseklet>-50 and kulso_homerseklet<50) {  //időnként valami fals érték jöhetett be méréskor, mert a napi átalgokban 
                                                                 //vad értékeket tárolt az SD kártya. Ezért a vizsgálat, ha baromság jön be azt 
                                                                 //inkább kihagyom
            multimemo(v_kulso_o,kulso_homerseklet*100);
            multimemo(v_kulso_o_min,kulso_homerseklet*100);
            multimemo(v_kulso_o_max,kulso_homerseklet*100);
            multimemo(0,kulso_homerseklet*100);
            multimemo(1,kulso_homerseklet*100);
            multimemo(2,kulso_homerseklet*100);
          }

          multimemo(v_para_o,paratartalom*100);
          multimemo(v_para_o_min,paratartalom*100);
          multimemo(v_para_o_max,paratartalom*100);
          multimemo(3,paratartalom*100);
          multimemo(4,paratartalom*100);
          multimemo(5,paratartalom*100);

          multimemo(v_legny_o,legnyomas*100);
          multimemo(v_legny_o_min,legnyomas*100);
          multimemo(v_legny_o_max,legnyomas*100);
          multimemo(6,legnyomas*100);
          multimemo(7,legnyomas*100);
          multimemo(8,legnyomas*100);
          szamjegybontas(kulso_homerseklet,0,0); //kulső hőmérséklet karakterképe bitsor0 tömbbe
          szamjegybontas(paratartalom,1,1); //páratartalom karakterképe bitsor1 tömbbe
          szamjegybontas(legnyomas,2,1); //legnyomás karakterképe bitsor2 tömbbe
          eszkoz_num++;
        }
        break;
      case 1:   //pince hőmérséklet
        //Indítunk egy mérést a ds2 dallas chip-en, hogy a következő mérési eszkönél már legyen mért eredményünk
        //Közben eltelik 15 másodperc, elkészül az eredmény a chip-ben, és így várni sem kell 750mses-et az eredméynre delay()-el
        ds2_on=false;
        if (ds2.reset()==1) {    //itt 1-el jelez, ha a reset jelre válaszol egy DS18b20, tehát van a vonalon chip. Ha nincs a vonalon DS18b20, akkor ez 0.
           ds2.skip();           //ezzel azt mondjuk a chip-nek, hogy egyedül van a vonalon, nem adunk meg eszköz címet, mindenképpen csinálja amira utasítást kap
           ds2.write(0x44,1);    //elinditunk egy mérést a chip-ben
           ds2_on=true;         //ezzel jelezzük, hogy elindítottunk egy mérést, 750msec múlva ki lehet olvasni a mért hőmérsékletet
         }
         else {akna_homerseklet_felso=99.9;}  //a ds2_on változót nem állítjuk true-ra, így várunk amíg lesz chip a vonalon, 
                                              //a kijelzőn a 99,9 fok jelzi, hogy nincs chip a vonalon

        // a mérés elindítás a bme280 szenzor kiolvasása előtt történik, itt már csak ki kell olvasni a mért eredményeket
        //ha a mérés indításakor kiderült, hogy nincs a vezetéken dallas chip, akkor nem is olvasunk ki semmit, kihagyjuk az egészet
        //Ezt a ds1_on változó jelzi
        if (ds1_on) {
          ds1.reset();             //kezdjük a kommunikációt
          ds1.skip();              //ezzel azt mondjuk a chip-nek, hogy egyedül van a vonalon, nem adunk meg eszköz címet, mindenképpen csinálja amira utasítást kap
          ds1.write(0xBE);         // Chip memóriájánbak olvasása következik
          for ( byte i=0;i<9;i++) {ds_data[i]=ds1.read();}    
          if ( OneWire::crc8(ds_data,8)!=ds_data[8]) {ds1_crc_hiba=true;pince_homerseklet=88.8;}   //crc hibát a 88,8 fok jelzi
          else {pince_homerseklet=(float) (((ds_data[1]<<8)|ds_data[0])/16.0);ds1_crc_hiba=false;}  //ez egy jó mérési adat
        }
        if (ds1_on and !ds1_crc_hiba)   //ha működik a hűmérő chi, és nincs crc hiba, akkor átalgolunk
        {
          multimemo(v_pince_o,pince_homerseklet*100);
          multimemo(9,pince_homerseklet*100);
        }
        eszkoz_num++;
        szamjegybontas(pince_homerseklet,3,0); //pince hőmérséklet karakterképe bitsor3 tömbbe
      case 2:   //akna hőmérséklet_felso
        //Indítunk egy mérést a ds3 dallas chip-en, hogy a következő mérési eszkönél már legyen mért eredményünk
        //Közben eltelik 15 másodperc, elkészül az eredmény a chip-ben, és így várni sem kell 750mses-et az eredméynre delay()-el
        ds3_on=false;
        if (ds3.reset()==1) {    //itt 1-el jelez, ha a reset jelre válaszol egy DS18b20, tehát van a vonalon chip. Ha nincs a vonalon DS18b20, akkor ez 0.
           ds3.skip();           //ezzel azt mondjuk a chip-nek, hogy egyedül van a vonalon, nem adunk meg eszköz címet, mindenképpen csinálja amira utasítást kap
           ds3.write(0x44,1);    //elinditunk egy mérést a chip-ben
           ds3_on=true;         //ezzel jelezzük, hogy elindítottunk egy mérést, 750msec múlva ki lehet olvasni a mért hőmérsékletet
         }
         else {akna_homerseklet_also=99.9;}  //a ds3_on változót nem állítjuk true-ra, így várunk amíg lesz chip a vonalon, 
                                             //a kijelzőn a 99,9 fok jelzi, hogy nincs chip a vonalon

        //A mérés elindítás a ds1 dallas szenzor kiolvasása előtt történik, itt már csak ki kell olvasni a mért eredményeket
        //Ha a mérés indításakor kiderült, hogy nincs a vezetéken dallas chip, akkor nem is olvasunk ki semmit, kihagyjuk az egészet
        //Ezt a ds2_on változó jelzi
        if (ds2_on) {
          ds2.reset();             //kezdjük a kommunikációt
          ds2.skip();              //ezzel azt mondjuk a chip-nek, hogy egyedül van a vonalon, nem adunk meg eszköz címet, mindenképpen csinálja amira utasítást kap
          ds2.write(0xBE);         // Chip memóriájánbak olvasása következik
          for ( byte i=0;i<9;i++) {ds_data[i]=ds2.read();}    
          if ( OneWire::crc8(ds_data,8)!=ds_data[8]) {ds2_crc_hiba=true;akna_homerseklet_felso=88.8;}   //crc hibát a 88,8 fok jelzi
          else {akna_homerseklet_felso=(float) (((ds_data[1]<<8)|ds_data[0])/16.0);ds2_crc_hiba=false;}  //ez egy jó mérési adat
        }
        if (ds2_on and !ds2_crc_hiba)  //ha működik a hűmérő chi, és nincs crc hiba, akkor átalgolunk
        {
          multimemo(v_aknaf_o,akna_homerseklet_felso*100);
          multimemo(11,akna_homerseklet_felso*100);
        }
        szamjegybontas(akna_homerseklet_felso,5,0); //akna hőmérséklet karakterképe bitsor5 tömbbe
        eszkoz_num++;
        break;
      case 3:   //akna hőmérséklet_alsó
        //Indítunk egy mérést a ds4 dallas chip-en, hogy a következő mérési eszkönél már legyen mért eredményünk
        //Közben eltelik 15 másodperc, elkészül az eredmény a chip-ben, és így várni sem kell 750mses-et az eredméynre delay()-el
        ds4_on=false;
        if (ds4.reset()==1) {    //itt 1-el jelez, ha a reset jelre válaszol egy DS18b20, tehát van a vonalon chip. Ha nincs a vonalon DS18b20, akkor ez 0.
           ds4.skip();           //ezzel azt mondjuk a chip-nek, hogy egyedül van a vonalon, nem adunk meg eszköz címet, mindenképpen csinálja amira utasítást kap
           ds4.write(0x44,1);    //elinditunk egy mérést a chip-ben
           ds4_on=true;          //ezzel jelezzük, hogy elindítottunk egy mérést, 750msec múlva ki lehet olvasni a mért hőmérsékletet
         }
         else {kishaz_homerseklet=99.9;}  //a ds3_on változót nem állítjuk true-ra, így várunk amíg lesz chip a vonalon, 
                                          //a kijelzőn a 99,9 fok jelzi, hogy nincs chip a vonalon

        //A mérés elindítás a ds2 dallas szenzor kiolvasása előtt történik, itt már csak ki kell olvasni a mért eredményeket
        //Ha a mérés indításakor kiderült, hogy nincs a vezetéken dallas chip, akkor nem is olvasunk ki semmit, kihagyjuk az egészet
        //Ezt a ds3_on változó jelzi
        if (ds3_on) {
          ds3.reset();             //kezdjük a kommunikációt
          ds3.skip();              //ezzel azt mondjuk a chip-nek, hogy egyedül van a vonalon, nem adunk meg eszköz címet, mindenképpen csinálja amira utasítást kap
          ds3.write(0xBE);         // Chip memóriájánbak olvasása következik
          for ( byte i=0;i<9;i++) {ds_data[i]=ds3.read();}    
          if ( OneWire::crc8(ds_data,8)!=ds_data[8]) {ds3_crc_hiba=true;akna_homerseklet_also=88.8;}   //crc hibát a 88,8 fok jelzi
          else {akna_homerseklet_also=(float) (((ds_data[1]<<8)|ds_data[0])/16.0);ds3_crc_hiba=false;}  //ez egy jó mérési adat
        }
        if (ds3_on and !ds3_crc_hiba)  //ha működik a hűmérő chi, és nincs crc hiba, akkor átalgolunk
        {
          multimemo(v_aknaa_o,akna_homerseklet_also*100);
          multimemo(10,akna_homerseklet_also*100);
        }
        szamjegybontas(akna_homerseklet_also,4,0); //akna hőmérséklet karakterképe bitsor4 tömbbe
        eszkoz_num++;
        break;
      case 4:   //kisház hőmérséklet
        //A mérés elindítás a ds3 dallas szenzor kiolvasása előtt történik, itt már csak ki kell olvasni a mért eredményeket
        //Ha a mérés indításakor kiderült, hogy nincs a vezetéken dallas chip, akkor nem is olvasunk ki semmit, kihagyjuk az egészet
        //Ezt a ds4_on változó jelzi
        if (ds4_on) {
          ds4.reset();             //kezdjük a kommunikációt
          ds4.skip();              //ezzel azt mondjuk a chip-nek, hogy egyedül van a vonalon, nem adunk meg eszköz címet, mindenképpen csinálja amira utasítást kap
          ds4.write(0xBE);         // Chip memóriájánbak olvasása következik
          for ( byte i=0;i<9;i++) {ds_data[i]=ds4.read();}    
          if ( OneWire::crc8(ds_data,8)!=ds_data[8]) {ds4_crc_hiba=true;kishaz_homerseklet=88.8;}   //crc hibát a 88,8 fok jelzi
          else {kishaz_homerseklet=(float) (((ds_data[1]<<8)|ds_data[0])/16.0);ds4_crc_hiba=false;}  //ez egy jó mérési adat
        }
        if (ds4_on and !ds4_crc_hiba)   //ha működik a hűmérő chi, és nincs crc hiba, akkor átalgolunk
        {
          multimemo(v_kishaz_o,kishaz_homerseklet*100);
          multimemo(v_kishaz_o_min,kishaz_homerseklet*100);
          multimemo(v_kishaz_o_max,kishaz_homerseklet*100);
          multimemo(12,kishaz_homerseklet*100);
          multimemo(13,kishaz_homerseklet*100);
          multimemo(14,kishaz_homerseklet*100);
        }
        szamjegybontas(kishaz_homerseklet,6,0); //kisház hőmérséklet karakterképe bitsor6 tömbbe
        eszkoz_num++;
        break;
   }
    if (eszkoz_num>4) { eszkoz_num=0;}
    meres_ido=millis();
  }
  /**********************************************************************************************************************
   * Ez a programrész 2 másodpercenként már értéket küld az alső hétszegmens kijelző sorra, é az alsó matrix kijelzőre  *
   **********************************************************************************************************************/
  if (millis()>kijelzovaltas_ido+2000) {  //2 másodpercenként váltjuk a kijelző also sorában kijelzett értékeket
    //adatok kijelzőre írása
    digitalWrite(2, LOW); //shift regiszter kimenetek lezárása (latchPin=0)
    shiftOut(4, 3, MSBFIRST, bitsor0[0]);            //külső hőmérséklet szazas
    shiftOut(4, 3, MSBFIRST, bitsor0[1]);            //külső hőmérséklet tizes
    shiftOut(4, 3, MSBFIRST, bitsor0[2]);            //külső hőmérséklet egyes
    shiftOut(4, 3, MSBFIRST, bitsor0[3]);            //külső hőmérséklet tizedes
    switch (kijelzes_num) {
      case 1:   //páratartalom
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00000000);
        lc.setRow(0,3,B00000000);
        lc.setRow(0,4,B00000000);
        lc.setRow(0,5,B00000000);
        lc.setRow(0,6,B00000000);
        lc.setRow(0,7,B00000000);
        lc.setRow(1,0,B00000000);
        lc.setRow(1,1,B00110000);
        lc.setRow(1,2,B00110010);
        lc.setRow(1,3,B00000100);
        lc.setRow(1,4,B00001000);
        lc.setRow(1,5,B00010000);
        lc.setRow(1,6,B00100110);
        lc.setRow(1,7,B00000110);
        shiftOut(4, 3, MSBFIRST, bitsor1[0]);            //páratartalom ezres (mindíg üres)
        shiftOut(4, 3, MSBFIRST, bitsor1[1]);            //páratartalom szazas (mindíg üres)
        shiftOut(4, 3, MSBFIRST, bitsor1[2]);            //páratartalom tizes
        shiftOut(4, 3, MSBFIRST, bitsor1[3]);            //páratartalom egyes
        kijelzes_num++;
        break;
      case 2:   //légnyomás
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00000000);
        lc.setRow(0,3,B11001011);
        lc.setRow(0,4,B00101100);
        lc.setRow(0,5,B00101000);
        lc.setRow(0,6,B00101000);
        lc.setRow(0,7,B11001000);
        lc.setRow(1,0,B00000000);
        lc.setRow(1,1,B00000001);
        lc.setRow(1,2,B00000001);
        lc.setRow(1,3,B01101001);
        lc.setRow(1,4,B01010101);
        lc.setRow(1,5,B01010101);
        lc.setRow(1,6,B01010101);
        lc.setRow(1,7,B01010101);
        shiftOut(4, 3, MSBFIRST, bitsor2[0]);            //légnyomás ezres
        shiftOut(4, 3, MSBFIRST, bitsor2[1]);            //légnyomás szazas
        shiftOut(4, 3, MSBFIRST, bitsor2[2]);            //légnyomás tizes
        shiftOut(4, 3, MSBFIRST, bitsor2[3]);            //légnyomás egyes
        kijelzes_num++;
        break;
      case 3:   //pince hőmérséklet
        //P betű a 0-ás kijelzőre
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00011100);
        lc.setRow(0,3,B00010010);
        lc.setRow(0,4,B00010010);
        lc.setRow(0,5,B00011100);
        lc.setRow(0,6,B00010000);
        lc.setRow(0,7,B00010000);
        lc.setRow(1,0,B00000000);
        //°C felirat az 1-es kijelzőre
        lc.setRow(1,1,B01000110);
        lc.setRow(1,2,B10101001);
        lc.setRow(1,3,B10101000);
        lc.setRow(1,4,B01001000);
        lc.setRow(1,5,B00001000);
        lc.setRow(1,6,B00001001);
        lc.setRow(1,7,B00000110);
        shiftOut(4, 3, MSBFIRST, bitsor3[0]);            //pince hőmérséklet szazas
        shiftOut(4, 3, MSBFIRST, bitsor3[1]);            //pince hőmérséklet tizes
        shiftOut(4, 3, MSBFIRST, bitsor3[2]);            //pince hőmérséklet egyes
        shiftOut(4, 3, MSBFIRST, bitsor3[3]);            //pince hőmérséklet tizedes
        kijelzes_num++;
        break;
      case 4:   //akna hőmérséklet also
        //Akna also felirat 0-as kijzőre
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00110000);
        lc.setRow(0,3,B01001000);
        lc.setRow(0,4,B01001000);
        lc.setRow(0,5,B01111000);
        lc.setRow(0,6,B01001011);
        lc.setRow(0,7,B01001011);
        shiftOut(4, 3, MSBFIRST, bitsor4[0]);            //akna hőmérséklet szazas
        shiftOut(4, 3, MSBFIRST, bitsor4[1]);            //akna hőmérséklet tizes
        shiftOut(4, 3, MSBFIRST, bitsor4[2]);            //akna hőmérséklet egyes
        shiftOut(4, 3, MSBFIRST, bitsor4[3]);            //akna hőmérséklet tizedes
        kijelzes_num++;
        break;
      case 5:   //akna hőmérséklet felso
        //Akna felső felirat 0-as kijzőre
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00110011);
        lc.setRow(0,3,B01001011);
        lc.setRow(0,4,B01001000);
        lc.setRow(0,5,B01111000);
        lc.setRow(0,6,B01001000);
        lc.setRow(0,7,B01001000);
        shiftOut(4, 3, MSBFIRST, bitsor5[0]);            //akna hőmérséklet szazas
        shiftOut(4, 3, MSBFIRST, bitsor5[1]);            //akna hőmérséklet tizes
        shiftOut(4, 3, MSBFIRST, bitsor5[2]);            //akna hőmérséklet egyes
        shiftOut(4, 3, MSBFIRST, bitsor5[3]);            //akna hőmérséklet tizedes
        kijelzes_num++;
        break;
      case 6:   //kisház hőmérséklet
        //H betű a 0-ás kijelzőre
        lc.setRow(0,0,B00000000);
        lc.setRow(0,1,B00000000);
        lc.setRow(0,2,B00010010);
        lc.setRow(0,3,B00010010);
        lc.setRow(0,4,B00011110);
        lc.setRow(0,5,B00011110);
        lc.setRow(0,6,B00010010);
        lc.setRow(0,7,B00010010);
        shiftOut(4, 3, MSBFIRST, bitsor6[0]);            //kisház hőmérséklet szazas
        shiftOut(4, 3, MSBFIRST, bitsor6[1]);            //kisház hőmérséklet tizes
        shiftOut(4, 3, MSBFIRST, bitsor6[2]);            //kisház hőmérséklet egyes
        shiftOut(4, 3, MSBFIRST, bitsor6[3]);            //kisház hőmérséklet tizedes
        kijelzes_num++;
        break;
    }
    digitalWrite(2, HIGH);  //beléptetett érték kiengedése a shiftregiszter kimenetére (latchPin=1)
    if (kijelzes_num>6) { kijelzes_num=1;}
    kijelzovaltas_ido=millis();
  } 

  
  /*****************************************************************************************************************
   *  Óránként egy alkalommal átküldjük a slave-nak a mért eredményeket (min és max értékkel)
   *  Ha sikerült az átküldés után feltételezzük, hogy sikerült az írás az SD kártyára, és nullázzuk
   *  az átlagértékek segéd változói (összeg és mérésszám). Ha nem volt SD írási hiba, akkor megjegyezzük
   *  az utolsó sd írás időpontját, ha volt hiba akkor a hiba tényét (utolso_nap_iras változóba).
   *****************************************************************************************************************/
  //óránként egyszer átküldjük az órás átlag adatokat a slavenak. Küldés után utan töröljük a változókat, hogy ujra kezdődhessen az átlagolás
  if (perc==0 and masodperc<10 and tarolas)  
  //if (masodperc<10 and tarolas)  
  {
    adatkuldes(0);
    tarolas=false;
    //töröljuk az orankénti átlagoláshoz használt FRAM cellákat
    multimemo(v_kulso_o,AVG);
    multimemo(v_kulso_o_min,MIN);
    multimemo(v_kulso_o_max,MAX);
    multimemo(v_para_o,AVG);
    multimemo(v_para_o_min,MIN);
    multimemo(v_para_o_max,MAX);
    multimemo(v_legny_o,AVG);
    multimemo(v_legny_o_min,MIN);
    multimemo(v_legny_o_max,MAX);
    multimemo(v_pince_o,AVG);
    multimemo(v_aknaa_o,AVG);
    multimemo(v_aknaf_o,AVG);
    multimemo(v_kishaz_o,AVG);
    multimemo(v_kishaz_o_min,MIN);
    multimemo(v_kishaz_o_max,MAX);
    if (sd_hiba==0)
    {
      //összeállítjuk az utolsó nap file dátumának szövegét az LCD-n történő kiíráshoz
      if (Clock.getHour(h12, PM)<10) {str_tmp="0"+String(Clock.getHour(h12, PM))+":";} else {str_tmp=String(Clock.getHour(h12, PM))+":";}
      if (Clock.getMinute()<10) {str_tmp=str_tmp+"0"+String(Clock.getMinute())+":";} else {str_tmp=str_tmp+String(Clock.getMinute());}
      //if (Clock.getSecond()<10) {str_tmp=str_tmp+"0"+String(Clock.getSecond());} else {str_tmp=str_tmp+String(Clock.getSecond());}
      utolso_nap_iras="  Nap file:"+str_tmp;
    }
    else
    {
      utolso_nap_iras="Nap file:SD error";
    }
  }

 
  /*****************************************************************************************************************
   *  Minden nap 23.50-kor átküldjük a slave-nak a mért eredményeket (min és max értékkel)
   *  Ha sikerült az átküldés után feltételezzük, hogy sikerült az írás az SD kártyára, és nullázzuk
   *  az átlagértékek segéd változói (összeg és mérésszám). Ha nem volt SD írási hiba, akkor megjegyezzük
   *  az utolsó sd írás időpontját, ha volt hiba akkor a hiba tényét (utolso_ev_iras változóba).
   *****************************************************************************************************************/
  if ((ora==23 and perc==59) and masodperc<10 and tarolasnap)  
  //if ((perc==35) and masodperc<10 and tarolasnap)  
  {
    adatkuldes(1);
    long szam=multimemo(0);multimemo(30,szam);
    szam=multimemo(1);multimemo(31,szam);
    szam=multimemo(2);multimemo(32,szam);
    tarolasnap=false;
    //töröljuk az naponkénti átlagoláshoz használt FRAM cellákat
    multimemo(0,AVG);
    multimemo(1,MIN);
    multimemo(2,MAX);
    multimemo(3,AVG);
    multimemo(4,MIN);
    multimemo(5,MAX);
    multimemo(6,AVG);
    multimemo(7,MIN);
    multimemo(8,MAX);
    multimemo(9,AVG);
    multimemo(10,AVG);
    multimemo(11,AVG);
    multimemo(12,AVG);
    multimemo(13,MIN);
    multimemo(14,MAX);
    if (sd_hiba==0)
    {
      //összeállítjuk az utolsó év file dátumának szövegét az LCD-n történő kiíráshoz
      if (Clock.getHour(h12, PM)<10) {str_tmp="0"+String(Clock.getHour(h12, PM))+":";} else {str_tmp=String(Clock.getHour(h12, PM))+":";}
      if (Clock.getMinute()<10) {str_tmp=str_tmp+"0"+String(Clock.getMinute())+":";} else {str_tmp=str_tmp+String(Clock.getMinute());}
      //if (Clock.getSecond()<10) {str_tmp=str_tmp+"0"+String(Clock.getSecond());} else {str_tmp=str_tmp+String(Clock.getSecond());}
      utolso_ev_iras="  Ev file: "+str_tmp;
    }
    else
    {
      utolso_ev_iras="Ev file:SD error";
    }
  } 

}


/***************************************************************************************
 * Csak 32 byte-ot lehet egyszerre egy menetben átvinni, a következő beyte-ok sérülnek *
 * nem tudom miért. Ezért két menetre bontottam az órás illetve a napi átlag küldésétt *
 * status a legelso byte:     1-datum idő átvitel 7 byte
 *                            2-az órás adatok 1 mért adatok 30 byte
 *                            3-az órás adatok 2 mért adatok 30 byte
 *                            4-a napi mért adatok 1 30 byte
 *                            5-a napi mért adatok 2 30 byte
 * elősször mindig a dátumot és az időt, és utánna az órás vagy napi mért adaokat küldöm át                           
 ***************************************************************************************/
void adatkuldes(bool allomany)
{
    
//    Serial.println("kuldes");
  Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
  Wire.write(1);
  Wire.write(ev);
  Wire.write(ho);
  Wire.write(nap);
  Wire.write(ora);
  Wire.write(perc);
  Wire.write(masodperc);
  Wire.endTransmission();     // vége az átvitelnek
  if (allomany==0)
  {
    kuldendo1=multimemo(v_kulso_o);
    kuldendo2=multimemo(v_kulso_o_min);
    kuldendo3=multimemo(v_kulso_o_max);
    kuldendo4=multimemo(v_para_o);
    kuldendo5=multimemo(v_para_o_min);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(2);
    kuld_4byte(kuldendo1);  //100-al már szorozunk a tároláskor, és most az átküldéskor is 100-al kéne, így most nem szorzunk, de nem is osztunk
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4); 
    kuld_4byte(kuldendo5); 
    Wire.endTransmission();     // vége az átvitelnek
    /**********************************************************/
    kuldendo1=multimemo(v_para_o_max);
    kuldendo2=multimemo(v_legny_o);
    kuldendo3=multimemo(v_legny_o_min);
    kuldendo4=multimemo(v_legny_o_max);
    kuldendo5=multimemo(v_kishaz_o);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(3);
    kuld_4byte(kuldendo1);
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4);
    kuld_4byte(kuldendo5);
    Wire.endTransmission();     // vége az átvitelnek
    /**********************************************************/
    kuldendo1=multimemo(v_kishaz_o_min);
    kuldendo2=multimemo(v_kishaz_o_max);
    kuldendo3=multimemo(v_aknaa_o);
    kuldendo4=multimemo(v_aknaf_o);
    kuldendo5=multimemo(v_pince_o);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(4);
    kuld_4byte(kuldendo1);
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4);
    kuld_4byte(kuldendo5);
  }
  else
  {
    kuldendo1=multimemo(0);
    kuldendo2=multimemo(1);
    kuldendo3=multimemo(2);
    kuldendo4=multimemo(3);
    kuldendo5=multimemo(4);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(5);
    kuld_4byte(kuldendo1);  //100-al már szorozunk a tároláskor, és most az átküldéskor is 100-al kéne, így most nem szorzunk, de nem is osztunk
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4); 
    kuld_4byte(kuldendo5); 
    Wire.endTransmission();     // vége az átvitelnek
    /**********************************************************/
    kuldendo1=multimemo(5);
    kuldendo2=multimemo(6);
    kuldendo3=multimemo(7);
    kuldendo4=multimemo(8);
    kuldendo5=multimemo(12);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(6);
    kuld_4byte(kuldendo1);
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4);
    kuld_4byte(kuldendo5);
    Wire.endTransmission();     // vége az átvitelnek
    /**********************************************************/
    kuldendo1=multimemo(13);
    kuldendo2=multimemo(14);
    kuldendo3=multimemo(10);
    kuldendo4=multimemo(11);
    kuldendo5=multimemo(9);
    Wire.beginTransmission(8);  // elindít a master egy átvitelt a 8 című slave felé
    Wire.write(7);
    kuld_4byte(kuldendo1);
    kuld_4byte(kuldendo2);
    kuld_4byte(kuldendo3);
    kuld_4byte(kuldendo4);
    kuld_4byte(kuldendo5);
  }
  Wire.endTransmission();     // vége az átvitelnek
  delay(50); //várunk 50msec-et, hogy a slave befejezhesse az SD írást, és kiderüljön sikerült-e
  Wire.requestFrom(8,1);      // a master kér 1 byte-ot a slave-től
  sd_hiba= Wire.read();       //beolvassuk a slave által küldött byte-ot    
}

void kuld_4byte(long kuldendo)
{
    byte out1=(kuldendo & 0xFF);
    byte out2=((kuldendo >> 8) & 0xFF);
    byte out3=((kuldendo >> 16) & 0xFF);
    byte out4=((kuldendo >> 24) & 0xFF);
    Wire.write(out1);               
    Wire.write(out2);
    Wire.write(out3);
    Wire.write(out4);
}


/****************************************************************************************************
 * Ha óra beállításkor nyomva tartja a nyomógombot, akkor folyamatosan számoltatja felfelé 
 * az éppen beállított adat értékét. Ha elérte a maximumot, akkor nullázza az értéket.
 ****************************************************************************************************/
byte ertekporgetes(byte o_ert, byte o_min, byte o_max)
{
  do
  {
    wdt_reset(); //alaphelyzetbe állítjuk a a watcdog timer-t. Erre itt is szükség van, különben az óra beállítás
                 //alatt is resetet generál a watchdog, mert a fő ciklus nem fut miközben ebben a függvényvben tartozkodik
                 //a program
    o_ert=o_ert+1;setup_num_novel=LOW;
    if (o_ert>o_max) {o_ert=o_min;}
    lcd.setCursor(9,1); 
    if (setup_num==8)
    {
      switch (o_ert) 
      {
        case 1:
          lcd.print("Hetfo");break;
        case 2:
          lcd.print("Kedd ");break;
        case 3:
          lcd.print("Szerd");break;
        case 4:
          lcd.print("Csut ");break;
        case 5:
          lcd.print("Pent ");break;
        case 6:
          lcd.print("Szomb");break;
        case 7:
          lcd.print("Vasar");break;
      }
    } 
    else
    {
      lcd.print(String(o_ert)+"  ");
    }
    delay(700);
  } while (digitalRead(10)==LOW);
  return o_ert;
} 


/****************************************************************************************************
 * Ez a funkció 4 byte-ból csinál egy long változót és visszadja az eredményt
 ****************************************************************************************************/
long byteToLong(long inp1, long inp2, long inp3, long inp4)
{
  //4 byte long változóvá alakítása
  return ((inp1 << 0) & 0xFF) + ((inp2 << 8) & 0xFFFF) + ((inp3 << 16) & 0xFFFFFF) + ((inp4 << 24) & 0xFFFFFFFF);
}

/****************************************************************************************************
 * inicializálja és lekérdezi a BME280 senzort. Ha a senzor inicializálása nem sikerül
 * akkor a függvény újbóli meghívásakor ismét megkisérli az inicializálást, Ha sikerül, akkor 
 * rögtön mér is egyet.
 * Ha már inincializálva van, akkor csak mér. Ha közben megszakad a BME280-al a kapcsolat
 * akkor a hőmérséklet lekérdezés -145.75 fokod ad vissza tapasztalatom szerint, ezért ekkor
 * a mérési eredméynek hamisak, és legközelebb újra megpróbáljuk inicializálni
 ****************************************************************************************************/
void bme280_lekerdez()
{
  if (!bme280_on)
  {
    if (bme.begin(0x76, &Wire)) 
    {         
      bme280_on=HIGH;  //bme280 inicializálása sikerült
      //rögtön mérünk is egyet
      kulso_homerseklet=bme.readTemperature();
      paratartalom=bme.readHumidity();
      legnyomas=bme.readPressure()/100; 
    } 
    else
    {
      kulso_homerseklet=99.9;paratartalom=99;legnyomas=0; 
    }
  }
  else
  {
    kulso_homerseklet=bme.readTemperature();
    paratartalom=bme.readHumidity();
    legnyomas=bme.readPressure()/100; 
    if (kulso_homerseklet<-100) 
    {
      bme280_on=LOW;  //ha nincs bme280 csatlakoztatva, akkor -145 fokot ad vissza, legközelebb megpróbáljuk ujra inincializálni
      kulso_homerseklet=99.9;paratartalom=99;legnyomas=0;
    }
  }
}

/****************************************************************************************************
 * Megméri az A6 bemenetre kötött fototrnzisztor és ellenállásosztóban az ellenállás 
 * feszültségét. Ellenállás értéke 1Kohm. A fototranzisztor kb 5000Lux, nál teljesen kinyit
 * ekkor az ellenálláson közel 5V feszültség mérhető. Sötétben a feszültség 0V
 ****************************************************************************************************/
void fenyero_beallitas(){
    int ledmatfeny=0;
    int hszegfeny=0;
    for (byte j=9;j>0;j--) {mert_fenyero[j]=mert_fenyero[j-1];}
    int fenyero=analogRead(A6);
    mert_fenyero[0]=fenyero;
    fenyertek=(mert_fenyero[0]+mert_fenyero[1]+mert_fenyero[2]+mert_fenyero[3]+mert_fenyero[4]+mert_fenyero[5]+mert_fenyero[6]+mert_fenyero[7]+mert_fenyero[8]+mert_fenyero[9])/10;
    if (fenyertek<=20) {hszegfeny=245;ledmatfeny=0;}
    if (fenyertek<=40 & fenyertek>20) {hszegfeny=245;ledmatfeny=1;}  
    if (fenyertek<=70 & fenyertek>40) {hszegfeny=220;ledmatfeny=2;}  
    if (fenyertek<=110 & fenyertek>70) {hszegfeny=198;ledmatfeny=3;}  
    if (fenyertek<=150 & fenyertek>110) {hszegfeny=175;ledmatfeny=4;}  
    if (fenyertek<=180 & fenyertek>150) {hszegfeny=158;ledmatfeny=5;}  
    if (fenyertek<=230 & fenyertek>180) {hszegfeny=140;ledmatfeny=6;}  
    if (fenyertek<=285 & fenyertek>230) {hszegfeny=123;ledmatfeny=7;}  
    if (fenyertek<=320 & fenyertek>285) {hszegfeny=105;ledmatfeny=8;}  
    if (fenyertek<=380 & fenyertek>320) {hszegfeny=88;ledmatfeny=9;}  
    if (fenyertek<=440 & fenyertek>380) {hszegfeny=70;ledmatfeny=10;}  
    if (fenyertek<=500 & fenyertek>440) {hszegfeny=53;ledmatfeny=11;}  
    if (fenyertek<=560 & fenyertek>500) {hszegfeny=35;ledmatfeny=12;}  
    if (fenyertek<=630 & fenyertek>560) {hszegfeny=24;ledmatfeny=13;}  
    if (fenyertek<=700 & fenyertek>630) {hszegfeny=12;ledmatfeny=14;}  
    if (fenyertek>700) {hszegfeny=0;ledmatfeny=15;} 
    analogWrite(5,hszegfeny);
    // fényerő beállítás 0 minimum, 15 maximum 
    lc.setIntensity(0,ledmatfeny);lc.setIntensity(1,ledmatfeny);
    lc.setIntensity(2,ledmatfeny);lc.setIntensity(3,ledmatfeny);
} 


/****************************************************************************************************
 * A függvénynek átadott számértéket annak típusától függően feldolgozza és bitsorozattá
 * alakítja a 74HC595 IC-be történő beléptetéshez. MInden szenzor által mért adatnak külön
 * tömbbe kerülnek az adatai. A légnyomás és a páratartalom csak egész érték lehet, a többi
 * tizedes, tehát a tizedespontot is ki be kell kapcsolni. A vezető nullákat kioltja és
 * kirakja a minusz jelet is
 ****************************************************************************************************/
void szamjegybontas(float szamertek,int ertekindex, int egeszertek){
/*ez a függvány a mérési eredményt négy számjegyre bontja a 7 szegmenses LED kijelzőkbe léptetéses formában
  átvett változók jelentése:
    szamertek : az átalakításra váró mért érték
    ertekindex : az er edmény tárolására szolgáló tömb indexe
    egeszertek : ha értéke 1, akkor lénynomás vagy páratartalom értékét kell átalakítani, ami csak pozitív szám lehet, és nem kell tizedesjegy kijelzés
  Az indexértékkel kiválasztott nevű tömböt tölt a számjegyek bitképével. A tömbök nevei: bitsor0=külső hőmérséklet.....
  A tömbök indexértékeinek jelentése:
    bitsorX[0] -> balrol az első számjegy
    bitsorX[1] -> balrol az második számjegy
    bitsorX[2] -> balrol az harmadik számjegy
    bitsorX[3] -> balrol az negyedik számjegy
  amennyiben a kijelzésre kerülő számjegy nagyobb mint 100 (ez a légnyomás érék), előjel kijelzés nem lehetséges és nincs tizedes érték
  amennyiben a kijelzére kerülő szám egyjegyű, a vezető nullát kioltjuk, illetve helyére kerül a minuszjel ha van. */ 
  float eszamertek=szamertek; //eredeti szamertek tárolására
  float proba;
  int tizedes;
  int ezres=0;    
  int szazas=0;
  int tizes=0;
  int egyes=0;
  boolean tizedespont=false;
  if (egeszertek==1) {  //ez csak a legnyomás lehet vagy paratartalom
    ezres=szamertek/1000;
    szazas=(szamertek-(ezres*1000))/100;
    tizes=(szamertek-(ezres*1000)-(szazas*100))/10;
    egyes=szamertek-(ezres*1000)-(szazas*100)-(tizes*10);
    if (szamertek<100) {  szazas=10;} //vezető nulla kioltása az szazas számjegyben
    if (szamertek<1000) { ezres=10;} //vezető nulla kioltása az ezres szamjegyben
  }
  else {  //az átalakítandó szám lehet pozitiv és negatív, és tizedesjegy értéket kell kijelezni
    if (szamertek<0) {  szazas=11;szamertek=0-szamertek;} else {  szazas=10;}
    tizes=szamertek/10;
    egyes=szamertek-(tizes*10);
    //vezető nullák kioltása (az 10-es érték üres kijelzés), illetve minusz előjel (11-es érték minusz jel)
    if (tizes==0 && eszamertek>=0) {  tizes=10;}
    if (szamertek<10 && eszamertek<0) { tizes=11;szazas=10;} //minusz előjel berakása a százas helyett a tizesbe
    proba=(szamertek-(int)szamertek);
    proba=(proba*10)+0.001;
    tizedes=(int)proba;
    tizedespont=true;
  }
  switch (ertekindex) {
    case 0:   //0 - külső hőmérséklet 
      bitsor0[0]=karakterkep[szazas];
      bitsor0[1]=karakterkep[tizes];
      bitsor0[2]=karakterkep[egyes]|B00000100;
      bitsor0[3]=karakterkep[tizedes];
      break;
    case 1:   //1 - páratartalom
      bitsor1[0]=karakterkep[ezres];
      bitsor1[1]=karakterkep[szazas];
      bitsor1[2]=karakterkep[tizes];
      bitsor1[3]=karakterkep[egyes];
      break;
    case 2:   //2 - légnyomás
      bitsor2[0]=karakterkep[ezres];
      bitsor2[1]=karakterkep[szazas];
      bitsor2[2]=karakterkep[tizes];
      bitsor2[3]=karakterkep[egyes];
      break;
    case 3:   //3 - pince hőmérséklet
      bitsor3[0]=karakterkep[szazas];
      bitsor3[1]=karakterkep[tizes];
      bitsor3[2]=karakterkep[egyes]|B00000100;
      bitsor3[3]=karakterkep[tizedes];
      break;
    case 4:   //4 - akna hőmérséklet
      bitsor4[0]=karakterkep[szazas];
      bitsor4[1]=karakterkep[tizes];
      bitsor4[2]=karakterkep[egyes]|B00000100;
      bitsor4[3]=karakterkep[tizedes];
      break;
    case 5:   //5 - kisház hőmérséklet
      bitsor5[0]=karakterkep[szazas];
      bitsor5[1]=karakterkep[tizes];
      bitsor5[2]=karakterkep[egyes]|B00000100;
      bitsor5[3]=karakterkep[tizedes];
      break;
    case 6:   //5 - kisház hőmérséklet
      bitsor6[0]=karakterkep[szazas];
      bitsor6[1]=karakterkep[tizes];
      bitsor6[2]=karakterkep[egyes]|B00000100;
      bitsor6[3]=karakterkep[tizedes];
      break;
  } 
}

long multimemo(byte cim) {
/***************************************************************************************************************
 * Ez a multimemo függvény akkor hívódik meg, ha csak egyetlen paramétert adtunk meg a függvény                *
 * meghívásakor (csak olvasni akarunk a tároló cellából)                                                       *
 * A három paraméteres multimemo függvényt hívja meg, de default értékkel tölti fel a maradék két paramétert   *
 * A megadott tároló cella címről adtot fogunk olvasni.                                                        *
 ***************************************************************************************************************/
  long adat=0;
  bool iras=0;
  return(multimemo(cim,adat,iras));
}


long multimemo(byte cim, long adat) {
/***************************************************************************************************************
 * Ez a multimemo függvény akkor hívódik meg, ha két paramétert adunk meg, a cella címét és a beírandó         *
 * adatot, vagyis írni akarunk a cellába. A tároló cella formázását és alaphelyzetbe állítását végző           *
 * két paraméteres multimemo függvénytől az különbözteti meg, hogy ennek második paramétere long típusú.       *
 * A három paraméteres multimemo függvényt hívja meg, de a harmadik paramétert (iras vagy olvasás) default     *
 * értékkel tölti fel (iras=1, azaz írunk). A megadott tároló cella címébe fogjuk az adtot beírni.             *
 ***************************************************************************************************************/
  bool iras=1;
  return(multimemo(cim,adat,iras));
}

long multimemo(byte cim, long adat, bool iras) {
/*****************************************************************************************************************************************************************
 * Ez a multimemo függvény akkor hívódik meg, ha három paraméterrel hívjuk. Ez végzi a tárolandó adat feldolgozását, tárolását, és visszaadja az eredményt       *  
 * visszatérő értékként. A tároló cella típusát az első tárolt byte adja meg, ezt az a multimemo függvény írja, melynek két paramétere van, és a második         *
 * cella_tipus (enum-al definiált felsorolás) típusú adatot vár.                                                                                                 *
 * A függvény bemenő paraméterei:                                                                                                                                *
 *    cim: 0-73 memória cella, egy cella 7 byte,                                                                                                                 *
 *    adat: long típusú 4 byte-os adat, amit beírunk a kijelölt memória cellába                                                                                  *
 *    iras: ez mondja meg, hogy írunk vagy olvasunk a tároló cellából. 0-olvasunk, 1-írunk                                                                       *
 * A tároló cella szerkezete:                                                                                                                                    *
 *    0. byte típus: 0=minimum cella, 1=maximum cella, 2=summa cella, 3=átlag cella, 4=tároló cella                                                              *
 *    1-4. byte adat long adattípus, ez a tényleges tárolt long adat 4 byte-on                                                                                   *
 *    5-6. byte átlag esetén az összegzett adatok száma int adattípusú Csak az átlagoló tároló cella használja, ebben számolja az írások számát.                 *
 *****************************************************************************************************************************************************************/
  int xcim=cim*7;
  byte page=0;
  byte adat0;
  byte adat1;
  byte adat2;
  byte adat3;
  if (xcim<256) {page=0;} else {page=1;xcim=xcim-256;}
  Wire.beginTransmission(_i2cAddress | (page&1));
  Wire.write(xcim);
  Wire.endTransmission(); 
  Wire.requestFrom(_i2cAddress | (page&1),7);
  byte xtipus=Wire.read();  //elkérjük az első byte-ot, ami a tárolt dat típusát adja meg
  long xadat=long(Wire.read()) | long(Wire.read())<<8 | long(Wire.read())<<16 | long(Wire.read())<<24 ; //elkérjük és betöltjük az adat aktuális értékét
  int xdb=int(Wire.read()) | int(Wire.read())<<8;  //elkérjük és betöltjük az adatok számát
  
  if (iras==0 and xtipus!=3) {return(xadat);}  //ha olvasás és nem átlagot kértünkvolt a művelet, akkor visszadjuk a kiolvasott long értéket
  if (iras==0 and xtipus==3) {if (xdb>0) {return((long)(xadat/xdb));} else {return(0);}}  //ha olvasás és átlagot kértünk, akkor osztani is kell, de csak ha xdb nem 0
  
  if (xtipus==0 and iras==1){ //ha írás és minimum cella
      if (xadat>adat) { //csak akkor írjuk be az új adatot, ha az eddig tárolt adatnál kissebb
        multimemo_adatiras(page,xcim,adat); //visszaírjuk az új adatot a tároló cellába
        return(adat);
      }
      else {return(xadat);} //visszadjuk a cellában tárolt minimum értéket
    }  
      
  if (xtipus==1 and iras==1){  //ha írás és maximum cella
      if (xadat<adat) {  //csak akkor írjuk be az új adatot, ha az eddig tárolt adatnál nagyobb
         multimemo_adatiras(page,xcim,adat); //visszaírjuk az új adatot a tároló cellába
        return(adat);
      }
      else {return(xadat);} //visszadjuk a cellában tárolt maximum értéket
    }  
      
  if (xtipus==2 and iras==1){  //ha írás és summa cella
    adat=xadat+adat;  //összeadjuk az új adatot ez eddig beírt adatok (tárolt) összegével
    multimemo_adatiras(page,xcim,adat);  //visszaírjuk az új adatot a tároló cellába
    return(adat); //visszadjuk az új cella értéket
  } 

  if (xtipus==3 and iras==1){  //ha írás és átlag cella
    adat=xadat+adat;  //összeadjuk az új adatot ez eddig beírt adatok (tárolt) összegével
    xdb=xdb+1; //növeljük a beírások számát 1-el
    Wire.beginTransmission(_i2cAddress | (page&1));Wire.write(xcim+1); //a cella első byte-ját már nem kell írni, azt beállított a cella reset, azért cim+1-től írunk
    Wire.write(adat & 0xFF);Wire.write((adat>>8) & 0xFF);Wire.write((adat>>16) & 0xFF);Wire.write((adat>>24) & 0xFF); //beírjuk az új összegzett adatot
    Wire.write(xdb & 0xFF);Wire.write((xdb>>8) & 0xFF);  //beírjuk az írások számát
    Wire.endTransmission(); 
    return((long)(adat/xdb));  //visszadjuk az új átlag értéket
  } 

  if (xtipus==4 and iras==1){  //ha írás és sima tároló cella
    multimemo_adatiras(page,xcim,adat);
    return(adat);
  } 
}

void multimemo_adatiras(byte page, byte xcim, long adat) {
// az átlag cella kivételével mindet ugyanúgy kell beírni, ezért a konkrét írás ebben a közösen használt függvényben lett megvalósítva
  Wire.beginTransmission(_i2cAddress | (page&1));Wire.write(xcim+1); //a cella első byte-ját már nem kell írni, azt beállított a cella reset, azért cim+1-től írunk
  Wire.write(adat & 0xFF);Wire.write((adat>>8) & 0xFF);Wire.write((adat>>16) & 0xFF);Wire.write((adat>>24) & 0xFF);
  Wire.endTransmission(); 
}

long multimemo(byte cim, cella_tipus tipus) {
/*******************************************************************************************************************************************************************  
 * Ez a multimemó függvény akkor hívódik meg, ha két paraméterrel hívjuk, és a második cella_tipus típusú változó, amit enum-al hoztunk létre a program elején.    *
 * A függvény elvégzi egy cella típusának beállítását (a cella első byte-ja), és alaphelyzetbe állítja a tárolt adatokat.                                          *
 * Bemenő paraméterek:                                                                                                                                             *
 *    cim: 0-73 db memória cella, egy cella 7 byte,                                                                                                                *
 *    típus: felsorolás típusú (enum) paraméter, ami meghatározza a cella tárolási módját. Lehetséges értékei 0-4 között.                                          *
 * Típus által képzett cella típusok, és azok tárolási módja, az elvégzett műveletek leírása:                                                                      *
 *  MIN: Az íráskor megkapott adatot csak akkor tárolja, ha az kissebb mint az éppen tárolt adat. Mielőtt elkezdjük a minimumot gyüjteni, be kell írni             *
 *       a lehető legnagyobb long értéket, különben nem biztos, hogy megjegyzi a legelső értéket. A számláló cellarészt nem használja.                             *
 *  MAX: Az íráskor megkapott adatot csak akkor tárolja, ha az nagyobb mint az éppen tárolt adat. Mielőtt elkezdjük a maximumott gyüjteni, be kell írni            *
 *       a lehető legkissebb long értéket, különben nem biztos, hogy megjegyzi a legelső értéket.                                                                  *
 *  SUM: Képzi a beírt adatok összegét. Alapértelmezetten a tartalma 0.                                                                                            *
 *  AVG: képzi a beírt adatok átlagát. Minden beít értéket szummáz az adat mezőben, számolja a beírások számát, és kiolvasáskor osztja az adatot a beírás számmal  *
 *       Alpértelmezetten az adat és a számláló is 0.                                                                                                              *
 *  STO: csak úgy simán tárolja az adatot, nem csinál vele semmit, ha volt bent előtte adat, azt felülírja. Alepértelmezett tartalma 0.                            *
 *******************************************************************************************************************************************************************/
  int xcim=cim*7;
  byte page;
  if (xcim<256) {page=0;} else {page=1;xcim=xcim-256;}
  Wire.beginTransmission(_i2cAddress | (page&1));
  Wire.write(xcim);
  if (tipus==MIN){
      // 2147483647 kezdő értéket írunk a tároló cellába, mert nincs nagyobb szám long esetén, így csak ennél kisebbek jöhetnek.
      Wire.write(0);Wire.write((long)2147483647 & 0xFF);Wire.write(((long)2147483647>>8) & 0xFF);Wire.write(((long)2147483647>>16) & 0xFF);Wire.write(((long)2147483647>>24) & 0xFF);
      Wire.write(0);Wire.write(0);
      Wire.endTransmission(); 
      return(0);
    }    
  if (tipus==MAX){
      // -2147483648 kezdő értéket írunk a tároló cellába, mert nincs kisebb szám long esetén, így csak ennél kisebbek jöhetnek.
      Wire.write(1);Wire.write((long)-2147483648 & 0xFF);Wire.write(((long)-2147483648>>8) & 0xFF);Wire.write(((long)-2147483648>>16) & 0xFF);Wire.write(((long)-2147483648>>24) & 0xFF);
      Wire.write(0);Wire.write(0);
      Wire.endTransmission(); 
      return(0);
    }    
  if (tipus==SUM or tipus==AVG or tipus==STO) {
      //össegző mező esetén csak simán törölni kell mindent
      Wire.write(tipus);Wire.write(0);Wire.write(0);Wire.write(0);Wire.write(0);
      Wire.write(0);Wire.write(0);
      Wire.endTransmission(); 
      return(0);
    }  
    Wire.endTransmission(); 
}

Ennek a programnak a mérete 29948byte, tehát 772 byte maradt szabadon. Azonban a ram számít, mert ebben az esetben már 623byte maradt szabadon. Az a 100byte nem sok, de mégis a teljes ram 5%-a, esetleg számít majd, és kevesebbet kell dolgoznia a watchdog-nak. „Kis lépés az embernek, de nagy lépés…” nekem. Azt már tudom, hogy a ds4 vonalon a crc hibát nem a program és a ram szabad méretének hiánya okozta (lásd később), de hátha mégis számít valamit. Közben míg az átalakításokat csináltam, kiderült hogy a szenzorokkal történő mérések közötti időt valamikor véletlenül 15 másodpercről 1,5 másodpercre állítottam. Nem kizárt, hogy ez sem tetszett a Dallas chip-nek. Valahol olvastam, hogy a túl gyakori mérés problémákat okoz?! Most ismét várakozunk, hogy javult-e valami. Néhány nap!

A slave programja:

/************************************************************
 * Kivezetések felsorolása:
 *  D9 LED error kijelző
 *  D10 SD card CS
 *  D11 SD card MOSI
 *  D12 SD card MISO
 *  D13 SD Card SCK
 *  
 */


//I2C busz kezelése 
#include <Wire.h>

// SD kártya modul programjai és változó deklarációi
//==================================================
#include <SD.h>
Sd2Card card;
File temp_adat;


String str_tmp;
bool oraadat_kesz=LOW;  //ha az I2C-n megérkezik egy óra mérési adata, akkor HIGH értékkel jelzi, hogy lehet SD-re írni
bool napadat_kesz=LOW;  //ha az I2C-n megérkezik egy nap mérési adata, akkor HIGH értékkel jelzi, hogy lehet SD-re írni
byte sd_hiba=1; //ha az sd van és sikerült az iras akkor 0, hiba esetén 1, visszaküldésre kerül masternek
byte erzekelo_hiba=0;  //a master küld jelzést, ha valamelyik érzékelővel hiba van 1=hiba, 0=nincs hiba


long hiba_ellenorzes=millis();  //sd kártya ellenőrzésének időzítéséhez, percenként ellenőrizzük, hogy rendben van-e
long led_villog=millis();
long led_villog_gyors=millis();
bool led_villog1=LOW;
bool led_villog2=LOW;

//az I2C-n érkezett időpont adatok tárolásához
byte ora=0;
byte perc=0;
byte masodperc=0;
byte ev=0;
byte ho=0;
byte nap=0;
//AzI2C-n érkezett adatok tárolásához
float kulso_homerseklet;
float kulso_homerseklet_min;
float kulso_homerseklet_max;
float paratartalom;
float legnyomas;
float pince_homerseklet;
float akna_homerseklet_also;
float akna_homerseklet_felso;
float kishaz_homerseklet;

//segéd változók az I2C adatfogadáshoz
byte fogad1;
byte fogad2;
byte fogad3;
byte fogad4; 

void setup()
{
  pinMode(9,OUTPUT);
  //Serial.begin(9600);
  if (!card.init(SPI_HALF_SPEED, 10)) {
    sd_hiba=1;
  } else {
    sd_hiba=0;
  } 
  delay(100);
  Wire.begin(8);                // I2C kommunikáció inicializálása 8-as eszköz címmel (mivel slave, címet kell megadni)
  Wire.onReceive(slave_fogad);  //Ezt a funkciót hivja az Arduino, amikor adatot kap a mastertől
  Wire.onRequest(slave_kuld);   //Ezt a funkciót hívja meg az Arduino, amikor a master adatot kér a slave-től 
  delay(100);
}

void loop()
{
  if (millis()>hiba_ellenorzes+10000)
  {
    if (!SD.begin(10)) {sd_hiba=1;} else {sd_hiba=0;}
    hiba_ellenorzes=millis();  
  }

  if ((millis()>led_villog+1000) and sd_hiba)
  {
    if (!led_villog1) {led_villog1=HIGH;}
    else {led_villog1=LOW;}
    led_villog=millis();
    //Serial.println(led_villog1);
  }
  if ((millis()>led_villog_gyors+100) and erzekelo_hiba)
  {
    if (!led_villog2) {led_villog2=HIGH;}
    else {led_villog2=LOW;}
    led_villog_gyors=millis();
    //Serial.println(led_villog2);
  }
  if (sd_hiba and erzekelo_hiba) {if (led_villog1) {digitalWrite(9,led_villog2);}}
  if (sd_hiba and !erzekelo_hiba) {digitalWrite(9,led_villog1);}
  if (!sd_hiba and erzekelo_hiba) {digitalWrite(9,led_villog2);}
  if (!sd_hiba and !erzekelo_hiba) {digitalWrite(9,LOW);}
  

  if (oraadat_kesz)
  {
    str_tmp="NP"+String(ev);
    if (ho<10) {str_tmp=str_tmp+"0"+String(ho);} else {str_tmp=str_tmp+String(ho);}
    if (nap<10) {str_tmp=str_tmp+"0"+String(nap)+".CSV";} else {str_tmp=str_tmp+String(nap)+".CSV";}
    if (!SD.begin(10)) {sd_hiba=1;} else {sd_hiba=0;}
    if (!SD.exists(str_tmp)) 
    {
      temp_adat = SD.open(str_tmp, FILE_WRITE);
      temp_adat.println("Datum;Ido;Homerseklet;Homerseklet_min;Homerseklet_max;Paratartalom;Legnyomas;Kishaz;Akna also;Akna felso;Pince;");
    }
    else 
    {  
      temp_adat = SD.open(str_tmp, FILE_WRITE);
    }      
    str_tmp="20"+String(ev)+".";
    if (ho<10) {str_tmp=str_tmp+"0"+String(ho)+".";} else {str_tmp=str_tmp+String(ho)+".";}
    if (nap<10) {str_tmp=str_tmp+"0"+String(nap);} else {str_tmp=str_tmp+String(nap);}
    temp_adat.print(str_tmp+";");
    if (ora<10) {str_tmp="0"+String(ora)+":";} else {str_tmp=String(ora)+":";}
    if (perc<10) {str_tmp=str_tmp+"0"+String(perc)+":";} else {str_tmp=str_tmp+String(perc)+":";}
    if (masodperc<10) {str_tmp=str_tmp+"0"+String(masodperc);} else {str_tmp=str_tmp+String(masodperc);}
    temp_adat.print(str_tmp+";");temp_adat.print(kulso_homerseklet);temp_adat.print(";");
    temp_adat.print(kulso_homerseklet_min);temp_adat.print(";");
    temp_adat.print(kulso_homerseklet_max);temp_adat.print(";");
    temp_adat.print(paratartalom);temp_adat.print(";");
    temp_adat.print(legnyomas);temp_adat.print(";");
    temp_adat.print(kishaz_homerseklet);temp_adat.print(";");
    temp_adat.print(akna_homerseklet_also);temp_adat.print(";");
    temp_adat.print(akna_homerseklet_felso);temp_adat.print(";");
    temp_adat.print(pince_homerseklet);temp_adat.println(";");
    temp_adat.flush();
    temp_adat.close();
    oraadat_kesz=LOW;
  }
  if (napadat_kesz)
  {
    str_tmp="EV20"+String(ev)+".CSV";
    if (!SD.begin(10)) {sd_hiba=1;} else {sd_hiba=0;}
    if (!SD.exists(str_tmp)) 
    {
      temp_adat = SD.open(str_tmp, FILE_WRITE);
      temp_adat.println("Datum;Ido;Homerseklet;Homerseklet_min;Homerseklet_max;Paratartalom;Legnyomas;Kishaz;Akna also;Akna felso;Pince;");
    }
    else 
    {  
      temp_adat = SD.open(str_tmp, FILE_WRITE);
    }      
    str_tmp="20"+String(ev)+".";
    if (ho<10) {str_tmp=str_tmp+"0"+String(ho)+".";} else {str_tmp=str_tmp+String(ho)+".";}
    if (nap<10) {str_tmp=str_tmp+"0"+String(nap);} else {str_tmp=str_tmp+String(nap);}
    temp_adat.print(str_tmp+";");
    if (ora<10) {str_tmp="0"+String(ora)+":";} else {str_tmp=String(ora)+":";}
    if (perc<10) {str_tmp=str_tmp+"0"+String(perc)+":";} else {str_tmp=str_tmp+String(perc)+":";}
    if (masodperc<10) {str_tmp=str_tmp+"0"+String(masodperc);} else {str_tmp=str_tmp+String(masodperc);}
    temp_adat.print(str_tmp+";");temp_adat.print(kulso_homerseklet);temp_adat.print(";");
    temp_adat.print(kulso_homerseklet_min);temp_adat.print(";");
    temp_adat.print(kulso_homerseklet_max);temp_adat.print(";");
    temp_adat.print(paratartalom);temp_adat.print(";");
    temp_adat.print(legnyomas);temp_adat.print(";");
    temp_adat.print(kishaz_homerseklet);temp_adat.print(";");
    temp_adat.print(akna_homerseklet_also);temp_adat.print(";");
    temp_adat.print(akna_homerseklet_felso);temp_adat.print(";");
    temp_adat.print(pince_homerseklet);temp_adat.println(";");
    temp_adat.flush();
    temp_adat.close();
    napadat_kesz=LOW;
  }
}


void slave_fogad ()      
//Ez a fuggvény akkor indul, amikor a slave értesítést kap, hogy a master adatot fog küldeni
{
  //beolvassuk a bevezeto adatokat
  byte R_status=Wire.read(); 
  if (R_status==9) 
  {           
    erzekelo_hiba=Wire.read();
  }
  if (R_status==1) 
  {           
    ev=Wire.read();            
    ho=Wire.read();            
    nap=Wire.read(); 
    ora=Wire.read(); 
    perc=Wire.read(); 
    masodperc=Wire.read();
  }
  if (R_status==2)
  { 
    //jönnek az átlagolt mérési adtok
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    kulso_homerseklet=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    kulso_homerseklet_min=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    kulso_homerseklet_max=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    paratartalom=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
  }
  if (R_status==3)
  { 
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    legnyomas=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    kishaz_homerseklet=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    akna_homerseklet_also=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    akna_homerseklet_felso=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    pince_homerseklet=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    oraadat_kesz=HIGH;
  }
  if (R_status==4)
  { 
    //jönnek az átlagolt mérési adtok
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    kulso_homerseklet=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    kulso_homerseklet_min=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    kulso_homerseklet_max=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    paratartalom=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
  }
  if (R_status==5)
  { 
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    legnyomas=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    kishaz_homerseklet=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    akna_homerseklet_also=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    akna_homerseklet_felso=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    fogad1 = Wire.read();fogad2 = Wire.read();fogad3 = Wire.read();fogad4 = Wire.read();            
    pince_homerseklet=((float)byteToLong(fogad1,fogad2,fogad3,fogad4))/100;
    napadat_kesz=HIGH;
  }

}

void slave_kuld()                             
//Ez a függvény akkor indul, amikor a master adatot kér a slave-től
{ 
    Wire.write(sd_hiba);               
}

long byteToLong(long inp1, long inp2, long inp3, long inp4)
//Ez a funkció 4 byte-ból csinál egy long változót és visszadja az eredményt
{
  //4 byte long változóvá alakítása
  return ((inp1 << 0) & 0xFF) + ((inp2 << 8) & 0xFFFF) + ((inp3 << 16) & 0xFFFFFF) + ((inp4 << 24) & 0xFFFFFFFF);
}


Eddigi tapasztalatok, szívások: Összességében működik az időjárás állomásunk, használható, örülünk neki, de elég sok gond van vele. Eleinte 2-3 naponta lefagyott! A program átnézésekor kiderült, hogy a mátrix kijelzőt rosszul vezérlem. Oszloponként írtam, ami nem optimális. Áttértem a soronkénti írásra, és azóta a lefagyások száma sokat csökkent, de sajnos néhány hetente még most is előfordul. Ezért elkezdtem foglalkoznia watcdog használatával. Sajnos a reset törli a változókat, ezért azt találtam ki, hogy egy külső I2C busszal működő RAM-ban gyújtom az adatokat. Kb. egy hónapja készültem el a megoldással, és az FRAM kezeléséről írtam is egy külön cikket (a közölt forrásban már ezek mind benne vannak). Jelenleg már bármikor reset gombot nyomhatok, és a watchdog is újra indíthat, adat nem veszik el. Az FRAM nagyon jól bevált eddig, élettartama szinte végtelen, nem kell hozzá elemes táplálás, nem felejt kikapcsoláskor sem.

Utólag kiegészítettem a programot még egy állománnyal az SD kártyán, ami ez elindulások számát gyűjti. Szerettem volna látni, hogy a watchdog milyen gyakran indítja újra a programot lefagyás miatt. Még nem tudom az eredményt, mert a program módosítások miatt olyan sokat állítottam le, hogy nem tudom mikor volt a watchdog és mikor én. Elkezdtem ugyan kutakodni, hogy a mikrovezérlő tudja-e magáról, hogy mi volt az újra indulás oka, ki is derült, de jelenleg nem lehet megoldani ennek lekérdezését. A vezérlő ugyan tudja magáról, de bootloader, amit a nano használ, elrejti ezt az információt. Van olyan bootloader verzió, ami elvileg elérhetővé teszi annak a regiszternek a tartalmát, ami az újra indulás okát tárolja, de nincs most időm ennek részletes megismerésére. Ennyire nem fontos kérdés.

Persze maradt még probléma bőven. Az egyik Dallas hőmérő vacakol. Kb 1-2 óra működés után CRC hibát produkál. A reset ekkor segít egy időre, de aztán újra jelentkezik a hiba. Lehetséges, hogy az okozza a bajt, hogy a program már csak cipőkanállal fér be a memóriába. Kb. 400byte van szabadon a flash-ban, és az SRAM is szinte tele van. Ekkor már láthatóan bizonytalan a működés, a lefagyások is ezért vannak tippjeim szerint. Hogy ezt kiderítsem, csináltam egy butított verziót a programból. Mindent kiszedtem, ami nem kell (SD kárta, FRAM, mátrix kijelzők használata stb.), szinte csak a mérések és az LCD kijelző meghajtása maradt. A memória használat 50% alá csökkent. Most várom, mi történik. Ha most napokig nem lesz CRC hiba, akkor már tudom mit kell tennem. Jöhet a dobozban pihenő ATmega alaplap. Abban van memória bőven, nem fogja a stack összerondítani a változókat. Ha ettől nem szűnik meg a hiba, akkor cserélem a Dallas hőmérőt. Jelezni fogom, mi volt a megoldás! (Sajnos nem szűnt meg a hiba, de még nem volt időm kiértékelni az eseményeket. Hobbyból csökkenteni szeretném a program méretét, és ezt a Dallas DS18B20 programrészek átalakításával kezdtem el, már be is írtam tapasztalataimat a szenzor ismertetőjébe, illetve azt, hogyan lehet egyszerűbb a program, ha egyetlen chip van egy Arduino bemeneten. Valószínűleg cserélni fogom a hőmérő chip-et, de épp beköszöntött az esős évszak, várom, hogy jobb idő legyen!)

A fenti sorokhoz megérkezett a még újabb információ! A chip illetve a hozzá vezető adat vezeték korrodálódott el. Tapasztalataim a DS18b20 szenzor leírásának végén!

Továbbfejlesztési terveim is vannak. Szeretnék szélsebességet és csapadékmennyiséget mérni. Mindkettőhöz kapható mérőeszköz marhadrágán. Ezért kísérletezgetek egy pc ventilátorból és alumínium lemezből hajtogatott szélsebesség mérővel. Működik, csak nagyon nagy szélsebességnél indul meg. Legfeljebb valakitől karácsonyra szélsebességmérőt kérek ajándékba. A csapadékmennyiség mérés egyszerűbbnek tűnik, csak ahhoz meg még nem volt időm hozzáfogni! A csapadék mérés azért is fontos, mert az idén belekezdtem egy automata locsolórendszer fejlesztésébe. Ha esik az eső, nem akarok locsolni!

Biztosan feltűnt, hogy a fő kijelzőn nem látszik soha az idő. Ennek oka, hogy az idő kijelzésnél nem akartam a fényerő szabályozással vesződni, ezért ezt a megoldást választottam:

…és szeretném megelőzni a kérdést: nincs több hordóm!!

Sok sikert, ha megépítesz valami hasonlót!

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!