6 számjegyes LCD kijelző

Először egy kis elmélet és múltidézés. Az LCD kijelzők sok évtizedes múlttal rendelkeznek. Az első kvarcórámat 35 évvel ez előtt vásároltam a Keleti Pályaudvar mellett a Baross szobornál. Akkoriban ez volt a paradicsom, ott árulták feketén ezeket a cuccokat! Azóta a szobrot kicsit arrébb helyezték. Ha jól emlékszem 1200Ft volt, évekig spóroltam rá. Hét zenés óra volt, én lettem a legnépszerűbb a gimiben egy hétre. Sorban hallgatták az osztálytársak a pity-pity zenét, így egy hét alatt lemerült az első elem. Egyébként legalább egy évig működött elemcsere nélkül. El sem tudtuk képzelni, hogy azzal az 5mm átmérőjű gombelemmel hogyan működhet az óra ennyi ideig (ha kikapcsolom a pity-pity-et). Ma már tudom, hogy a trükk a kis fogyasztású folyadékkristályos kijelző. A kijelző előlapja üveg és átlátszó, a hátlapja pedig ezüst színű fényvisszaverő anyag. A beeső fényt a hátlap visszaveri és polarizálja. A polarizált fényt pedig kitakarják a két réteg közé „öntött” leheletvékony folyadékkristály rétegben 90 fokban beforduló hosszú molekulák. Nyilván ezek a molekulák csak akkor fordulnak el 90 fokkal, ha feszültséget kapcsolunk rá. Működés közben nem folyik áram, így a kijelző gyakorlatilag nulla fogyasztású. Persze a vezérlő chip azért fogyaszt. Hátrány, hogy a molekulák lassan állnak be a vezérlő feszültség hatására, így videófilmet nem fogunk ezen a kijelzőn nézni. Nagy hidegben látni a szegmensek átkapcsolását, mert nem akar eltűnni a kikapcsolt szegmens. De ettől még igen sok mindenre használható típus.

Vásároltam is egy háttér világításos, 6 karakteres LCD kijelzőt.

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

Automatikusan generált leírás

Forrás: https://www.aliexpress.com/item/32944755027.html?spm=a2g0s.9042311.0.0.27424c4dJP2WTf

Bekapcsolt világítással 4mA az áramfelvétele. Elemmel működő eszközökhöz lesz tökéletes. Egyelőre még csak kísérletezgetek vele. Kipróbáltam, és az Arduino Uno 3,3V tápfeszültségről is tökéletesen működik. Tehát várhatóan 2 ceruza elemről lehet majd táplálni a kütyüt. Talán a három elem jobb, mert az ATmega328 2.7V feszültségig üzemel, és 2.7V-ra gyorsan lemerülhet két ceruzaelem. Ilyenkor még elég sok energia van bennük, pazarlás lenne. Terveim szerint egy konyhai időzítő fog elkészülni belőle, amit elemmel szeretnék táplálni. A kapható konyhai időzítők körülményesek. A legtöbb típuson 2-3 nyomógomb is van, és az időzítési idő beállítása és elindítása egy csomó gombnyomogatás. Nehezen találtam olyat, ahol egy forgatógombbal lehet beállítani az időt, és egy gombnyomással elindítani az időzítést. Amit megvettem, azon meg a gomb forgatása 15 másodperces lépésekben állítja az időt. Nekem ez feleslegesnek tűnik. Kit érdekel, hogy a tojás 10 percig, vagy 10 perc 15 másodpercig fő. Úgy gondolom tudok jobbat, egyszerűbbet csinálni!

A kijelző problémás, mert állandóan be van kapcsolva a világítás. Szerencsére egy forrasztással és ónlehúzással megoldható a probléma. Így néz ki a hátoldala:

Beszédbuborék: lekerekített sarkú téglalap: Leszedni az ónt, vagy elvágni a vezetéket

Ezt követően már a LED+ feliratú kivezetésnek kell tápot adni pl. az Arduino egyik kimenetéről. Az áramör 5V-ra van optimalizálva, vagyis 3V feszültségen lényegesen halványabb a háttér világítás. A fényerő a 100ohm-os soros ellenállás csökkentésével növelhető. Egyedileg kell kipróbálni, szerintem egy 150ohm körüli ellenállást érdemes párhuzamosan forrasztani.

A kijelző működése:
Lényegében egy SPI kommunikációs megoldással tudjuk a kijelzőt vezérelni. A WR bemenet az órajel, a Data az adatvezeték, a CS meg a chip select. A kijelző alatt egy HT1621-es LCD megható áramkör található, ami egy általános LCD meghajtó áramkör család egyik tagja. Van benne egy memória, amiben minden egyes vezérelhető szegmensnek található egy bit. Ha a bit 1, akkor elsötétedik a szegmens, ha meg 0 akkor nem. Ennyire egyszerű. Van tehát parancs, amivel ez a memória írható és olvasható is, és vannak az IC egyéb beállításainak megváltoztatására szolgáló parancsok. Ezek közül néhányat kiemelnék. Az IC képes egy kis hangszóró (buzzer) közvetlen meghajtására. Jelen áramkörben ezt nem vezették ki sajnos, erről a lehetőségről le kell mondanunk. Lehetőség van a szegmens elsötétedését befolyásoló előfeszítő feszültség megváltoztatására. Ha ½ bias értéket állítunk be, akkor sötétebb a bekapcsolt szegmens, de ekkor már azok a szegmensek is szürkék lesznek, melyeknek nem lenne szabad látszaniuk. Ráadásul ha nem szemből nézzük, akkor minden szegmens fekete, és nem látható jól a kijelzett érték. Így én a demó programban beállított alapértelmezett értéknél maradtam. A kijelző egyetlen paranccsal ki és bekapcsolható, azaz kikapcsoláskor eltűnik a kijelzett érték, de a memóriában megmarad. A szegmenseket időszeletekben vezérli, mivel kijelező mátrix rendszerű a működés. Ehhez órajel kell, és többféle órajelet is tud használni a chip, belsőt külsőt egyaránt. Sajnos nem nagyon értem, erre mi szükség lehet, de biztosan oka van. Annak is biztosan oka van, hogy egy watcdog áramkört is beépítettek. Ezt sem értem, hogy mire jó, de átléptem rajta, mert nekem nem kellett! A második táblázat tartalmazza ennek beállítási lehetőségeit.

A részletek iránt érdeklődőknek íme a parancsokat tartalmazó adatlap részlet:

Jelmagyarázat:
X             dont care (bármi lehet)
A5-A0     RAM adress
D3-D4    RAM data
D/C         Data/Command mód
def.         bekapcsoláskor a gyári alapértelmezés

Ebből a halmazból én mindössze kettőt találtam hasznosnak:

LCD kijelzés be és kikapcsolása:
LCD off: 10000000010X
LCD on: 10000000011X

Bias beállítás (a common opció esetünkben nem érdekes, mert a konkrét LCD panel meghajtásához a 4 commons mód szükséges.
BIAS&COM: 1000010abXcX
c=0         1/2 bias
c=1         1/3 bias
ab=00    2 commons option
ab=01    3 commons option
ab=10    4 commons option

Még talán a memória térkép lehet érdekes:

https://www.14core.com/wp-content/uploads/2017/04/7-Segment-6-Digit-LCD-Display-Module-HT621-LCD-Spi-Display-14core-02.jpg

Található hozzá függvény könyvtár több is. Nekem azonban az volt a célom, hogy szegmensenként tudjam vezérelni, így nem volt hasznos egy olyan függvény, ami ki tud írni a kijelzőre egy max. 6 jegyű számot. Ezért a vezérlését az egyik forráskódból visszafejtettem, és magam írtam meg a saját vezérlő függvényeimet. Nagy munka nem kellett hozzá, szinte csak másolgatni kellett. Minimális kommenteket is írtam a programba. A program a setup részben felvillant egy 0-át jobbról az első karakter pozícióban, majd sorban felvillantja az összes karakter minden szegmensét jobbról balra haladva. A működéséből látható, hogy az utolsó három számjegyhez már nem tartozik tizedespont, ezek a jobb felső sarokban látható elem feszültség jelző szimbólumhoz lettek kivezetve. Hasznos lesz, ha az áramkör méri az elem feszültségét és így ki tudjuk jelezni, ha már cserélni kell. Ebből persze az is következik, hogy maximum 3 tizedesjegy pontossággal tudunk számértéket kijelezni. pl. az 1.235 még megy, a 3.5443már nem!

#define CS   13  //Pin 13 lesz a kijelző chip select bementére kötve 
#define WR   12  //Pin 12 lesz a kijelző órajel bemenetére kötve
#define DATA 7  //Pin 7 lesz a kijelző data bemenetére kötve

//HT1621 parancsok
#define  ComMode    0x52  //b01010010  //Ez a jó kijelzés, csak a világító szegmens látszik a kikapcsoltak nem
//#define  ComMode    0x50  //b01010000 //Erősebben világítanak a szegmensek, de oldalról mind látszik, a kikapcsolt is
#define  RCosc      0x30  //b00110000  
#define  LCD_on     0x06  //b00000110  //Bekapcsolja az LCD bias generátort
#define  LCD_off    0x04  //b00000100  //Kikapcsolja az LCD bias generátort
#define  Sys_en     0x02  //b00000010  //Bekapcsolaj a rendszer oszcillátort
#define  CTRl_cmd   0x80  //b10000000
#define  Data_cmd   0xa0  //b10100000

/************* Az egyes karakterek megjelenítéséhez ezeket a kódokat kell kiküldeni a chip-nek*****/
const char num[]={0x7D,0x60,0x3E,0x7A,0x63,0x5B,0x5F,0x70,0x7F,0x7B,0x77,0x4F,0x1D,0x0E,0x6E,0x1F,0x17,0x67,0x47,0x0D,0x46,0x75,0x37,0x06,0x0F,0x6D,0x02,0x00,};
                 //0    1    2    3    4    5    6    7    8    9    10   11   12   13   14   15   16   17   18   19   20   21   22   23   24   25   26   27
                 //0    1    2    3    4    5    6    7    8    9    A    b    C    c    d    E    F    H    h    L    n    N    o    P    r    t    U    -   " "/

void setup() {
  Serial.begin(9600);
  pinMode(CS, OUTPUT);   
  pinMode(WR, OUTPUT); 
  pinMode(DATA, OUTPUT); 
  digitalWrite(CS, HIGH);
  digitalWrite(DATA,HIGH);
  digitalWrite(WR,HIGH);
  delay(50);
  //led meghajtó inicializálás
  SendCmd_1621(Sys_en);
  SendCmd_1621(RCosc);    
  SendCmd_1621(ComMode);  
  SendCmd_1621(LCD_on);

  HT1621_clear();   
  HT1621_Write(0,num[0]);  //0 szám a 1. pozicióban
  delay(1000);
  HT1621_clear();
  HT1621_Write(1,255);  //összes szegmens bekapcs. a 2. pozicióban
  delay(1000);
  HT1621_clear();
  HT1621_Write(2,255);  //összes szegmens bekapcs. a 3. pozicióban
  delay(1000);
  HT1621_clear();
  HT1621_Write(3,255);  //összes szegmens bekapcs. a 4. pozicióban
  delay(1000);
  HT1621_clear();
  HT1621_Write(4,255);  //összes szegmens bekapcs. a 5. pozicióban
  delay(1000);
  HT1621_clear();
  HT1621_Write(5,255);  //összes szegmens bekapcs. a 6. pozicióban
  delay(1000);
  HT1621_clear();
 
}

void loop() {
}



void HT1621_Write(byte addr,byte sdata)
/***************************************************************************************
kiírunk egy adatot a kijelző megadott segmensére
az addr vátozó mindíg a digit indexének kétszerese. pl. 0. digit 0, 1, digit 2 stb.
sdata a kijelzésre kerülő karakterkép, 
a byte bitjeinek jelentése:
   **5**
   1   6
   **2**
   3   7
 8 **4**
****************************************************************************************/ 
  addr=addr+addr;
  addr<<=2; 
  digitalWrite(CS, LOW); 
  SendBit_1621(0xa0,3);  //command kód 101     
  SendBit_1621(addr,6);  //memori adres (egy címen 4bit-et lehet írni, így egy digit két címen található a ram-ban    
  SendBit_1621(sdata,8); //segmens világit nam világít infó, bitenként egy szegmes vezérlés  (egy kezdőcímtől lehet egyszerre 2x4bitet kiírni)
  digitalWrite(CS, HIGH); 
} 


void HT1621_clear() 
{
  byte i; 
  for(i=0;i<6;i++) 
  { 
    HT1621_Write(i,0x00); 
  } 
}


void SendBit_1621(byte sdata,byte bitszam)
/*******bitenként kiléptet sdata változó tartalmából a bitszam változóban megadott bitet********/
{ 
  byte i; 
  for(i=0;i<bitszam;i++) 
  { 
    digitalWrite(WR, LOW); //alacsonyra ejtjük a WR bemnetet
    if(sdata&0x80) digitalWrite(DATA,HIGH); //ha balról az első bit 1, akkor DATA =1
    else digitalWrite(DATA,LOW); 
    digitalWrite(WR,HIGH);  //felfutó és a WR bemeneten, ennek hatására olvassa be Data bemenetet a chip
    sdata<<=1; //léptetünk balra egyet
  } 
}


void SendCmd_1621(byte command) 
/*************parancsot küldünk a kijelző csipnek****************/
{ 
  digitalWrite(CS, LOW); 
  SendBit_1621(0x80,4);  //a kijelzőnek egy parancs "100"-al kezdődik, plusz még kell egy "0"
  SendBit_1621(command,8); //most jön a konkrét command
  digitalWrite(CS, HIGH);                     
}

A teljesség kedvéért beidézek egy példa programot, ami 0-tól 999.999-ig számol. A program megmutatja, hogy ez a kijelző nem olyan lassú, mint az én első kvarcz órám kijelzője. Teker rendesen! Figyelem: a kivezetések máshová lettek kötve az Arduino-n mint az előző programban. Ez a program már kezeli a háttér világítást is, ha előtte megcsináltuk a forrasztgatós átalakítást! Ha jól emlékszem ebből a könyvtárból emeltem ki az előző program függvényeinek forrását.

/*
  Hello World!
  Displays the milliseconds passed since power on.
  Using an HT1621 based 7-segment LCD with 6 digits
  The circuit:
  cs to pin 13
  wr to pin 12
  Data to pin 8
  backlight to pin 10
  Created 9 dec 2018
  By valerio\new (5N44P)

  https://github.com/5N44P/ht1621-7-seg
*/

#include <HT1621.h> // include our library


HT1621 lcd; // create an "lcd" object


void setup(){
  // start the lcd:
  // cs to pin 13
  // wr to pin 12
  // Data to pin 8
  // backlight to pin 10
  // you can chose whichever pin you want



  lcd.begin(13, 12, 8, 10); // (cs, wr, Data, backlight)
  // if no backlight control is given, you can also use:
  // lcd.begin(13, 12, 8); // (cs, wr, Data)

  lcd.noBacklight(); // turn on the backlight led

  lcd.clear(); // clear the screen
}

void loop(){
  lcd.print(millis()/1000.0, 3); // print the floating point seconds value with 3 decimal digits precision
  delay(1); // wait 1 millisecond
}

1602 LCD kijelző (2 sor 16 karakter)

A kereskedelemben igen sokféle LCD kijelző kapható. Egy kezdőnek a legegyszerűbb és legolcsóbb a 2 soros soronként 16 karakteres kijelző használata. A kijelző ára 500Ft környékén mozog, így nem nagy beruházás. Gyengén látóknak (mint jómagam) szükség lehet nagyobb karakterméretű de teljesen azonos működésű típusra. A Chipcad-nél találtam 3000Ft környékén ilyen kijelzőt, ennek mérete óriási, messziről olvasható!
A kijelzőnek igen sok kivezetése van, így az Arduino Uno R3 sok kivezetését elhasználja. Szerencsére kapható hozzá egy kiegészítő áramkör kb. 300Ft értékben, ami I2C buszra illeszti a kijelzőt, így összesen csak 2 kivezetést kell elhasználnunk. Az I2C busz már “gyárilag beépítésre került az Az Arduino Uno R3-ba (illetve az ATmega chipekbe), így azt szinte azonnal használatba vehetjük.

Így nézhet ki az Arduino és az I2C illesztővel egybeépített LCD kijelző hardveres összekötése:

Az LCD-re az I2C illesztő egységet simán csak rá kell dugni a gyárilag előre kialakított furatokra, és beforrasztani. Ehhez persze kell egy kis forrasztási tapasztalat, de nem nagy ördöngösség. Valahogy így néz ki a két panel összeforrasztva a szemben álló lukakat és tüskéket:

Ha nem szeretnél forrasztani, akkor olyan LCD kijelzőt keress, amit már eleve összeépítetek és beforrasztotották az I2C illesztő áramkört az LCD kijelző modullra.
Akár készen megvettük, akár megforrasztottuk, így már készen állunk arra, hogy programot írjunk a kipróbálásra.

Az interneten számtalan program könyvtár található annak érdekében, hogy ne kelljen sokat programoznunk, és kényelmesen használhassuk a kijelzőnket. A legegyszerűbb módszer egy ilyen programcsomag beszerzésére, ha elindítjuk az Arduino IDE programot és a könyvtár kezelés menüpontban keresünk egyet:

Ha ezzel megvagyunk, lehet az LCD kijelzőt használni a programunkból. A kapott programok használatához segítséget kapunk. Találunk számos mintapéldát, amiből megfejthető a működés:

Lehet nézegetni, de néhány alapvető infót megadnék.

A programban meg kell adnunk az I2C buszon az eszköz címét. Ez alapértelmezetten 0x27. Ha azonban több kijelzőt is szeretnénk egyszerre csatlakoztatni, szükséges az egyes kijelzők (illetve a kijelzőket illesztő I2C panel) címeinek megkülönböztetésére. Ehhez az illesztő áramkör címeit három db rövidzár beforrasztásával, vagy éppen a forrasztás leszedésével tudjuk változtatni. A képen láthatók a panelen kialakított rövidzárak, mellette pedig a táblázat, hogy mely címekhez mely rövidzárat kell használni a háromból:

A0A1A2HEX Address
1110x27
0110x26
1010x25
0010x24
1100x23
0100x22
1000x21
0000x20

A megjelenő karakterek ASCII kódjaihoz itt egy jól használható táblázat:

Ha az adott karakter ASCII kódjára vagy kíváncsi, az oszlop legfelső karakterének kódja az oszlop feletti szám, ettől kezdve számolj lefelé a neked szükséges karakterig soronként!
Íme egy felkommentezett mintaprogram. Az utasítások a kommentekkel együtt remélhetőleg érthetők lesznek. Két előre megírt program gyűjteményt kell a fordítónak megadnunk, amit majd a fordító programunkhoz fog adni. Ezek a függvény könyvtárak az #include <> utasítással kerülnek beillesztésre.

#include <Wire.h>                              //I2C library
#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
void setup() 
{
  lcd.begin(16,2);                     //LCD inicializálása
  lcd.backlight();                       //háttérvilágítás bekapcsolása
  lcd.setCursor(0,0);                 //LCD kurzor a 1. sor 1. karakter pozícióba
  lcd.print("Hello!");                 //Hello felirat a kurzortól kezdve
  lcd.setCursor(5,1);                 //LCD kurzor a 2. sor 6. karakter pozicióba
  lcd.print("Szia!");                  //Szia felirat a kurzortól kezdve
  delay(3000);                          //3 másodperc várakozás
  lcd.clear();                             //kijelző törlése
   for (byte i=0; i<16; i++) {
    lcd.setCursor(i,1);                //LCD kurzor a 2. sor i. pozicióba
    lcd.print("#");                    //a kurzor pozicióba egy "#"-jel beírása
    delay(100);
  }
  for (byte i=0; i<16; i++) {
    lcd.setCursor(i,1);                //LCD kurzor a 2. sor i. pozicióba
    lcd.print(" ");                       //a kurzor pozició karakterének letörlése egy szóközzel.
    delay(100);
  }
  //egyéb kijelző kezelő függvények bemutatása 
  //háttérvilágítás ki és bekapcsolása
  lcd.clear();lcd.println("Hatter vilagitas");lcd.setCursor(0,1);lcd.print("kikapcsolas");
  delay(3000);lcd.noBacklight();delay(3000);lcd.backlight();delay(3000);
  //Cursor pozició villogtatása sötét hátérrel.
  lcd.clear();lcd.print("Blink funkcio"); lcd.blink(); delay(3000);lcd.noBlink();
  //Bekapcsoljuk a blink funkciót és a szöveg kiírását követően balra mozdítjuk a kurzort
  lcd.clear();lcd.blink();lcd.print("Cursor balra");delay(3000);lcd.moveCursorLeft();delay(3000);lcd.noBlink();
  //Bekapcsoljuk a blink funkciót és a szöveg kiírását követően jobbra mozdítjuk a kurzort
  lcd.clear();lcd.blink();lcd.print("Cursor jobbra");delay(3000);lcd.moveCursorRight();delay(3000);lcd.noBlink();
  //szöveg kiírást követően bekapcsoljuk a kurzort, majd kis idő mulva kikapcsoljuk
  lcd.clear();lcd.print("Cursor on");delay(3000);lcd.cursor();delay(3000);
  lcd.clear();lcd.print("Cursor off");delay(3000);lcd.noCursor();delay(3000);
  //kikapcsoljuk a display-t. A vikágítás marad, de szövegek nem láthatóak, azonban a tartalom nem törlődik, bekapcsoláskor ujra láthatóvá válik
  lcd.clear();lcd.print("Disp. ki es be!");lcd.setCursor(0,1);lcd.print("Vilagitas marad!");delay(3000);
  lcd.noDisplay();delay(3000);lcd.display();delay(3000);
  //kikapcsoljuk a display-t. Teljes kikapcsiolás, a világítás is lekapcsolódik. A tartalmat azonban nem felejti el, visszakapcsoláskor ujra láthatóvá válik az előzőleg kiírt szöveg
  lcd.clear();delay(3000);lcd.print("Disp. teljes ki");lcd.setCursor(0,1);lcd.print("es bakapcsolasa");delay(3000);
  lcd.off();delay(3000);lcd.on();delay(3000);
  //A kiírt szöveget balra mozdítjuk egy pozicióval
  lcd.clear();lcd.print(" Scroll balra");delay(3000);lcd.scrollDisplayLeft();delay(3000);
  //A kiírt szöveget jobbra mozditjuk egy pozicióval
  lcd.clear();lcd.print("Scroll jobbra");delay(3000);lcd.scrollDisplayRight();delay(3000);
  //kiírjuk az "Autoscroll:" szöveget és bekapcsoljuk az autoscroll funkciót. Kiírunk 10 számot,
  //és az eredetileg kiírt szöveg balra tolódik egy egy pozicióval a számok kiírásakor
  lcd.clear();  lcd.print("Autoscroll:");delay(3000);
  lcd.autoscroll();for (int i=0; i<10; i++) {lcd.print(i);delay(200);}lcd.noAutoscroll();
  //bekapcsoljuk a jobbra írás funkciót, és a write függvénnyel kiírunk egy szöveget
  lcd.clear();lcd.leftToRight(); lcd.write("Jobbra irt szov.");delay(3000);
  //balra írás mód
  lcd.clear();lcd.setCursor(15,0);lcd.rightToLeft();lcd.write("Balra irt szoveg");delay(3000);lcd.leftToRight();
  //Magyar éklezetes kisbetűk használata
  //ékezetes betűk karakterképének definiciója tömbökben. Csak nyolc saját karakterünk lehet, ebből 7-et kell felhasználnunk
  byte aI_t[8] = {B10,B100,B1110,B1,B1111,B10001,B1111};             //á betű karakterképe
  byte eI_t[8] = {B10,B100,B1110,B10001,B11111,B10000,B1110};   //é betű karakterképe
  byte iI_t[8] = {B10,B100,B0,B1110,B100,B100,B1110};                     //í betű karekterképe
  byte oI_t[8] = {B10,B100,B0,B1110,B10001,B10001,B1110};            //ó betű karakterképe
  byte uI_t[8] = {B10,B100,B10001,B10001,B10001,B10011,B1101}; //ú betű karakterképe
  byte oII_t[8] = {B00101,B01010,B0,B1110,B10001,B10001,B1110};    //ő betű karakterképe
  byte uII_t[8] = {B00101,B01010,B0,B10001,B10001,B10011,B1101};  //ű betű karakterképe
  //Az ö 239, az ü 245 ascii kódon megtalálható akarakterek között, azt nem kell definiálni
  //saját kerakterek betöltése a kijelző memóriájába
  lcd.createChar(0, aI_t);lcd.createChar(1, eI_t);lcd.createChar(2, iI_t);lcd.createChar(3, oI_t);
  lcd.createChar(4, uI_t);lcd.createChar(5, oII_t);lcd.createChar(6, uII_t);
  //Csak azért, hogy könnyebb legyen az ékezetes karaktereket kiírni, beszédesebb nevű változókba
  //töltöm azt a kódot, amit a kijelzőnek kell küldeni a karakter megjelenítéséhez
  byte aI=0;byte eI=1;byte iI=2;byte oI=3;byte uI=4;byte ooo=239;byte uoo=245;byte oII=5;byte uII=6;
  lcd.clear();
  //ékezetes karakterek kiírása a kijelzőre
  lcd.write(eI);lcd.print("kezetes bet");lcd.write(uII);lcd.print("k:");
  lcd.setCursor(7,1);
  lcd.write(aI);lcd.write(eI);lcd.write(iI);lcd.write(oI);lcd.write(uI);lcd.write(239);
  lcd.write(245);lcd.write(oII);lcd.write(uII);
}
void loop()
{
}

Ha esetleg valakinek egy 4 sor 20 karakteres kijelzőt sikerülne beszerezni, annak gondolnia kell arra, hogy a kijelző I2C címe 3F, így a programban ezt kell írni a harmadik sorba:
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
Egyébként a 4 soros kijelző minden gond és változtatás nélkül működik, csak több infó fér el rajta. Kicsit drágább is, h jól emlékszem 1200Ft körül lehet beszerezni.


Két kijelző használata:

Nincs pillanatnyilag két kijelzőm, ezért az alábbi programot nem próbáltam ki. Azonban más moduloknál mindig jól működött.
Szerintem első lépésben külön címet kell beforrasztani a kijelzőkön, és a programban a következőket kell írni:

#include <Wire.h>                              //I2C library
#include <LiquidCrystal_I2C.h>        //I2C LCD kezelő könyvtár
LiquidCrystal_I2C lcd1(0x26, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  //egyik LCD paramétereinek megadása
LiquidCrystal_I2C lcd2(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  //másik LCD paramétereinek megadása



Itt talán látható, hogy más-más változó nevet adtam a két kijelzőnek. Így már külön-külön lehet rájuk hivatkozni a programban. pl.:

 lcd1.begin(16,2);                   //LCD1 inicializálása
  lcd1.backlight();                     //háttérvilágítás bekapcsolása
  lcd1.setCursor(0,0);               //LCD1 kurzor a 1. sor 1. karakter pozícióba
  lcd1.print("Hello!");               //Hello felirat a kurzortól kezdve

  lcd2.begin(16,2);                   //LCD2 inicializálása
  lcd2.backlight();                     //háttérvilágítás bekapcsolása
  lcd2.setCursor(0,0);               //LCD2 kurzor a 1. sor 1. karakter pozícióba
  lcd2.print("Hello!");               //Hello felirat a kurzortól kezdve



 Ha valaki kipróbálta, jelezzen vissza, hogy működik-e?

Időjárás állomás

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égyezt 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ényérzékelő ellenállás bekötése
//---------------------------------
    //fényellenálláskivezetés Vezeték   Arduino UNO/NANO kivezetés
    //  Fényellenállás 1              (fehér vezeték)    A0
    //  Fényellenállás 2              (kék vezeték)      GND
    //  felhúzó ellenállás            (1Kohm és A0-ra)   +5V
    // mért aadatok a bekötött ellenállásosztó kimenetén kölönböző fényviszonyoknál
    // felhúzó ellenállás 1kohm a +5v-ra, fényellenállás a föld felé
    // tápfeszt veszi referenciának
      // Mért érték sötétben: 1000 vagy több
      // Mért érték erős napsütésben kb 400 vagy kissebb
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ényérzékelő ellenállás bekötése
//---------------------------------
    //fényellenálláskivezetés Vezeték   Arduino UNO/NANO kivezetés
    //  Fényellenállás 1              (fehér vezeték)    A0
    //  Fényellenállás 2              (kék vezeték)      GND
    //  felhúzó ellenállás            (1Kohm és A0-ra)   +5V
    // mért aadatok a bekötött ellenállásosztó kimenetén kölönböző fényviszonyoknál
    // felhúzó ellenállás 1kohm a +5v-ra, fényellenállás a föld felé
    // tápfeszt veszi referenciának
      // Mért érték sötétben: 1000 vagy több
      // Mért érték erős napsütésben kb 400 vagy kissebb
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.

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 oda tapasztalataimat, 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!)

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!

Ritkán működő gépek monitorozása V2.0

Nemrégiben vásároltam egy 16×1 LCD kijelzőt. Kiderült, hogy nem működik a háttér világítása. Kis méregetés után kiderült, hogy a kijelzőbe beépített led tropa. Kapargattam egy kicsit az üveglap élét, és kiderült, hogy a kijelző javítható, csak be kell építeni egy új ledet. A javítás abból állt, hogy a kijelző üveglapjának pereméről lekapartam a feséket, és oda ragasztottam egy ledet, Ha ez világit, egész jól látható a kijelzett szöveg. Nem tökéletes, de használható. Így néz ki a preparált LCD:

Sajnos beépítés előtt elfelejtettem lefotózni a kijelző oldalt, így a led a képen nem látszik, de talán el lehet képzelni mi történt!

Mivel ezen a kijelzőn nem lehetett szoftveres úton ki/be kapcsolni a háttér világítást, keresni kezdtem valamilyen értelmes felhasználást. Pont előtte néhány nappal szükségem volt a szivattyú monitorozó áramkörbe épített áram érzékelő feszültség adatára, de sehogyan sem tudtam elérni, hogy a szivattyú működjön és közben mérjem az érzékelő feszültség kimenetét. Ahhoz, hogy járjon a szivattyú a vízszint érzékelőjét meg kell „emelni”, de eközben nem állhatok mérőműszerrel 5 méterrel távolabb. Ez a bosszantó probléma, ráébresztett arra, hogy a szivattyú monitorozó áramkörömben milyen jól felhasználhatnám a félig roncs LCD-t!

Minden maradt ugyanaz, csak kivezettem az ATmega328 lábairól az I2C buszt a kijelzőhöz, és átalakítottam a programot. Ime néhány kép az új kütyüről:

Ezen a kapcsoló dobozon számunkra a 7 szegmenses kijelző, a két nyomógomb és a legalsó sötét csík, az LCD kijelző a lényeg. Van még néhány világítós kapcsoló, azok itt most nem érdekesek.
A vezérlő elektronika egy kicsit átalakult, mert kapott egy külön kapcsoló üzemű tápegység modult a régebbi konnektorba dugható telefontöltő helyett. Hely problémákkal küszködtem, ezért döntöttem a nagyon drága 300Ft-os táp beépítése mellett:

Az áramérzékelő elhelyezése maradt olyan mint volt, de az áramérzékelő alaposabb megismerése alapján kétszer vezettem át a 230V-os vezetéket, így kétszer akkor feszültséget kaptam az egyenirányító kimentén:

Az áram érzékelőnek van egy alap kimenő feszültsége akkor is, amikor a szivattyú nem működik. Bekapcsoláskor ezt megmérem, és tárolom. Ezzel a mért értékkel a későbbiekben korrigálni fogom a mért adatokat. Ez egyben azt is jelenti, hogy az elektronikát akkor szabad bekapcsolni, amikor a szivattyú éppen nem működik. Ez egy áramszünetet követően nem biztos, hogy így is lesz.

Ennek az offset feszültségnek az oka az, hogy a D1 és D2 egyenirányító és a szinteltoló dióda feszültsége nem teljesen azonos. Az áramérzékelő kapcsolása emlékeztetőül:

Hőmérséklet változással a két dióda feszültsége egyre inkább eltér egymástól, ezért ez az offszet még változik is, de ez engem nem nagyon érdekel, nincs szükségem ilyen pontosságra. Tekintve, hogy immár le is tudok olvasni konkrét feszültség értéket, és tudom, hogy ez arányos a szivattyú áramfelvételével, van értelme valahogyan konvertálni a mért adatot. Ehhez feleségem villanyvasalóját használtam. Teljesítmény 1200W, tehát 1200W/230V=5,2A áramot vesz fel. A szivattyú helyett a vasalót kötöttem be, és a mutatott feszültséget feljegyeztem. Ezt követően már volt egy váltószámom, amivel a mért feszültségből közvetlenül áramfelvételt írhatok ki a kijelzőre. Tudom, hogy nem egy pontos megoldás, de nekem ennyi épp elegendő.

 A program jelentősen leegyszerűsödött kivettem belőle a tárolt adatokat „levillogtató” egy karakteres megjelenítő megoldást, hiszen már van LCD kijelző, nem kell a 7 szegmenses kijelzővel hülyéskedni. Az egyik nyomógomb direktben tápot ad egy soros ellenálláson keresztül a kijelző utólag beszerelt led háttér világításának, tehát a gombot nyomni kell folyamatosan, ha látni akarom az adatokat.
A másik nyomógomb váltogatja a regisztrált értékeket, és leolvasgathatom ami érdekel. A következő kijelzések közül lehet válogatni:

A a következőket lehet leolvasni:

  • Ossz.muk.ido: a szivattyú összes működési ideje. Ezt másodperc alapon mérem. Nem ez határozza meg az élettartamot, csak kíváncsi voltam rá!
  • Ossz.mot.indit: A szivattyú beindításának darabszáma a készülék üzembehelyzése óta. Epromban tárolt adat, nem törlődik áramszünetkor.
  • Arammero offset: Bekapcsoláskor a zárójelben látható adatot olvastam ki a konverterből. EZ a tapsztalati konverziós szám meghatározása után (villanyvasalós mérés) a kijelzett áramerősséget jelenti. Ez fals áramerősség, a motor 0A áramot vesz fel, tehát ezzel korrigálni kell a tényleges mért értéket.
  • Mot.erz.kuszob: Előre programban beállított adat, ennél nagyobb áram értéknél tekinti úgy a program, hogy működik a motor.
  • Tularam kuszob: A potenciométerrel beállítható áram érték, ami felett túláram riasztást ad a kijelző tizedes pontja. A túláram valamilyen komolyabb problémára is utalhat a szivattyúval, pl. beleakadt egy kő a darálóba stb.
  • Tularamok szama: Hány túláram jelzés volt a működési időben.
  • Uts.max.mot.aram: Ezért az adatért csináltam az egészet. Látható, hogy a szvattyú 3,72 A áramot vesz fel (legalább is utoljára ennyit), így teljesítménye 850W. És ez igaz, az adatlapja szerint 800W-os. Nem is tévedtem olyan nagyot a villanyvasalóval!
  • Motoraram: Az éppen aktuális motoráram. Most épp nem megy a szivattyú. Az a 0,02A abból fakad, hogy az offszet feszültség korrigálása nem teljesen pontos, az offszet kicsit mindig változik.
  • 24H inditasszam: Ezt az adatot jelzi ki a 7 szegmens kijelző is. Nálunk ez reggel általában 3 szokott lenni, mert az esti zuhanyzással elég sok vizet fogyasztunk. Délután ez az érték már csak 2.

És ha valakit érdekel, itt a forráskód is:

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

#define tombmeret 10		//mekkora legyen a ramban tárolt adaok mennyisége
#define eepromkimeles 0   //ha értéke egy, akkor csak minde 5. indítás után tárolunk az eepromban, ha 0 akkor minden indításkor
#define felejtes_ido 86100  //ennyi idon belüli szivattyú indítások számát jelezzük ki. 86100sec=24 óra
byte hossz=0;
long kijelzo_frissites=millis();
long lcd_vilagitas=millis();
char szamjegy_db[]={'0','0','0','0'};
byte szamjegy_db_num[]={0,0,0,0};
char szamjegy_ido[]={'0','0','0','0'};
byte l=0;
byte motor_on=0;
byte motor_on_state=0;
byte szintjelzes=0;
long s1=0;					//eeprom-ból kiolvasottértékek átmeneti tárolása
long s2=0;					//eeprom-ból kiolvasottértékek átmeneti tárolása
long s3=0;					//eeprom-ból kiolvasottértékek átmeneti tárolása
byte k=0;
int inditas_db=0;
int korrekcio=0;
long ido_tmp=millis();	//a másodpercenkénti figyeléshez
long ido_tmp2=millis();	//a 100msec-es figyeléshez
long ido_tmp3=millis();	//a 100msec-es figyeléshez
//long ido_tmp4=millis();	//a 100msec-es figyeléshez
long bekapcs_ido=0;		//az aktuális szivattyú működés időtartama
long ido[tombmeret]; 			//ebben mérjük a bekapcsolások között eltelt időt
long bekapcsolva[tombmeret];		//az egyes bekapcsolások ideje (szivattyú működési idő
byte tarolasjelzes[tombmeret]; //a tartalmában levo 1-es hatasara taroljuk az adatokat az epromban
byte sw_elozo_allapot=LOW;	//szivattyú működés előző ciklusban érzékelt állapota
long o_ido=0;				//tömb elemek összeadásakor használt változó
int tombindex=0;
byte villogas=0;
byte veszjelzesmemo=0;
long veszjelz_ido=millis();
byte veszjelz_tmp=0;
byte motor_megy=LOW; //szivattyú működéseklor HIGH, ha nem működik, akkor LOW
int aram_kuszob=0;  //szivattyú áramküszöb értéke, mely felett működőnek tekintjük (áramváltó alap feszültsége+3+alapfesz/5)
byte motor_tularam=LOW; //szivattyú tuláram esetén HIGH, alatta LOW, Bármilyen lekérdezés LOW-ba billenti
byte szintjelzo_alapertek=0;  //ha nincs vészjelzés, akkor LOW vagy HIGH értéket vesz fel.
byte szintjelzo_on=0;
int aram_offset=0;
int motoraram=0;
int aramlimit=0;
int uts_max_motoraram=0;
//prellmentesítés segédváltozói
 byte in_prev_state=0;     //bemenet előző állapota segéd változó
 byte in_prell_tmp=0;      //bemenet prell figyeléshez segéd változó
 long in_prell_time=0;     //bemenet prellmentesítéshez eltelt idő az első kontaktus óta, segéd változó
 long out_setup_time_tmp=0;//kimenet kikapcsolási időhöz segéd változó
 byte in_state=0;          //nyomógomb nyomvatartás alatt értéke 1
byte adat_valaszto=0; //az LCD kijelzett értéket határozza meg
bool k_frissit=LOW;


//szivattyú működésérzékelő bemenet
//hétszegmenses kijlző kimenetek
//   -       A       Szegmensek: 1   -  B,C
//  | |   F     B                2   -  A,B,G,E,D 
//   -       G                   3   -  1,3,4,6,7
//  | |   E     C                4   -  F,B,G,C
//   -       D                   5   -  A,F,G,C,D
//                               6   -  A,F,G,E,C,D
//                               7   -  A,B,C
//                               8   -  A,F,B,G,E,C,D
//                               9   -  A,F,B,G,C,D
//                               0   -  A,F,B,E,C,D
//                               forgas1   -  G
//                               forgas2   -  C
//                               forgas3   -  D
//                               forgas4   -  E
//                               telijelzés1   -  D
//                               telijelzés2   -  G
//                               telijelzés3   -  A
//                A F B G E C D 
byte szegmens[]= {0,0,0,1,0,0,0,   //0, 0
                  1,1,0,1,1,0,1,    //1, 7
                  0,1,0,0,0,1,0,    //2, 14
                  0,1,0,0,1,0,0,    //3, 21
                  1,0,0,0,1,0,1,    //4, 28
                  0,0,1,0,1,0,0 ,    //5, 35
                  0,0,1,0,0,0,0,    //6, 42
                  0,1,0,1,1,0,1,    //7, 49
                  0,0,0,0,0,0,0,    //8, 56
                  0,0,0,0,1,0,0,    //9, 63
                  1,1,1,0,1,1,1,    //f1, 70
                  1,1,1,1,1,0,1,    //f2, 77
                  1,1,1,1,1,1,0,    //f3, 84
                  1,1,1,1,0,1,1,    //f3, 91
                  1,1,1,1,1,1,0,    //s1, 98
                  1,1,1,0,1,1,1,    //s2, 105
                  0,1,1,1,1,1,1,    //s3, 112
                  1,1,1,1,1,1,1};   //ures, 119

byte pin_szegmens[] = {7,  8,  9, 10, 11, 12, 13};
// szegmens betüjele:  A,  F,  B,  G,  E,  C , D
//chip kivezetés:     13, 14, 15, 16, 17, 18, 19 


void setup()
{
  Serial.begin(9600);
  analogReference(DEFAULT);  //A tápfeszt veszi referenciának (5V)
  Wire.begin();  // I2C busz használat indítása
  lcd.begin(20,4  ); //LCD inicializálása
//  lcd.noBacklight();      //háttérvilágítás bekapcsolása
  lcd.backlight();      //háttérvilágítás bekapcsolása

  //tömbök indulú értékének feltöltése
  for (byte i=0;i<5;i++) {	ido[i]=0;bekapcsolva[i]=0;tarolasjelzes[i]=0;}
  tarolasjelzes[0]=1;
  pinMode(2,INPUT); //motor működés érzékelő bemenet //4. chip kivezetés
  digitalWrite(2,HIGH);
  pinMode(3,INPUT); //"teli" szintjelző érzékelő bemenet //5. chip kivezetés
  digitalWrite(3,HIGH);
  pinMode(4,INPUT); //Kijelző világítás bekapcsoló gomb. 60 másodpercig világít, 
                    //jelenlegi hardverben nincs funkciója, mert a világítást egy külön nyomógomb direktben kapcsolja a kijelzőn
  digitalWrite(4,HIGH);
  pinMode(5,INPUT); //Kijelzett érték váltása az LCD kijelzőn és gyári alapbeállítás, ha nyomva van bekapcsoláskor
  digitalWrite(5,HIGH);
  
  // led kijelző szegmenseinek vezérlő kimeneteinek beállítása
  // Arduino láb:        7, 8, 9,10,11,12,13
  // szegmens betüjele:  A, F, B, G, E, C, D
  for (byte i=6;i<14;i++) {pinMode(i,OUTPUT);digitalWrite(i,HIGH);} //led kijelző szegmenseinek vezérlő kimenetei
  if (digitalRead(5)==LOW) //gyári alapbeállítás
  {
    lcd.setCursor(0,0);lcd.print("Alapertek beall.");
    lcd.setCursor(0,1);lcd.print("                ");
    //eeprom törlés, gyári alapbeállítás
    for (byte i=0;i<20;i++) {EEPROM.write(i,0);}
    EEPROM.write(9,digitalRead(3));       //szintjelző alapállapotának lekérdezése
    //tizedespont villogtatás, ami a gyári alapbeállítást jelzi
    for (byte i=1;i<5;i++) {digitalWrite(6,LOW);delay(200);digitalWrite(6,HIGH);delay(200);}
  }
  lcd.clear();lcd.setCursor(0,0);lcd.print("Offset meres!   ");
  //10x mérünk és átlagoljuk, így megkapjuk a nyugalmi feszültségét az áramváltó egyenirányítójának
  //fontos, hogy bekapcsoláskor ne működjön a szvattyú
  for (byte i=0;i<10;i++) {aram_offset=aram_offset+analogRead(A2);delay(60);}
  aram_offset=aram_offset/10;  //egyenirányitó átlagos nyugalmi offszet átlagos feszültségének számítása
  aram_kuszob=aram_offset*10;   //nyugalmi offszetnél harmoszorosa a működő motor érzékelésének áramküszöbe
  lcd.setCursor(0,1);lcd.print("Offset:");
  lcd.setCursor(0,1);lcd.print((float) aram_offset*0.017);lcd.print("A (");lcd.print(aram_offset);lcd.print(")");
  delay(2000);
  szintjelzo_alapertek=EEPROM.read(9);  //tárolt szintjelző alapállapot kiolvasása
  uts_max_motoraram=EEPROMReadlong(15);
  lcd.setCursor(0,1);lcd.print("Uts.max.mot.aram");
  lcd.setCursor(0,1);lcd.print("torlesehez nyomd");
  delay(2000);
  lcd.setCursor(0,1);lcd.print("a nyomógombot!  ");
  lcd.setCursor(0,1);lcd.print("Hatravan:       ");
  for (byte i=5;i>0;i--) 
  {
    lcd.setCursor(9,1);lcd.print(i);
    if (digitalRead(5)==LOW)
    {
      for (byte j=15;j<20;j++) {EEPROM.write(j,0);}
      lcd.setCursor(0,0);lcd.print("Max aram torolve");
      lcd.setCursor(0,1);lcd.print("================");
      delay(2000); 
      break;
    }
    delay(1000);
  }
}

void loop()
{
  //4-es bemenetre kötött gombnyomásra bekapcsoljuk az lcd háttérvilágítását, és egy perc mulva kapcsoljuk ki
  if (digitalRead(4)==LOW) {lcd.backlight();lcd_vilagitas=millis();}
  //if (lcd_vilagitas+60000<millis()) {lcd.noBacklight();}

  //egy másodpercenként ellenőrizzuk, hogy megy e a motor és adminisztrálunk
  if (millis()>ido_tmp+1000) {inditas_szamlalo();ido_tmp=millis();}

  //1,2 másodpercre beállítjuk a vizszint vészjelzést ha bekapcsolt a vész vizszintjelző
  if (millis()>ido_tmp3+1200) {if (motor_on!=1) {szintjelzes=1;}}
  if (millis()>ido_tmp3+2400) {	ido_tmp3=millis();szintjelzes=0;k=0;}

  //Szintjelző tárolt alapértéke alapján a vészjelzés detektálása szintjelzo_on=HIGH jelzi a magas folyadékszintet 
  szintjelzo_on=LOW;
  if (szintjelzo_alapertek==LOW) {if (digitalRead(3)==HIGH) {szintjelzo_on=HIGH;}} 
  else {if (digitalRead(3)==LOW) {szintjelzo_on=HIGH;}}

  //*******************szintjelző riasztás megjelenítése led kijelzőn***********************************
  //bekapcsolt a vész szintjelző kapcsoló, sorban villogtatjuk a függőleges pálcikákat 3 másodpercenként
  if (szintjelzes==1 && szintjelzo_on==HIGH)  
  {
    if (millis()>ido_tmp2+200) 
    {
      for (byte i=0;i<7;i++) {digitalWrite(pin_szegmens[i],szegmens[98+(k*7)+i]);}
      k++;if(k==3) {k=0;}
      ido_tmp2=millis();
    }
  }

  //******************motor működés kelzése a led kijelzőn*******************************************
  //éppen működik a motor, sorban körbe villogtajuk az alsó 4 szegmenst
  if (motor_on==1 && szintjelzes==0) 
  {
    if (millis()>ido_tmp2+200) 
    {
      //motor működik	
      for (byte i=0;i<7;i++) {digitalWrite(pin_szegmens[i],szegmens[70+(motor_on_state*7)+i]);}
      motor_on_state++;if (motor_on_state==4) {	motor_on_state=0;}
      ido_tmp2=millis();
    }			
  }
  
  //********************indításszám kijelzése a led kijelzőn****************************************
  //sem a motor nem működik, sem vész vizszint kijelzés nincs
  //kijelezzük az utolsó 24 óra indításainak számát, villogtatjuk ha több mint 8
  if (motor_on==0 && szintjelzes==0) 
  {
    if (millis()>ido_tmp2+200) 
    {
      if (inditas_db==8) {villogas++;} else {villogas=1;}
      if (villogas==2) {for (byte i=0;i<7;i++) {digitalWrite(pin_szegmens[i],szegmens[119+i]);}}
      if (villogas==1) {for (byte i=0;i<7;i++) {digitalWrite(pin_szegmens[i],szegmens[inditas_db*7+i]);}}
      if (villogas==2){villogas=0;}
      ido_tmp2=millis();
    }
  }

  // **************prellmentesítés a nyomógombon, és kijelzett érték paraméterének változtatása*****************
  //első lenyomás érzékelése
  if (in_state==0 and digitalRead(5)==LOW and in_prell_tmp==0)
    {in_prell_tmp=1;in_prell_time=millis();} 
  // már 50msecv óta nyomva van, most már biztos, hogy lenyomták és nem prellezik
  if (in_state==0 and digitalRead(5)==LOW and in_prell_tmp==1 and millis()>in_prell_time+50) 
    {
      in_state=1;in_prell_tmp=0;
      //növeljük a kijelzett érték változóját, ciklikuan 0-ha, elértük a legnagyobb értéket
      adat_valaszto++;if (adat_valaszto==9){adat_valaszto=0;}
      k_frissit=HIGH; //ennek hatására azonnal ki fogja írni a kiválasztott adot (frissíti a kijelzőt)
      digitalWrite(6,HIGH);  //kikapcsoljuk a tizedespontot (túláram jelzés törlése)
    } 
  //első elengedés érzékelése
  if (in_state==1 and digitalRead(5)==HIGH and in_prell_tmp==0)
    {in_prell_tmp=1;in_prell_time=millis();} 
  // már 50msecv óta elengedve, most már biztos, hogy elengedték és nem prellezik
  if (in_state==1 and digitalRead(5)==HIGH and in_prell_tmp==1 and millis()>in_prell_time+50) 
    {in_state=0;in_prell_tmp=0;} 
        
  //***********************************kijelző frissítés******************************************
  //Serial.println(k_frissit);
  if (millis()>kijelzo_frissites+1000 or k_frissit==HIGH)  //egymásodpercenként frissítjük a kijelzésre kerülő értéket
                                                           //vagy ha megnyomta a nyomógombot
  {
    k_frissit=LOW;
    //lcd.setCursor(0,1);lcd.print("                ");
    switch (adat_valaszto)
    {
      case 0:   //24 óra indításszáma
        lcd.setCursor(0,0);lcd.print("24H inditasszam:");
        lcd.setCursor(0,1);lcd.print(inditas_db);lcd.print(" db            ");break;
      case 1:   //Összes motor működési idő
        lcd.setCursor(0,0);lcd.print("Ossz.muk.ido:   ");
        lcd.setCursor(0,1);lcd.print(EEPROMReadlong(0)/60);lcd.print(" perc       ");break;
      case 2:   //Összes motor indításszám
        lcd.setCursor(0,0);lcd.print("Ossz.mot.indit:");
        lcd.setCursor(0,1);lcd.print(EEPROMReadlong(4));lcd.print(" db            ");break;
      case 3:   //árammérő offszet értéke
        lcd.setCursor(0,0);lcd.print("Arammero offset:");
        lcd.setCursor(0,1);lcd.print((float) aram_offset*0.017);lcd.print("A (");lcd.print(aram_offset);lcd.print(") ");break;
      case 4:   //motor működés érzékelési küszöb
        lcd.setCursor(0,0);lcd.print("Mot.erz.kuszob: ");
        lcd.setCursor(0,1);lcd.print((float)aram_kuszob*0.017);lcd.print("A (");lcd.print(aram_kuszob);lcd.print(") ");;break;
      case 5:   //motor túláram risztási küszöb (potméter beállított értéke)
        lcd.setCursor(0,0);lcd.print("Tularam.kuszob: ");
        lcd.setCursor(0,1);lcd.print((float) aramlimit*0.017);lcd.print("A (");lcd.print(aramlimit);lcd.print(") ");break;
      case 6:   //motor túláram risztási küszöb (potméter beállított értéke)
        lcd.setCursor(0,0);lcd.print("Tularamok szama: ");
        lcd.setCursor(0,1);lcd.print(EEPROMReadlong(10));lcd.print(" db            ");break;
      case 7:   //motor áramának értéke (offszet éték kivonásával)
        lcd.setCursor(0,0);lcd.print("Uts.max.mot.aram:");
        lcd.setCursor(0,1);lcd.print((float)uts_max_motoraram*0.017);lcd.print("A (");lcd.print(uts_max_motoraram);lcd.print(") ");break;
      case 8:   //motor áramának értéke (offszet éték kivonásával)
        lcd.setCursor(0,0);lcd.print("Motoraram:      ");
        lcd.setCursor(0,1);lcd.print((float) (motoraram-aram_offset)*0.017);lcd.print("A (");lcd.print(motoraram);lcd.print(") ");break;
    }
    kijelzo_frissites=millis();
  }
}	



void inditas_szamlalo()
{
  //idő számlálók növelése. Másodperc alapon mérünk időt
  bekapcs_ido++;ido_tmp=millis();
  ido[0]=ido[0]+1;
  o_ido=0;
  s3=0;
  // sorban összeadjuk a tömbben tárolt időt, ha elértük a 24 órát (86400 másodperc), akkor megállunk
  //az utolsó 24 óra szivattyú indításainak számára vagyunk kíváncsiak
  while (o_ido<felejtes_ido && s3<tombmeret-1 && ido[s3]!=0)
  {
    o_ido=o_ido+ido[s3];
    s3++;
  }		
  inditas_db=s3-1;
  if (inditas_db==8) {veszjelzesmemo=1;}
  if (tarolasjelzes[tombmeret-1]==1 && eepromkimeles==1) //tarolásjelzés, tehát az utolsó 5 adatot összgezni és tárolni kell
                                                         //de csak akkor, ha az eeprom kimélés be van kapcsolva
  {
    //Összeadjuk a tömbben tárolt bekapcsolási időket, és közben töröljük az összeadottakat
    //a törlés csak a működés nyomnkövethetősége miatt lett beépítve
    o_ido=0;
    for (byte j=0;j<5;j++) {	o_ido=o_ido+bekapcsolva[tombmeret-j-1];bekapcsolva[tombmeret-j-1]=0;}
      //osszes szivattyú működési idő kiolvasása az eeprom-ból és hozzáadjuk az utóbbi tárolt bekapcsolási időket
    s1=EEPROMReadlong(0);
    s1=s1+o_ido;
      //Összes eddigi indításszám kiolvasása eeprom-ból és hozzáadjuk az utóbbi tárolt indítás számot
    s2=EEPROMReadlong(4);
    EEPROMWritelong(0,s1);
    EEPROMWritelong(4,s2+5); //értékek írása az eeprom-ba
    tombindex=0;
    tarolasjelzes[tombmeret-6]=1;
    tarolasjelzes[tombmeret-1]=0;
  } //if vége
  motor_lekerdezes();
  
  //a szivattyú indítás felfutó éle, tároljuk a tömbb 0-as indexén az utolsó indítás óta 
  //eltelt időt és tároljuk ennek változóját, töröljuk a bekapcsolási idő változóját
  if (motor_megy && !sw_elozo_allapot) {  bekapcs_ido=0;motor_on=1;}
  
  //szivattyú kikapcsolása (lefutó él). Minden értéket lejjebb másolunk a tömbben és
  //tároljuk a bekapcsolási idő számlálást
  if (!motor_megy && sw_elozo_allapot) 
  {
    if (motor_tularam==HIGH) 
    {
      //ha a motor áramfelvétele nagyobb volt a működés alatt mint a potival beállított limit, akkor kigyúllad a tizedespont. 
      //Az5-os bemenetre kötött gomb lenyomása kikapcsolja
      digitalWrite(6,LOW);
      motor_tularam=LOW;
      int ta=EEPROMReadlong(10);
      ta++;
      EEPROMWritelong(10,ta);
    }
    EEPROMWritelong(15,uts_max_motoraram);
    bekapcsolva[0]=bekapcs_ido;
    motor_on=0;
    for (byte j=tombmeret-1;j>0;j--)
    {
      bekapcsolva[j]=bekapcsolva[j-1];
      ido[j]=ido[j-1];
      tarolasjelzes[j]=tarolasjelzes[j-1];
    }
    bekapcsolva[0]=0;ido[0]=0;tarolasjelzes[0]=0;
    if (eepromkimeles==0) //eeprom kimélés kikapcsolva, így minden motor működés után beírjuk az adatokat az eeprom-ba
    {
      //Összes eddigi működési idő kiolvasása eeprom-ból és hozzáadjuk a legutóbbi működési időt
      s1=EEPROMReadlong(0);
      s1=s1+bekapcs_ido;
      EEPROMWritelong(0,s1);
      //Összes eddigi indításszám kiolvasása eeprom-ból és hozzáadunk egyet
      s2=EEPROMReadlong(4);
      EEPROMWritelong(4,s2+1); //értékek írása az eeprom-ba
    }
  }
  sw_elozo_allapot=motor_megy; //fel és lefutó él érzékeléséhez
}


//Ez a funkció kiír egy 4 byte (32bit) long változót az eeprom-ba
void EEPROMWritelong(int address, long value)
{
	//szétszedjük byte-okra a long-ot
	byte four = (value & 0xFF);
	byte three = ((value >> 8) & 0xFF);
	byte two = ((value >> 16) & 0xFF);
	byte one = ((value >> 24) & 0xFF);
	//A 4 byte-os adat epromba írása
	EEPROM.write(address, four);
	EEPROM.write(address + 1, three);
	EEPROM.write(address + 2, two);
	EEPROM.write(address + 3, one);
}

//Ez a funkció visszaolvas 4 byte (32bit) long változót az eeprom-ból
long EEPROMReadlong(long address)
{
	//4 bytes olvasása az eeprom-ból.
	long four = EEPROM.read(address);
	long three = EEPROM.read(address + 1);
	long two = EEPROM.read(address + 2);
	long one = EEPROM.read(address + 3);
	//4 byte long változóvá alakítása
	return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}

void char_konv(int szam)
{
	String konv_string=String(szam);
	hossz=konv_string.length();
	for (byte j=0;j<4;j++) {szamjegy_db[j]='0';}
	for (byte i=0;i<hossz;i++) {szamjegy_db[4-hossz+i]=konv_string.charAt(i);}
}

void motor_lekerdezes()
{
motoraram=analogRead(A2);
if (uts_max_motoraram<(motoraram-aram_offset)) {uts_max_motoraram=motoraram-aram_offset;}
aramlimit=analogRead(A1);
if (!digitalRead(2) || (motoraram-aram_offset)>aram_kuszob) {motor_megy=HIGH;}  else {motor_megy=LOW;}
if ((motoraram-aram_offset)>aramlimit) {motor_tularam=HIGH;}
}