Magyarul beszélő óra gyengén látóknak

Tartalom:

  • Nagy számok a kijelzőn, környezeti megvilágításhoz alkalmazkodik
  • Nappal egész óránként bemondja az időt
  • Gombnyomásra kijelzi a dátumot és a hét napját, és ezeket az adatokat el is mondja
  • Választható női és férfi hang, beállítható hangerő
  • Szerelési tapasztalatok, forráskód

Régi elképzelésem volt, hogy készítsek egy beszélő mérőműszert, ami bemondja a mért feszültség és áram értékeket, így nem kell a műszerre nézni mérés közben. Végeztem előtanulmányokat és készítettem mp3 lejátszóval egy olyan programot, ami szavakból összerakja a mondandó adatot. A hangokat a Word és a Google felolvasó moduljától „loptam” el. Az előbbi linken megtalálhatók az mp3 állományok, nem kell megcsinálni! Nem szépen beszél, de érthetően. Elég sokféle adat bemondására felkészültem többek között az idő és dátum bemondásra is. Aztán kiderült, hogy anyukámnak szürkehályog műtétre lesz szüksége. Ha megműtik, akkor is csak nagyon homályosan fog látni egy másik gyógyíthatatlan szembetegség miatt. Hatalmas számjegyeket esetleg felismer majd. A magyar egészségügy a propaganda szerint gyorsan segít, a valóságban félig meg fog vakulni mire sorra kerül sürgősséggel. Jobb felkészülni a legrosszabbra! Nem akartam én beszélő órát csinálni! Először meg akartam venni. Magyarul beszélő óra azonban 25.000Ft-ért kapható, és épp tartósan nem volt készleten. Tiszta szocializmus! Így ugrott be az ötlet, hogy minden programom és alkatrészem meg van a feladathoz. Végre valami hasznosra fogom használni a szórakozásomat. Készítek egy órát, ami bemondja óránként (kivéve éjszaka) az időt, illetve gombnyomásra a dátumot és a hét napját is. Nagyon fontos a hét napja, mert aki egész nap otthon van, annak az unalmas hétköznapok tompítják az időérzékét. Tapasztaltuk, hogy anyukám már soha nem tudja milyen nap van. Nem is kell neki ez az infó, csak néha kellemetlenséget okoz, hogy azt hiszi, hét vége van, mi meg épp dolgozunk. Ez a beszélő óra hiteles története! Egyszer majd megfilmesítem! Engem Ray Liotta fog játszani. …basszus, már Ő is meghalt a múlt héten!

Egy kis reklám az óra tulajdonságaiból:

  • MAX7219 meghajtókkal LED mátrix kijelzővel működő hatalmas kijelző
  • A DS3231 chip-nek köszönhetően igen pontos, tapasztalatom szerint évi néhány másodperc az eltérés. Nem kell internetes időszerver hozzá!
  • A hét napját magától tudja a dátumból, nem kell megadni
  • Kezeli a szökőéveket
  • Nyári időszámításra automatikusan átáll március utolsó vasárnapján, és vissza november utolsó vasárnapján.
  • Bemondja óránként az időt egész órakor, amit egy rövid szignállal kezd. A bemondás csak egy beállítható időszakban történik. Éjszaka lehet aludni tőle!
  • Gombnyomásra megmutatja a dátumot és a hét napját, valamint a pillanatnyi hőmérsékletet. Ugyanekkor be is mondja a pontos időt, a dátumot és a hét napját! Bemondás hangereje beállítható.
  • A kijelző fényerejét beállítja a szoba fényviszonyaihoz.
  • Gondozásmentes óra! Be kell dugni egy telefontöltő konnektorba dugható 5V-os tápjába, és évekig elvan magának!

Túl sok magyarázatot nem érdemel az óra működése. Az alapötlet már régi, és félig készen is volt! Vettem egy 4 tagból álló 8×8-as led mátrix kijelzőt, amit MAX7219 IC-k hajtanak meg. Ennek a hátsó felületére szereltem egy Arduino Nano-t, egy DS3231 óra modult, és egy DFRobot mp3 lejátszót. Járulékos anyag még egy TEP4400 fotótranzisztor, ami a megvilágítást méri, és beállítja a fényerőt. Éjszaka még a legkisebb fényerő is majdnem sok, nappal meg az árnyékos szoba ellenére maximumot állítottam be, mert ez gyengén látóknak segítség, bár engem már enyhén vakít!

A dobozt nyáklemezból csináltam. Levágtam a megfelelő méretű lapokat, és az éleknél simán összeforrasztottam. A fenéklemezt, ahol szerelhető a belseje, a doboz oldalfalához forrasztott anyacsavarokhoz lehet rögzíteni. Régi bevált technika málam. Az óra méret így 14x4x3.5 cm lett. Kellett még csiszolni, festeni. A doboz tartott legtovább!

Néhány fotó a kivitelről:

Összeszerelve:

A mátrix kijelző saját bontásból származik, utólag forasztgattam össze a négy tagot. Eredetileg az időjárás állomásom első verziójában szolgált nyugdíjazásáig! A doboz tetejére került egy nyomógomb, ez már a képen nem látszik, mert beleolvad a fekete színbe. Azért a doboz tetejére került, hogy könnyű legyen kitapogatni szükség esetén.

Az óra setup lehetőségekkel is fel lett vértezve! Be lehet állítani a dátumot, az időt! Beállítható, hogy automatikusan álljon-e át a nyári óraállításkor az idő (állítólag megszüntetik az óraállítást)! Beállítható a hangszóró hangereje. A hangszóró bármi lehet, nálam egy Genius számítógép hangszóró passzív része, amit az ócskapiacon vettem 200Ft-ért. Pont jó!

Beállítható a kezdő időpontja (órája) az óránkénti hangbemondásnak. Ugyanígy beállítható a záró időpont is. Pl. ha a kezdetet 8-ra állítom, a végét meg 20-ra, akkor csak reggel 8 és este 8 között mondja óránként az időt. Az óránkénti bemondásnál értelem szerűen csak az órát mondja (pl. tizennégy óra). Ez azonban annyira rövid időnként, hogy sokszor lemaradtam a szövegről, csak azt halottam, hogy megint morog valamit az óra. Ezért feleségem ötlete alapján az óránkénti bemondás előtt egy szignál hangzik el. Pont olyan lett, mint egy pályaudvar hangosbemondója! A szignál a Windows egyik beépített hangja lett. Nem vacakoltam sokat a keresgéléssel, ott volt a gépen!

Ha a nyomógombot megnyomják, akkor két-két másodperces időtartamig megmutatja a dátumot, a hét napját, és a hőmérsékletet. Tapasztalatom szerint a zárt dobozban meleg van, így a DS3231 hőmérője egy-két fokkal többet mutat. Kár!

A nyomógomb megnyomásakor a kijelzőn történő „mutogatással” együtt bemondja a pontos időt, az aktuális dátumot évek nélkül (csak hónap és nap), valamint a hét napját. Itt nincs szignál, aki megnyomja, tudja, hogy az óra beszélni fog, tehát figyel.

Beállítható még, hogy férfi vagy női hang mondja be az időt. A nő Google a férfi Word. Nem túl kellemes a hangzás! Sokat lehetne javítani, mert pl. az óránkénti bemondáshoz egyben fel tudná olvasni mindkét program az időt szépen hangsúlyozva, de ennyi munkát nem szántam rá. Mindent újra felvenni és audió editorral összeszerkeszteni elég sok idő. Ha majd valaki sorozatban gyártja az órát, akkor érdemes lesz ezzel vacakolni. Vagy bele kell tenni egy 50.000Ft-os számítógépet hangszintetizátorral, és az tökéletes lesz. Nekem 5000Ft-os költségvetésből erre tellett!

A setup folyamat a nyomógomb 5 másodpercig tartó megnyomásával indul. Villogni kezd a setup felirat, ekkor rövid gombnyomásra mutatja az első beállítható adatot, az évet. Az évszám utolsó két jegye vibrálva villog, ezzel mutatja, hogy most ezt lehet beállítani. Ha ekkor hosszan nyomom a gombot, akkor az évszám felfelé számol egészen 2050-ig, ott visszaugrik 2021-re és újra felfelé számol. Az aktuális évnél el kell engedni a nyomógombot. Rövid gombnyomásra jön a következő adat, a hónap. Hosszú gombnyomással számolgatunk januártól decemberig. És így megy tovább minden dátum és idő és egyéb paraméter beállítása. Az értékek a következő adat megjelenésekor azonnal tárolásra kerülnek a DS3231 chip-ben, illetve az eeprom-ban. Néhány fotó a setup képernyőkről (sorrendben)

Mivel a képeken nem látható, hogy a nyomógomb elengedett állapotában mi villódzik igen gyorsan (vibrál), bekarikáztam az érintett képernyő részletet.

Így néz ki az óra a padlásról begyűjtött régi Philips hangfalon, amivel igen jól szólt!

Ezzel a hangfallal túl sok volt a basszus, ezért nagyon jót tett a Genius dobozhang az érthetőségnek. Sajnos a Géniusz hangszóróval még küzdök, mert az 4 ohm-os, és ha rádugom az mp3 hangszóró kimenetére, akkor nem indul el az óra bekapcsoláskor. Utólag rádugva működik! A Philips 8 ohm-os, ezért ez fejlesztéskor nem okozott gondot. Lehet, hogy kerítenem kell egy 4 ohm körüli soros ellenállást a Geniusz hangszóróba, és ezzel oldom meg a problémát. Amúgy sem kell nagy hangerő, 25-ös hangerő szinten a 30-ból már szinte túl hangos!

Közben a fenti problémára is meg lett a megoldás! Nem a 4 ohm-os Genius hangszóró a hibás. Az 5V-os tápot egy selejtezett Nokia telefon töltője szolgáltatta. Ez még az ógörög korból való, és csak 400mA áramot adott. Kicseréltem egy 2A-es modernebb darabra, és már bekapcsol az óra a hangfallal. Sokat szívok mostanában a tápegységekkel, még ha jók, akkor is!

És végül az alaposan felkommentezett forráskód! Ez egy hosszabb 1500 soros program. Itt most egybemásoltam, de fejlesztéskor már az Arduino IDE lapjain tartom logikusan szétvágott darabokban. A hozzám hasonló kezdőknek adnám át praktikus tanácsként, hogy a forrást szedjék szét darabokra, így könnyebb navigálni a függvények között. Ehhez az IDE szerkesztőjében az állománynév sorában a jobb szélen található egy kicsike „pöcök”, ott lehet új füzetlapot nyitni. Ezért kerül egy megkezdett program forrás állomány mindig alkönyvtárba, hogy abban legyenek a forrás állományok, amiket így létrehozunk! AZ alábbi képen látható, hogy néz ki a részekre szedett forrás lapokra bontva. Az említett pöcök a lap fülekkel egy sorban jobbra, a képen épp rákattintottam:

/***********************************
* Ledmatrix kivezetések bekötése:  *
* D3 - CS                          *
* D4 - CLK                         *
* D5 - DIN                         *
* D2 - Nyomógomb                   *
* D6 - Mp3 busy jel bemenet        *
* D10 - RX                         *
* D11 - TX                         *
* A0 - TEKT4400 fototanzisztor     *
************************************/
#include <EEPROM.h>
#include <Wire.h>
#include "Arduino.h"
#include "SoftwareSerial.h"       //használunk egy szoftveres soros portot, hogy megmaradjon a valódi soros port a fejlesztéshez, hibakereséshez
#include "DFRobotDFPlayerMini.h"  //MP3 lejátszó programkönyvtára

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX   //beállítjuk a szoftveres soros portot, csak a TX kimenetet fogjuk használni belőle, mert az mp3 lejátszó nem küld semmit
DFRobotDFPlayerMini myDFPlayer;                      //myDFPlayer néven fogunk hivatkozni erre az mp3 lejátszó példányra

//Az óra használatához szükséges dolgok
#define CLOCK_ADDRESS 0x68  //a modulon található óra IC címe az I2C buszon. 

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

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


const byte font[] = {              //karakterképek 8x8 bites karaktertérképen balra rendezve (utolsó két oszlop üres)
                                   //minden byte egy-egy sor egymás alatt, legelső a legfelső
120,204,204,204,204,204,204,120,   //0 karakterkép
48,112,48,48,48,48,48,120,         //1 karakterkép
120,204,12,24,48,96,192,252,       //2 karakterkép
120,204,12,120,12,12,204,120,      //3 karakterkép
28,60,108,204,204,252,12,12,       //4 karakterkép
252,192,192,248,204,12,204,120,    //5 karakterkép
56,96,192,248,204,204,204,120,     //6 karakterkép
252,204,12,24,48,96,192,192,       //7 karakterkép
120,204,204,120,204,204,204,120,   //8 karakterkép
120,204,204,124,12,12,204,120,     //9 karakterkép
0,0,0,0,0,0,0,0};                  //üres karakterkép

const byte honap_font[]= {                                 //A hónap rövidített feliratai 8x16 képpontban (egy sor két egymást követő byte)
0,0,51,34,20,178,20,178,23,170,20,166,148,166,100,162,        //JAN
0,0,238,206,136,169,136,169,204,206,136,169,136,169,142,201,  //FEBR
0,128,136,28,217,146,170,82,138,92,139,210,138,82,138,82,     //MÁR
32,0,7,56,100,164,148,164,151,56,244,36,148,36,148,36,        //ÁPR
0,128,136,6,217,130,170,66,138,66,139,194,138,82,138,76,      //MÁJ
1,0,48,34,20,178,20,178,20,170,20,166,148,166,99,34,          //JÚN
1,0,48,32,20,160,20,160,20,160,20,160,148,160,99,60,          //JÚL
0,0,100,152,148,164,148,160,244,172,148,164,148,164,147,28,   //AUG
0,0,111,118,129,69,129,69,66,118,36,68,40,68,207,116,         //SZEP
0,0,100,190,148,136,149,8,150,8,149,8,148,136,100,136,        //OKT
0,0,137,145,202,81,202,81,170,81,154,74,154,74,137,132,       //NOV
0,0,231,152,148,36,148,32,151,32,148,32,148,36,231,152,       //DEC
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};                             //üres

const byte het_font[]= {                                   //hét napjainak rövidített feliratai 8x16 képpontban
1,0,144,62,151,136,148,8,247,8,148,8,148,8,151,136,           //HET
0,0,151,184,148,36,164,36,199,36,164,36,148,36,151,184,       //KED
0,0,119,188,128,160,128,160,97,56,18,32,20,32,231,188,        //SZE
0,36,99,128,148,36,132,36,131,36,128,164,144,164,103,24,      //CSÜ
1,0,224,34,151,178,148,50,231,42,132,38,132,38,135,162,       //PÉN
0,0,119,152,128,164,128,164,97,36,18,36,20,36,231,152,        //SZO
0,0,137,142,138,80,138,80,139,204,82,66,82,66,34,92,          //VAS
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};                             //üres

const byte start_font[]= {                                   //START felirat 8x32 képpontban
0,0,0,0,115,231,57,240,128,136,164,64,128,136,164,64,
112,143,184,64,8,136,164,64,8,136,164,64,112,136,164,64};

const byte setup_font[]= {                                   //SETUP felirat 8x32 képpontban
0,0,0,0,115,239,162,240,130,2,34,136,130,2,34,136,
115,194,34,240,10,2,34,128,10,2,34,128,115,226,28,128};

const byte aut_font[]= {                                   //NYÁRI: felirat 8x24 képpontban, és utolsó kijelzőn BE,KI felirat
0,0,0,0,0,0,16,0,231,132,0,0,0,148,148,149,38,64,148,164,
213,85,80,231,196,242,118,64,148,164,178,85,80,148,148,
146,85,64,231,148};

const byte ev_font[]= {                                   //az év beállításhoz használt felirat 8x24 képpontban
0,49,128,64,74,64,0,10,64,212,10,64,                       //ÉV:20
149,18,64,212,34,64,137,66,64,200,121,128};

const byte hang_font[]= {                                   //a hangerő beállításához használt felirat 8x24 képpontban
16,1,0, 48,16,128, 240,136,64, 244,68,64,                       //Hangszóró ikon hanghullámokkal
244,68,64, 240,136,64, 48,16,128, 16,1,0};

const byte bsta_font[]= {                                   //az óránkénti idő bemondás első időpontja (órája)
0,0,0, 16,192,0, 52,193,0, 242,193,128,                       //hangszóró ikon faltól induló nyíl
242,255,192, 242,193,128, 52,193,0, 16,192,0};

const byte bsto_font[]= {                                   //az óránkénti idő bemondás utolsó időpontja (órája)
0,0,0, 16,0,192, 52,4,192, 242,6,192,                       //hangszóró ikon falnak ütköző nyíl 
242,255,192, 242,6,192, 52,4,192, 16,0,192};

const byte ff_no_font[]= {                                   //hangszóró ikon, férfi és nő jel, utolsó kijelzőn FF,NŐ felirat
0,0,0,0,5, 16,112,16,0,5, 52,136,32,0,0, 242,137,192,238,146,
242,82,32,136,213, 242,34,32,204,245, 52,114,32,136,181,
16,33,192,136,146};

const byte cfok_font[]= {0,70,169,72,8,8,9,6,};               //celsius fok karakterképe 8x8 képpontban

const byte ho_tabla[] {  //Március utolsó vasárnapjának dátuma és október utolsó vasárnapjának dátuma 2021-2050-ig 2 byte-on
28,31,27,30,26,29,31,27,30,26,29,25,28,31,26,29,
25,28,31,27,30,26,28,31,27,30,26,29,25,28,30,26,
29,25,28,31,27,30,25,28,31,27,30,26,29,25,27,30,
26,29,25,28,31,27,29,25,28,31,27,30
};

//A MAX7219 chip paramcsai
const byte decode_mode=9;     //MAX7219 beállításakor a decode mód regiszter címe
const byte scan_limit=11;     //MAX7219 beállításakor scan imit regiszter címe
const byte intenzity=10;      //MAX7219 beállításakor intenzitás regiszter címe
const byte shut_down=12;      //MAX7219 beállításakor shut down mód regiszter címe
const byte disp_test=15;      //MAX7219 beállításakor a disp test regiszter címe

//A MAX7219 chip felé menő kivezetések
const byte adat_kimenet=5;     //MAX7219 adat in bemenetének vezérlésére szolgáló Arduino kimenet száma 
const byte cs_kimenet=3;       //MAX7219 CS bemenetének vezérlésére szolgáló Arduino kimenet száma
const byte clk_kimenet=4;      //MAX7219 CLK bemenetének vezérlésére szolgáló Arduino kimenet száma
const byte idozites=10;        //Késleltetetés ideje mikrosec-ben a MAX7219 adat beírás bitjei között
const byte sw=2;

//Fénymérés TEPT4400 fotó tranzisztorral. A rövidebb láb a kollektor, ez megy a tápfesz 5V-ra
//A hosszabb láb az emitter, ez egy 1Kohm ellenálláson keresztül megy a földre. Az emitterből
//vezetem a mérendő feszültséget az A6 bemenetre. Sötétben a mért fesz 0 körül, napsütésben 
//1000 körül. Megvilágítva nyit ki a tranzisztor és felhúzza a jelvezetéket a tápfeszre.
//A méréskor a tápfeszt veszem referenciának! Ez a program egy árnyékos szobában fog órát
//működtetni, ezért soha nem nyit ki a tranzisztor, mert nem süt rá a nap. Ezért 0 és 
//200-300 körüli értékek fordulnak elő. Sötétedéskor 0 és 10 körüli értékek fordulnak elő
//ezért nagyon nem lineárisan lettek elosztva a fényerő szintek.
int mert_fenyero[10]={0,0,0,0,0,0,0,0,0,0}; //az utolsó 10 mért fényerő értéke
int fenyertek=0;                            //az utolsó 10 mért fényerő érték átlaga
int pill_fenyero,elozo_fenyero;

byte aut_atall=1;
byte hang;       //hangerő értéke az idő és dátum kimondásakor
byte bsta;         //óránkénti bemondás első időpontja (órája)
byte bsto;         //óránkénti bemondás utolsó időpontja (órája)
bool ff_no=0;         //ha ennek értéke 1, akkor az mp3 által lejátszandó file indexéhez 95-öt hozzáadok, mert onnan kezdődnek ugyanazok a szavak, csak férfi hangon

bool szoko_ev;  //szökőév jelzéséhez
float homerseklet;

long ido_tmp=millis();    //egy másodperces óra lekérdezéshez segédváltozó, óra setup alatt az állított érték villogtatásához
long ido_tmp1=millis();
bool pont=0;
bool ora_setup=0;  //ha hosszú ideig nyomjuk a gombot, akkor az óra átmegy setup módba, ekkor értéke 1
byte setup_fazis=0;  //az óra beállítás fázisait jelzi 0-év,1-hó,2-nap,3-óra,4-perc,5-aut.nyári átállás, 
                     //6-hangerő, 7-bemondást kezdő időpontja (órája), 8-bemondás záró időpontja (órája), 9-Férfi női hang
bool sw_allapot1;  //nyomógomb állapot ciklus elején
byte lassit;       //segédváltozó ahhoz, hogy setup-ban a nyári óraállítás BE illetve KI felirata ne váltson olyan gyorsan

long sw_time;                  //nyomógomb lenyomás idejének figyeléséhez segédváltozó
bool sw_allapot=0;             //nyomógomb lenyomott állapota esetén 1
long vissza_time;               //visszakapcsolás óra kijelzés üzemmódba segédváltozója (20 sec időzítéséhez használom)
bool ism_tilt1=0;               //1-es gombon a hosszan nyomva tartás ismétlésének akadályozására. Akkor lesz 1, ha még nem engedte el a nyomógombot, de már egyszer letelt a 800msec
byte uzemmod=0;                 //nyomógomb rövid megnyomásakor lezajló folyamat követésére. 0-időkijelzés,1-dátum kijelzés,2-hőmérséklet kijelzés
byte szamol=0;                  //ezzel lassítom az üzemmód váltást, mert egy adatot 2 sec ideig akarok kint tartani, de a ciklus másodpercenként fut 

byte szo[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //ebben a tömbben gyűjtöm össze a kimondandó szó részek indexeit.
                           //Maximum 15 állományt fogunk tudni lejátszani, ha már nincs több lejátszandó, 
                           //akkor a következő tömbelem 0. Ha van 15 lejátszandó, akkor az index érték lesz
                           //15, és innen tudjuk, hogy le kell állítani a lejátszást
byte index=0;              //ez mondja meg, hogy éppen melyik állományt kell lejátszani. Ha értéke 15, akkor
                           //nincs lejátszás illetve már befejeztük. 15-re állítjuk az utolsó lejátszott állomány esetén is.
                           //A lejátszás indításakor 0-ra kell állítani a kezd nevű változót pedig 1-re.
long varakozas=millis();   //amikor elindítom a lejátszást, a lejátszón a busy jelvezeték nem vált azonnal 1-re, illetve
                           //rövid ideig még változik is. Ezért várok egy kis időt, amíg figyelni kezdem. Ehhez kell!
//ezek a konstansok csak a program könnyebb értelmezése miatt kellenek
const byte januar=60,elso=29,honap=87,hetfo=53,ora=84,perc=85,szunet=95;
const byte minusz=45,nulla=1,egy=2,ketto=3,tiz=11,husz=12,szaz=20,tizen=42,huszon=43,ezer=46,millio=47,milliard=48,egesz=49,ezred=50,szazad=51,tized=52;
byte bemond_fazis=0;
long setup_kilep=millis();

void setup() {
  Wire.begin();
  Serial.begin(115200);
  
  pinMode(6,INPUT);        //ide kötöttem az mp3 lejátszó busy jelét
  
  mySoftwareSerial.begin(9600);               //inicializáljuk a szoftveres soros portot
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //mp3 lejátszó inicializálása. Ha nem sikerült, akkor 0
    //Serial.println("MP3 player hiba!");       //valami hiba volt, nincs jól csatlakoztatva az mp3 lejátszó a 10 és 11-es kimenetekhez, vagy nincs benne sd kártya
                                              //mivel a soros port visszatérő ágát már be sem kötöttem (Arduino RX, ebben a programban 10-es kivezetés), ezért itt már 
                                              //nem igazán várhatok valós hibajelzést :-), ezért nem is kell ez a sor
  }
  //Serial.println("MP3 player OK!");           //mp3 lejátszó kész a működésre, csak fejlesztéskor kell ez a sor

  pinMode(adat_kimenet,OUTPUT);    //MAX7219 adatbemenete felé menő kimenet
  pinMode(cs_kimenet,OUTPUT);      //MAX7219 CS bemenete felé menő kimenet
  pinMode(clk_kimenet,OUTPUT);     //MAX7219 órajel bemenet felé menő kimenet
  digitalWrite(cs_kimenet,1);      //a max7219 CS bemenete 1-en van, amikor nincs kiválasztva, és nem kommunikálunk vele
  //MAX7219 alapértelmezett beállításai
  matrix_setup(disp_test,0);       //Display test kikapcsolva (minden led világítana, ha nem kapcsoljuk ki)
  matrix_setup(decode_mode,0);     //Decode mód kikapcsolása
  matrix_setup(scan_limit,7);      //Scan limit regiszter beállítása (8 számjegy kijelzését kapcsoljuk be)
  matrix_setup(shut_down,1);       //Shutdown kikapcsolva
  matrix_setup(intenzity,15);      //Intenzitás maximum
  //Kijelző törlése
  for (byte sor=0;sor<8;sor++) {   //Minden kijelzőn egyszerre írjuk ugyanazt a led sort
    digitalWrite(cs_kimenet,0);    //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,0);
    kileptet(sor+1,0);
    kileptet(sor+1,0);
    kileptet(sor+1,0);
    digitalWrite(cs_kimenet,1);     //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve 
                                    //ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
  pinMode(sw,INPUT);                //nyomógomb bemenete
  digitalWrite(sw,HIGH);            //felhúzó ellenállás be

 //************* Legelső óra beállítás és eeprom tartalom feltöltés ************************************/
  //EEPROM.put(0,(byte)1);       //alapértelmezetten be van kapcsolva az automatikus nyári óraállítás 
                                 //(és november utolsó vasárnapján a kikapcsolása)
  //EEPROM.put(1,(byte)1);       //az adott napon épp van nyári időszámítás 
  //EEPROM.put(2,(byte)15);      //hangerő az időpont kimondáskor
  //EEPROM.put(3,(byte)7);       //óránkénti idő kimondás kezdő időpontja (órája) 
  //EEPROM.put(4,(byte)18);      //óránkénti idő kimondás záró időpontja (órája)
  //EEPROM.put(5,(byte)1);       //Alapértelmezetten férfi hangon beszéljen az óra
  //figyelni kell, hogy a beállított dátumon épp van-e nyári időszámítás, és azzal szinkronban kell 
  //beállítani az eeprom tartalmat az 1-es eeprom címen
  //ds3231.masodperc=30;
  //ds3231.perc=59;
  //ds3231.ora=8;
  //ds3231.het_napja=6;
  //ds3231.nap=28;
  //ds3231.ho=5;
  //ds3231.ev=2022; 
  //setTime24();                 //óra beállítása: négyszög kimenő jelet kikapcsolja, 
                                 //32Khz-s kimenetet kikapcsolja és 24 órás üzemmódot állít be.
                                 //Beállítja a pontos időt a fenti változók értékével 
 //*************************************************/
  analogReference(DEFAULT);          //A tápfeszt veszi referenciának (5V)

  //eepromből áttültjük memória változókba az alapvető működési paramétereket
  EEPROM.get(0, aut_atall);     //automatikus nyári óraállítás
  EEPROM.get(2, hang);          //bemondási hangerő
  EEPROM.get(3, bsta);          //időbemondás kezdő órája
  EEPROM.get(4, bsto);          //időbemondás záró órája
  EEPROM.get(5, ff_no);         //férfi vagy női hang
  
  //bekapcsoláskor megmutatunk minden paramétert 
 // matrix_setup(intenzity,14);       //Intenzitás maximum
  aut_ir(aut_atall,0);
  delay(1000);
  hang_ir(hang,0);
  delay(1000);
  bsta_ir(bsta,0);
  delay(1000);
  bsto_ir(bsto,0);
  delay(1000);
  ff_no_ir(ff_no,0);
  delay(1000);
  homeresklet_ir(getTemperature());
  delay(1500);
  getTime24();
  if (aut_atall==1) {
    atallas_ell();
  }
  ev_ir(ds3231.ev-2000,0);
  delay(1500);

  elozo_fenyero=analogRead(A0);
  myDFPlayer.volume(hang);                      //Hangerőt beállítjuk állítjuk (0-30)
}


void loop() { 
  bemond_vezerles();                                          //ez a függvény indítja a bemondást, ha index változó értékét 0-ra állítottuk
                                                              //és a szo[] tömböt feltöltöttük a bemondandó tartalommal, nincs benn delay
                                                              //a loop fut tovább
  if (index==15 and ora_setup==0) {                           //amikor nyomógombot nyom, és nincs setup mód, és éppen nem is mond semmit,
                                                              //akkor elindítjuk az aktuális idő, aztán pedig a dátum és a hét napjának bemondását
                                                              //Szintén nincs benne delay, éa a loop fut tovább
    if (bemond_fazis==1 or bemond_fazis==2) {idobemondas();}  //egy rövid nyomógomb megnyomás a bemond_fazis változót 1-re álltja, és 
                                                              //ekkor indul a pillanatnyi idő és dátum bemondása
    if (bemond_fazis==3) {datumbemondas();}
  }
  //itt jönnek a nyomógomb ellenőrzés lépései
  //rövid (kisebb mint 700msec megnyomás indítja a dátum és hőmérséklet kijelzést, és a bemondást, ha épp a start és stop időpontok között vagyunk
  //Hosszú megnyomás setup módban (nagyobb mint 800msec) lépteti az éppen aktuális adat értékét a beállítandó adat kiválasztásához (év, hónap, nap stb.)
  //Hosszú megnyomás ha még nem vagyunk setup módban (nagyobb mint 5sec), elindítja a setup módot
  sw_allapot1=digitalRead(sw);    
  if (sw_allapot1==LOW and sw_allapot==0) {                      //megnyomtuk az 1-es gombot, indul az időzítés, hogy megtudjuk rövid vagy hosszú lenyomás lesz
    ism_tilt1=0;sw_allapot=1;sw_time=millis();
    vissza_time=millis();
  } 
  //ha hosszan nyomva tartotta a gombot, valamit csinálni kell amikor elengedte  
  if ((ora_setup==0 and sw_allapot1==LOW and sw_time+5000<millis() and sw_allapot==1 and ism_tilt1==0) or    //ha még nem vagyunk setup módban, akkor 5 sec után belépjünk
      (ora_setup==1 and sw_allapot1==LOW and sw_time+800<millis() and sw_allapot==1 and ism_tilt1==0))       //ha már setup-ban vagyunk, akkor 0.8 sec után az adat értékének léptetése indul
  {    
    //itt következik annak levizsgálása, hogy mennyi ideig tartottuk nyomva hosszan a nyomógombot 
    setup_kilep=millis();               //itt épp egy gombnyomásnak van vége, ezért innen indítom a 20 másodperces tétlenségi kilépést a setup módból
    if (ora_setup==0) {                 //nem voltunk setup módban, most az következik, biztos ami biztos, újra átolvassuk a paramétereket az eepromból
      EEPROM.get(0,aut_atall);
      EEPROM.get(2, hang);
      EEPROM.get(3, bsta);
      EEPROM.get(4, bsto);
      EEPROM.get(5, ff_no);
    }
    if (ora_setup==1) {                 //ez a setup mód, akkor lesz ora_setup=1, ha már egyszer benne voltunk ebben az if-ben
                                        //a következő loop() ciklusban vált 1-re, mert előtte még 0, és csak a setup előkészítése történik
      ido_tmp1=millis()-700;            //azért, hogy a következő do ciklus belső feltétele biztosan igaz legyen, mikor bele lépünk a ciklusba
      lassit=0;                         //ezzel lassítom az automatikus időszámítás értékének váltását. 700msec-enként váltana az érték, 
                                        //ami tül gyors, és ezért nehéz a setup-ban kiválasztani a szükséges állapotot, így csak minden második
                                        //ciklusban változtatom. A többinél nem kell, mert ott számlálókat léptetek, ott ez lenne lassú.
      do {
       sw_allapot1=digitalRead(sw);
        if (ido_tmp1+700<millis()) {
          //ha folyamatosan nyomjuk a gombot, akkor 700msec időnként kerülünk be az if ágba.
          //az éppen aktuális paramétert 700msec-enként növeljük (egy limit után újra 0 lesz)
          ido_tmp1=millis(); 
          switch (setup_fazis) {
            case 0:                                                //ebben a fázisban kiírjuk a setup feliratot, hogy tudja a kezelő, mi következik
              setup_ir(0);
              break;
            case 1:                                                //setup felirat után megnyomta röviden a gombot, villogtatni fogjuk az évet, mert azt lehet beállítani
              ds3231.ev++;if (ds3231.ev>2040) {ds3231.ev=2021;}; 
              ev_ir(ds3231.ev-2000,0);
              break;
            case 2:                                                //év beállítás után megnyomta röviden a gombot, megjelenítjük a hónapot és a napot, villogtatni fogjuk az hónapot, mert azt lehet beállítani
              ds3231.ho++;if (ds3231.ho>12) {ds3231.ho=1;}; 
              dat_ir(ds3231.ho,ds3231.nap,0,0);
              break;
            case 3:                                                //hónap beállítás után megnyomta röviden a gombot, villogtatni fogjuk az napot, mert azt lehet beállítani
              ds3231.nap++;
              szoko_ev=szokoev(ds3231.ev);
              if (
                 ((ds3231.ho==1 or ds3231.ho==3 or ds3231.ho==5 or ds3231.ho==7 or ds3231.ho==8 or ds3231.ho==10 or ds3231.ho==12) and ds3231.nap>31)
                 or
                 ((ds3231.ho==4 or ds3231.ho==6 or ds3231.ho==9 or ds3231.ho==11) and ds3231.nap>30)
                 or 
                 (szoko_ev==0 and ds3231.ho==2 and ds3231.nap>28)
                 or 
                 (szoko_ev==1 and ds3231.ho==2 and ds3231.nap>29)
                 ) {ds3231.nap=1;}; 
              dat_ir(ds3231.ho,ds3231.nap,0,0);
              break;
            case 4:                                               //hónap és nap beállítás után megnyomta röviden a gombot, megjelenítjük az órát és a percet, villogtatni fogjuk az órát, mert azt lehet beállítani
              ds3231.ora++;if (ds3231.ora>23) {ds3231.ora=0;}; 
              ido_ir(ds3231.ora,ds3231.perc,1,0,0);
              break;
            case 5:                                               //óra beállítás után megnyomta röviden a gombot, villogtatni fogjuk a percet, mert azt lehet beállítani
              ds3231.perc++;if (ds3231.perc>59) {ds3231.perc=0;}; 
              ido_ir(ds3231.ora,ds3231.perc,1,0,0);
              break;
            case 6:                                               //óra és perc beállítás után megnyomta röviden a gombot, megjelenítjük a nyári óraállítást, villogtatni fogjuk a a KI illetve BE feliratot, mert azt lehet beállítani
              aut_ir(aut_atall,0);
              lassit++;
              if (lassit==2) {
                if (aut_atall==0) {aut_atall=1;} else {aut_atall=0;} 
                aut_ir(aut_atall,0);
                lassit=0;
              }
              break;
            case 7:                  //Automatikus nyári óraállítás beállítás után megnyomta röviden a gombot, megjelenítjük a hangerő értéket, villogtatni fogjuk a hangerő értékét, mert azt lehet beállítani
              hang++;
              if (hang>30) {hang=1;}  
              hang_ir(hang,0);
              break;
            case 8:                 //Hangerő beállítás után megnyomta röviden a gombot, megjelenítjük a start időpontot, villogtatni fogjuk az óra értékét, mert azt lehet beállítani
              bsta++;
              if (bsta>23) {bsta=0;}  
              bsta_ir(bsta,0);
              break;
            case 9:                //Sttart időpont beállítás után megnyomta röviden a gombot, megjelenítjük a stop időpontot, villogtatni fogjuk az óra értékét, mert azt lehet beállítani
              bsto++;
              if (bsto>23) {bsto=bsta;}  
              bsto_ir(bsto,0);
              break;
            case 10:               //Stop időpont beállítás után megnyomta röviden a gombot, megjelenítjük a férfi és nő állapotot, villogtatni fogjuk az FF illetve NŐ feliratot, mert azt lehet beállítani
              if (ff_no==0) {ff_no=1;} else {ff_no=0;} 
              ff_no_ir(ff_no,0);
              break;
            case 11:
              ora_setup=0;uzemmod=0;sw_allapot1=1;
              break;
          }
        }
      } while (sw_allapot1==0);
    } 
    if (setup_fazis==11) {sw_allapot=1;}
    if (uzemmod==0) {ora_setup=1;} 
  }
  if (sw_allapot1==HIGH and sw_allapot==1) {                     //már nem nyomja az 1-es nyomógombot
    setup_kilep=millis();               //itt épp egy gombnyomásnak van vége, ezért innen indítom a 10 másodperces tétlenségi kilépést a setup módból
    sw_allapot=0;
    if (millis()-sw_time<800 and millis()-sw_time>20) {            //ha 20ms-nél tovább nyomta, de kevesebb mint 800msec-ig, akkor kijelzést váltunk 
                                                                                    //a dátumra és a hőmérsékletre, illetve ha setup módban vagyunk akkor a következő
                                                                                    //beállítandó adatra
      if (ora_setup==0) {           //röviden nyomta és nem volt setup módban, akkor indítjuk a dátum és hőmérséklet kijelzést
        bemond_fazis=1;                                    //ezzel elindul az időbemondás, és azt követően a dátumbemondás
        uzemmod=uzemmod+1;         //sorban jelezzük ki az adatokat, és ez a változó vezéreli, hogy éppen melyiket
        szamol=0;
        ido_tmp=ido_tmp-1000;
        if (uzemmod>3) {uzemmod=0;}  //minden adatot kijeleztünk, felvesszük a nyugalmi helyzetet, az időpont kijelzést
      }
      if (ora_setup==1) {                                  //setup módban voltunk és rövidet nyomott, jön a következő adat, vagy ha utolsón álltunk, 
                                                           //akkor az értékek beírása a DS3231 chip-be és az eeprom-ba


        //ezt még itt fejlesztem
        if (setup_fazis<6)  {   //beállítjuk az időt a DS3231 chip-ben is
          ds3231.het_napja=datum_hetnapja(ds3231.ev,ds3231.ho,ds3231.nap);
          setTime24();
        }
        if (setup_fazis==6)  {   //beírjuk az automatikus nyári óraállítás paraméter értéket az eeprom-ba
          EEPROM.put(0,aut_atall);
        }
        if (setup_fazis==7)  {   // beírjuk a hangerő paraméter értéket az eeprom-ba
          EEPROM.put(2,hang);
          myDFPlayer.volume(hang);                      //Hangerőt beállítjuk állítjuk (0-30)
        }
        if (setup_fazis==8)  {   // beírjuk a bemondás start idő paraméter értéket az eeprom-ba
          EEPROM.put(3,bsta);
        }
        if (setup_fazis==9)  {   // beírjuk a bemondás stop idő paraméter értéket az eeprom-ba
          EEPROM.put(4,bsto);
        }
        if (setup_fazis==10)  {   // beírjuk a férfi-nő paraméter értéket az eeprom-ba
          EEPROM.put(5,ff_no);
          setup_fazis=-1;ora_setup=0;
        }
        setup_fazis++;
      }
    }
  }  
  //ha nem vagyunk setup módban, akkor üzemmod változó mondja meg, hogy mit jelzünk ki
  //uzemmod=0 - időkijelzés
  //uzemmod=1 - dátum kijelzés
  //uzemmod=2 - hét napjának kijelzése
  //uzemmod=3 - hőmérséklet kijelzés
  if (ido_tmp+1000<millis() and ora_setup==0) {
    ido_tmp=millis();
    fenyero_beallitas(); //fénymérés és fényerő beállítás 
    getTime24();
    orankenti_bemondas();   //ellenőrzi, hogy éppen egész óra van-e, és ha igen, akkor elindítja az idő bemondását
    if (uzemmod==0) {
      if (aut_atall==1) {
        atallas_ell();
      }
      if (pont==0) {ido_ir(ds3231.ora,ds3231.perc,1,0,0);pont=1;}
      else {ido_ir(ds3231.ora,ds3231.perc,0,0,0);pont=0;}
    }
    if (uzemmod==1) {
      szamol++;
      if (szamol>2) {uzemmod=2;szamol=0;}
      dat_ir(ds3231.ho,ds3231.nap,0,0);
    }
    if (uzemmod==2) {
      szamol++;
      if (szamol>2) {uzemmod=3;szamol=0;}
      het_ir(ds3231.nap,ds3231.het_napja,0);
    }
    if (uzemmod==3) {
      szamol++;
      if (szamol>2) {uzemmod=0;}
      homeresklet_ir(getTemperature());
    }
  }
  
  //Ha setup módban vagyunk, akkor a setup_fazis mondja meg, hogy éppen milyen adat látszik a képernyőn, 
  //és ha épp nem nyomja folyamatosan a gombot, akkor villogtatjuk is gyorsan az éppen állítható adatot
  if (ora_setup==1) {
    if (setup_kilep+20000<millis() and setup_fazis<10) {ora_setup=0;uzemmod=0;sw_allapot1=0;setup_fazis=0;}  //ha 20 másodpercig egy érték beállításán ácsingózik, akkor kilépünk a setup módból
    if (ido_tmp+25<millis()) {
      //ebbe az if-be 25msec-enként megyünk bele, és egyik alkalommal kijelezzük az éppen állított adatot, másik alkalommal meg nem
      ido_tmp=millis();
      switch (setup_fazis) {
        case 0:     //setup felirat jelzi a beállítás kezdetét
          if (pont==0) {setup_ir(0);pont=1;}
          else {setup_ir(1);pont=0;}
          break;
        case 1:    //év beállításhoz villogtatás
          if (pont==0) {ev_ir(ds3231.ev-2000,0);pont=1;}
          else {ev_ir(ds3231.ev-2000,1);pont=0;}
          break;
        case 2:    //hó beállításhoz villogtatás
          if (pont==0) {dat_ir(ds3231.ho,ds3231.nap,0,0);pont=1;}
          else {dat_ir(ds3231.ho,ds3231.nap,1,0);pont=0;}
          break;
        case 3:    //nap beállításhoz villogtatás
          if (pont==0) {dat_ir(ds3231.ho,ds3231.nap,0,0);pont=1;}
          else {dat_ir(ds3231.ho,ds3231.nap,0,1);pont=0;}
          break;
        case 4:     //óra beállításhoz villogtatás
          if (pont==0) {ido_ir(ds3231.ora,ds3231.perc,1,0,0);pont=1;}
          else {ido_ir(ds3231.ora,ds3231.perc,1,1,0);pont=0;}
          break;
        case 5:     //perc beállításhoz villogtatás
          if (pont==0) {ido_ir(ds3231.ora,ds3231.perc,1,0,0);pont=1;}
          else {ido_ir(ds3231.ora,ds3231.perc,1,0,1);pont=0;}
          break;
        case 6:     //Automatikus átállás nyári időszámításra beállításhoz villogtatás
          if (pont==0) {aut_ir(aut_atall,0);pont=1;}
          else {aut_ir(aut_atall,1);pont=0;}
          break;
        case 7:     //Hangerő beállításhoz villogtatás
          if (pont==0) {hang_ir(hang,0);pont=1;}
          else {hang_ir(hang,1);pont=0;}
          break;
        case 8:     //Bemondás start idő beállításhoz villogtatás
          if (pont==0) {bsta_ir(bsta,0);pont=1;}
          else {bsta_ir(bsta,1);pont=0;}
          break;
        case 9:     //Bemondás stop idő beállításhoz villogtatás
          if (pont==0) {bsto_ir(bsto,0);pont=1;}
          else {bsto_ir(bsto,1);pont=0;}
          break;
        case 10:     //A férfi vagy női hang kiválasztásához ff vagy no villogtatása
          if (pont==0) {ff_no_ir(ff_no,0);pont=1;}
          else {ff_no_ir(ff_no,1);pont=0;}
          break;
      }
    }
  }
}


void bemond_vezerles() {
/***************************************************************************************************
 * Az itt következő programrészek a szo[] tömbben összeállított szavak végig mondását végzik el    *
 * amikor az index változót 0-ra állítjuk, akkor indul a szöveg kimondása. Közben a ciklus fut     *
 * tovább, csak akkor vesz el egy kis időt a következő szöveg elindítása az mp3 lejátszón, amikor  *
 * éppen befejeződött az előző szöveg lejátszása. A 6-os kivezetésen jelenik meg az mp3 lejátszó   *
 * busy jele, ami mindaddig 0, amig épp lejátszik valamit. Mivel a busy jel nem megy le azonnal    *
 * 0-ra lejátszás alatt, hanem változik néhányszor, a hang lejátszás indítása után kell egy kicsit *
 * várni, mielőtt figyelni kezdjük.                                                                *
 ***************************************************************************************************/  
  if (digitalRead(6)==1 and index<15 and millis()>varakozas+200) {   //éppen szabad az mp3 lejátszó, lehet neki parancsot küldeni, ha van mit lejátszani és
                                                                     //eltelt legalább 200msec az utolsó indítás óta, mert a busy jelnek be kell állni 0-ra
                                                                     //a lejátszás indítása után, hogy figyelhessem mikor fejezte be a lejátszást (1-re vált)
                                                                     //Kezdetben 100msec várakozást használtam, de egyes szavak kimondását kihagyta, így 200msec-re
                                                                     //kelet növelni a várakozási időt. 
    varakozas=millis();                                 //elindítjuk a várakozást, amivel várunk egy kicsit mielőtt a busy jelet ellenőriznénk (tranziensek 
                                                        //vannak a lejátszás elindítása után egy ideig a busy jelen)
    if (ff_no==1) {myDFPlayer.play(szo[index]+95);}     //ha férfi, akkor 95-öt kel hozzáadni az index értékhez. 95 női hangú file van és 95 férfi
    else {myDFPlayer.play(szo[index]);}
    index++;
    if (szo[index]==0) {                                //ha az index értékhez tartozó tömbelem 0, akkor azt jelenti, hogy vége a lejátszható részleteknek
      index=15;                                         //index=15 jelzi, hogy éppen nincs lejátszani való
    }
  }                     
}

void orankenti_bemondas() {
  if (ds3231.perc==0 and ds3231.masodperc==0 and ds3231.ora>=bsta and ds3231.ora<=bsto) {
    if (index==15 and ora_setup==0) {
      index=0;ido_szo(ds3231.ora,ds3231.perc,1);
    }
  }
}

void idobemondas() {
  if (bemond_fazis==1) {index=0;ido_szo(ds3231.ora,ds3231.perc,0);}
  bemond_fazis=2;
  if (index==15) {bemond_fazis=3;}
}

void datumbemondas() {
  index=0;datum_szo(0,ds3231.ho,ds3231.nap,1,ds3231.het_napja);
  bemond_fazis=0;
}

byte datum_hetnapja(int ev, byte ho, byte nap)
/*******************************************************************************
 * Ez a függvény paraméterként várja egy dátumból az évet, hónapot és napot.   *
 * Eredményként visszaadja a megadott dátum melyik napja a hétnek. A hét napja *
 * 1től 7-ig megadott érték, az 1 a hétfő, 7 a vasárnap.                       *
 *******************************************************************************/
{
  if (ho<1) { return 0;} //hónap napjainak száma nem lehet 0
  if (ho!=1 & ho!=3 & ho!=5 & ho!=7 & ho!=8 & ho!=10 & ho!=12 & nap>31) { return 0;}; //több napot adtunk meg a hónapnak, mint amennyi napja van
  if (ho!=4 & ho!=6 & ho!=9 & ho!=11 & nap>30) { return 0;} //több napot adtunk meg a hónapnak, mint amennyi napja van
  if (ho==2) { //ha február van, ellenőrizni kell a szökőév szerinti napokat is
    if (szokoev(ev)) { //megmondja, hogy az adott év szökőév-e, mert ha igen, akkor a február 29 napos
    if (nap>29) { return 0;}} //szökőév, és több napot adtunk meg
    else {
    if (nap>28) { return 0;}} //nem szökőév, és több napot adtunk meg
  }
  int ho_napjai[]={0,31,59,90,120,151,181,212,243,273,304,334,365}; //Az évből eltelet hónapok napjainak száma halmozva havonként nem szökőévben
  long elmult_nap=ev*365;                                           //Eddig ennyi napja volt az elmúlt éveknek a szökőévek figyelembevétele nélkül
  int elmult_szokonap=0;                                            //Ebbe a változóba számoljuk ki majd a szökőévekből adódó plusz napok számát
  int szn4=(ev-1)/4;                                                //Minden negyedik év szökőév (kivéve minden 100. év, de azt később levonjuk)
                                                                    //az aktuális évet nem szabad beleszámolni, mert az majd az aktuális év napjaiban benne lesz
  int szn100=(ev-1)/100;                                            //minden 100. év nem szökőév, ezt majd levonjuk, kivéve minden 400. év, azt meg mindjárt hozzáadjuk
  int szn400=(ev-1)/400;                                            //Minden 400. év mégiscsak szökőév
  elmult_szokonap=szn4-szn100+szn400;                               //így megkaptuk a szökőévekből adódó plusz napokat
  long akt_ev_nap=ho_napjai[ho-1]+nap;                              //Az eddig eltelt hónapok napjainak száma kiderül a tömbből, plusz hozzáadjuk az aktuális hónap napjait, ahol épp járunk
                                                                    //Ha az adott év szökőév, és már elmúlt február, akkor még egyet hozzá kell majd adni, mert a tömb egy nem szökőévre készült.
  long akt_ev_szokonap=0;
  if (ho>2) {
    if (szokoev(ev)) {
      akt_ev_szokonap++;                                            // ha az aktuális éveben már elmúlt február, és az év szökőév, akkor még egy napot hozzá kell adni
    }
  }
  long napok=elmult_nap+elmult_szokonap+akt_ev_nap+akt_ev_szokonap; //és ezzel megkaptuk Jézus születésének napja óta eltelt napok számát
  if (napok%7==0) {
    return 7;                                                       //ha pont vasárnap van, akkor maradék nélkül osztható 7-el, ezért ilyenkor 7-et adunk vissza
  }
  else {
    return napok%7;                                                 //a maradék az adott hétben eltelt napok száma (hétfő az 1)
  }
}

bool szokoev(int ev) {
/************************************************************************************
 * Ez a függvény paraméterként várja az évet (pl. 2022) és visszaadja bool értékben *
 * hogy a paraméterben megadott év szökőév, vagy sem.                               *
 ************************************************************************************/
  if (ev==0) {
    return false; //a 0.évet nem vesszük szökőévnek
  }
  bool szoko_ev=false;
  if (ev%4==0) { //ha néggyel osztva nem ad maradékot, akkor szökőév
    szoko_ev=true;
    if (ev%100==0) { //ha 100-al osztva nem ad maradékot, akkor nem szökőév
      szoko_ev=false;
      if (ev%400==0) {
        szoko_ev=true; //ha 400-al osztva nem ad maradékot, akkor mégis szökőév
      }
    }
  }
  return szoko_ev;
}


void atallas_ell() {  
/********************************************************************************************************
 * Ez a függvény ellenőrzi, hogy elérkezett-e a nyári időszámítás átállásának időpontja, s ha igen, és  *       
 * Az óra nincs nyári időszámításban, akkor az aktuális órához hozzáad egyet. Ha elérkezett a nyári     *
 * Időszámítás kikapcsolásának időpontja, akkor pedig levon az órából egyet.                            *
 * Nyári időszámítás bekapcsolása: minden év márciusának utolsó vasárnapján hajnali 2-kor át kell       *
 * állítani az órát 3-ra.                                                                               *
 * Nyári időszámítás kikapcsolása: minden év októberének utolsó vasárnapján hajnali 3-kor vissza        *
 * kell állítani az órát hajnali 2-re.                                                                  *
 *                                                                                                      *
 * A függvény akkor is megoldja az óra állítást, ha az óra nem volt áram alatt, és a DS3231 óra chip    *
 * épp elemről működött. A ds3231 magától nem tud nyári óraállítást végezni.                            *
 ********************************************************************************************************/
  byte akt_marc_dat=ho_tabla[(ds3231.ev-2021)*2];                 //a ho_tabla[] többől kiolvassuk, hogy az adott évben hányadikára esik március utolsó vasárnapja
  byte akt_okt_dat=ho_tabla[(ds3231.ev-2021)*2+1];                //a ho_tabla[] többől kiolvassuk, hogy az adott évben hányadikára esik október utolsó vasárnapja
  byte nyari=0;

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

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

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

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

  //Ha az óraállítás pillanatában az Arduino nincs áram alatt, és a DS3231 elemről működik, akkor nem történik meg az óra átállítás.
  //Ekkor az ezt követő első bekapcsoláskor kell az időt visszaállítani egy órával. Ha az óra által mutatott időpont a téli időszámítás
  //előtti pillanatban van (de a nyári időszámítás beállítási időpontja után) és az eeprom szerint nincs téli időszámításban, akkor kell
  //beállítani. Viszont ha a bekapcsolás éjfél és egy óra között történik, akkor nem visszaállítani kell az órát, hanem egy nappal előbbre
  //és 23 órára. Az egy nappal előbbre állítás miatt azonban akár hónapot is kell váltani, ha épp 1.-én ált a naptár.
  //Ha október van, de már elmúlt az óraállítás napja, vagy már elmúlt október, vagy már a következő évben vagyunk és március (nyári óraállítás
  //előtt, vagy már márciusban vagyunk de még nem jött el a nyári óraállítás dátuma, és az óra nincs téli időszámítás időpontban, akkor kell 
  //átállítani az időt.
  if (((ds3231.ho==10 && ds3231.nap>akt_okt_dat) || (ds3231.ho>10) || (ds3231.ho<3) || (ds3231.ho==3 && ds3231.nap<akt_marc_dat)) && nyari==1) {
    EEPROM.put(1,(byte)0);                                           //Az eepromban beállítjuk a téli időszámítást
    if (ds3231.ora==0) {                                             //Ha még 0 óra van, akkor előző napra kell beállni
      ds3231.ora=23;                                                 //Az előző napon ekkor 23 óra van
      ds3231.nap=ds3231.nap-1;                                       //csökkentjük a napot
      ds3231.het_napja=ds3231.het_napja-1;                           //csökkentjük a hét napját
      if (ds3231.het_napja==0) {  ds3231.het_napja=7;}               //ha a hét napja 0 lett (hétfőn fordulhat elő), akkor nem 0 nap következik, hanem 7 (vasárnap)
      if (ds3231.nap==0) {                                           //ha 1.-e volt, akkor hónapot is kell váltani
        ds3231.ho=ds3231.ho-1;                                       //csökkentjük a hónapot
        if (ds3231.ho==0) {                                          //ha a hónap január volt, akkor nem a 0. hónap jön, hanem az előző év decembere
          ds3231.ho=12;ds3231.nap=31;                                //az új dátum december 31
          ds3231.ev=ds3231.ev-1;                                     //csökkentjük az évet 
        }
        if (ds3231.ho==1 || ds3231.ho==3 || ds3231.ho==5 || ds3231.ho==7 || ds3231.ho==8 || ds3231.ho==10) {  ds3231.nap=31;}  //ezekben a hónapokban az előző hónap 31 napos, tehát az előzö nap 31.-e
        if (ds3231.ho==4 || ds3231.ho==6 || ds3231.ho==9 || ds3231.ho==11) {  ds3231.nap=30;} //ezekben a hónapokban az előző honap 30 napos, tehát az előző nap 30.-a
        if (ds3231.ho==2 && szokoev(ds3231.ev)) { ds3231.nap=29;}    //február utolsó napja van, ami 02.29, mert szökőévben vagyunk
        if (ds3231.ho==2 && !szokoev(ds3231.ev)) {  ds3231.nap=28;}  //február utolsó napja van, ami 02.28, mert nem szökőévben vagyunk
      }
    } 
    else {  ds3231.ora=ds3231.ora-1;}                                //nem 0 óra volt, így nyugodtan csökkenthetjük az órát 1-el.
    setTime24();                                                     //beállítjuk az órát az új időpontra
  } 
}


void setTime24() {
/*************************************************************************************************************
* Ezzel a függvénnyel lehet beállítani az időt. Egy dat_ido típusú és ds3231 nevű változót vár a működéshez. *
* Ezt a változót globális változóként célszerű létrehozni. A getTime24() függvény ugyanezt a változót        *
* tölti fel a ds3231 chipből kiolvasott dátummal és időponttal. Ha memóriában átírjuk a dátumot és időt      *
* a ds3231 változóban, akkor ez a függvény beírja a változó aktuális értékét a chip-be.                      *
* A dat_ido struktúra részleteit lásd a getTime24() függvény kommentjeiben!                                  *
**************************************************************************************************************/
  //status regiszter beállítása
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x0e);               //A control regiszterbe fogunk írni, azt címezzük meg
  Wire.write(0b01100011);         //BBSQW bit 1, vagyis elemes táplálásnál is működik az oszcillátor
                                  //ha 1-re állítanánk, elemes táplálásnál nem járna az óra, csak őrizni az utolsó időpontot
                                  //A RS2 és RS1 bit 0-val beállítja a négyszögjel kimenetet 1Hz-ra, ezen lehet változtatni:
                                  // 0b01101011 esetén 1024Khz, 0b01110011 esetén 4096Khz, 0b01111011 esetén 8192Khz.
                                  //A INTCN bit 0-val beállítja, hogy az INT/SQW kimenet beállított frekvenciájú jelet ad ki.
  //címbet a státus regiszter következik, nem kell megcímezni csak írni, és az adat oda kerül
  Wire.write(0b00000000);         //A status regiszterben töröljük az OSF fleg-et, ami 1-el jelzi majd, ha elemes táplálásnál 
                                  //nem működött az oszcillátor, vagyis az óra valószínűleg nem pontos.
                                  //Az EN32Khz bit-et is 0-ra írjuk, azaz letiltjuk a 32Khz-s kimenetet
  Wire.endTransmission();
  //dátum és időpont beállítása
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x00);
  Wire.write(dec_bcd(ds3231.masodperc));
  Wire.write(dec_bcd(ds3231.perc));
  Wire.write(dec_bcd(ds3231.ora) & 0b10111111);
  Wire.write(dec_bcd(ds3231.het_napja)); 
  Wire.write(dec_bcd(ds3231.nap));
  Wire.write(dec_bcd(ds3231.ho));
  Wire.write(dec_bcd(ds3231.ev-2000)); 
  Wire.endTransmission();
}

void getTime24() {
/****************************************************************************************************
 * Ez a függvény kiolvassa a DS3231 RTC óra chip-ből a dátumot és az időt és egy dat_ido típusú és  *
 * ds3231 navű változóba tölti azok aktuális pillanatnyi értékét.                                    *
 * A változót globális változóként célszerű létrehozni a program eljén:                             *
 * struct dat_ido {    // a dátum és idő beállításához illetve kiolvasásához a struktúrát           *
 * int ev;             //év tárolása a struktúrában (évszázadokkal kell megadni,                     *
 *                     //illetve így kapjuk meg az eredményt a dátum kiolvasásakor)                 *
 * byte ho;            //ho tárolása a struktúrában                                                 *
 * byte nap;           //nap tárolása a struktúrában                                                *
 * byte het_napja;     //hét napja a struktúrában (1-hétfő....7-vasárnap)                           *
 * byte ora;           //óra tárolása a struktúrában (24 órás üzemmódot fogunk használni)           *
 * byte perc;          //perc tárolása a struktúrában                                               *
 * byte masodperc;     //másodperc tárolása a struktúrában                                          *
 * bool pontos;        //ez a változó fogja megadni az IDO kiolvasását követően,                    *
 *                     //hogy pontos-e a kiolvasott időpont ha elemes működés közben leáll a        *
 *                     //DS3231 oszcillátora, akkor az "OSF" flag bebillen, és ezt olvassuk ki      *
 *};                                                                                                *
 *dat_ido ds3231;  //létrehozzuk az dat_ido típusú változónkat DS3231 változó néven                 *
 ****************************************************************************************************/
  //kiolvassa a dátumot és az időpontot 
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 7);
  ds3231.masodperc = bcd_Dec(Wire.read());
  ds3231.perc = bcd_Dec(Wire.read());
  ds3231.ora = bcd_Dec(Wire.read());
  ds3231.het_napja = bcd_Dec(Wire.read());
  ds3231.nap = bcd_Dec(Wire.read());
  ds3231.ho = bcd_Dec(Wire.read() & 0b01111111);
  ds3231.ev = bcd_Dec(Wire.read())+2000;
  //status regiszterből az OSF bit kiolvasása.
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x0f);
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 1);
  if (Wire.read()& 0b10000000) {ds3231.pontos=0;} else {ds3231.pontos=1;}  //1-el jelezzük, ha az óra valószínűleg pontos
}

float getTemperature() {
  // Kiolvassa a hőmérséklet értékét a 0x11h és 0x12h regiszterekből
  byte temp;
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x11);         //a DS3231 chip 0x11 és 0x12-es regisztere a hőmérséklet regiszter
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 2);         //2 byte-ot kérünk el a chip-től
  temp = Wire.read();                         //hőmérséklet MSB regisztere
  return float(temp) + 0.25*(Wire.read()>>6); //hőmérséklet LSB regiszterének kiolvasása
}

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

void ido_szo(int xora, byte xperc,bool bing) {
/********************************************************************************************************
 * Ez a függvény a szo[] tömbbe helyezi az idő kimondásához szükséges szavak index értékét kimondáshoz  *
 * szükséges sorrendben.                                                                                *
 * Paraméterek:                                                                                         *
 * ora        - az időpont órája                                                                        *
 * perc       - az időpont perce                                                                        *
 * bing       - az óránkénti bemondásnál szignált tesz a szöveg elé. Speciálisan a szignál a 191. file  *
 *              az SD kártyán, és ezt teszi be első hangnak                                             *
 ********************************************************************************************************/
  for (byte i=0;i<15;i++) {szo[i]=0;}    //tömb törlése
  byte index=0;
  if (bing==1) {szo[index]=191;index++;szo[index]=szunet;index++;}  //szignál az első tömbelembe, a második egy szünet
  byte h_tiz;
  byte h_egy;
  //óra ************************************
  h_tiz=xora/10;
  h_egy=xora-((long)h_tiz*10);
  if ((h_tiz==1) & (h_egy==0)) {szo[index]=tiz;index++;}
  if ((h_tiz==1) & (h_egy>0)) {szo[index]=tizen;index++;}
  if ((h_tiz==2) & (h_egy==0)) {szo[index]=husz;index++;}
  if ((h_tiz==2) & (h_egy>0)) {szo[index]=huszon;index++;}
  if (h_tiz>2) {szo[index]=tiz+h_tiz-1;index++;}
  if (h_egy>0) {szo[index]=egy+h_egy-1;index++;}
  szo[index]=ora;index++;
  if (xperc>0) {
    szo[index]=szunet;index++;    //az óra kimondása után beteszünk 0,2sec várakozást a szöveg tagolása érdekében
    //perc*************************************************
    h_tiz=xperc/10;
    h_egy=xperc-((int)h_tiz*10);
    if ((h_tiz==1) & (h_egy==0)) {szo[index]=tiz;index++;}
    if ((h_tiz==1) & (h_egy>0)) {szo[index]=tizen;index++;}
    if ((h_tiz==2) & (h_egy==0)) {szo[index]=husz;index++;}
    if ((h_tiz==2) & (h_egy>0)) {szo[index]=huszon;index++;}
    if (h_tiz>2) {szo[index]=tiz+h_tiz-1;index++;}
    if (h_egy>0) {szo[index]=egy+h_egy-1;index++;}
    szo[index]=perc;index++;
  }
}

void datum_szo(int ev, byte ho, byte nap, bool ho_nev, byte het_napja)
{
/*********************************************************************************************
 * Ez a függvény a szo[] tömbbe helyezi a dátum kimondásához szükséges szavak index értékét  *
 * kimondáshoz szükséges sorrendben.                                                         *
 * Paraméterek:                                                                              *
 * ev        - a dátumban megadott év, évszázadokkal együtt (pl. 2021). Ha az ev=0,          *
 *             akkor csak a hónapot mondja a hónap nevével                                   *
 * ho        - a dátum hónapja                                                               *
 * nap       - a dátum napja                                                                 *
 * ho_nev    - ha értéke 1, akkor a hónapokat a nevükkel mondja ki pl. "február",            *
 *             ha értéke 0, akkor a hónap sorszámával pl. "második hó"                       *
 * het_napja - ha 0, akkor nem kerül kimondásra a hét napja, ha értéke 1-7 közötti,          *
 *             akkor a dátum végén kimondja a hét napjának nevét is pl. ha 1, akkor "hétfő"  *
 *********************************************************************************************/
  for (byte i=0;i<15;i++) {szo[i]=0;}
  byte index=0;
  byte h_egyezer;
  byte h_egyszaz;
  byte h_tiz;
  byte h_egy;
  int maradek;
  //év ************************************
  szo[index]=szunet;index++;
  if (ev>0) {                           //ha az ev nagyobb mint 0 csak akkor mondjuk ki
    h_egyezer=ev/1000;
    maradek=ev-((long)h_egyezer*1000);
    h_egyszaz=maradek/100;
    maradek=maradek-((long)h_egyszaz*100);
    h_tiz=maradek/10;
    h_egy=maradek-((long)h_tiz*10);
    //ezer  
    if (h_egyezer>1) {szo[index]=egy+h_egyezer-1;index++;szo[index]=ezer;index++;}
    if (h_egyezer==1) {szo[index]=ezer;index++;}
    //ezernél kissebb rész  
    if (h_egyszaz!=0) {szo[index]=szaz+h_egyszaz-1;index++;}
    if ((h_tiz==1) & (h_egy==0)) {szo[index]=tiz;index++;}
    if ((h_tiz==1) & (h_egy>0)) {szo[index]=tizen;index++;}
    if ((h_tiz==2) & (h_egy==0)) {szo[index]=husz;index++;}
    if ((h_tiz==2) & (h_egy>0)) {szo[index]=huszon;index++;}
    if (h_tiz>2) {szo[index]=tiz+h_tiz-1;index++;}
    if (h_egy>0) {szo[index]=egy+h_egy-1;index++;}
    if (ev==0) {szo[index]=nulla;index++;}   //ha a kimondandó szám 0, akkor legalább egy 0-át mondani kell
    szo[index]=szunet;index++;    //az év kimondása után beteszünk 0,2sec várakozást a szöveg tagolása érdekében
  }
  //hónap ***************************************
  h_tiz=ho/10;
  h_egy=maradek-((long)h_tiz*10);
  if (ho_nev==1 or ev==0) {            //ha az ev=0 vagy a paraméter előírja, akkor nevével mondjuk a hónapot
    //hónap nevekkel kimondva
    szo[index]=januar+ho-1;index++;
  }
  else {
    //hónap sorszámmal kimondva
    szo[index]=elso+ho-1;index++;
    szo[index]=honap;index++;
  }
//  szo[index]=szunet;index++;    //a hónap kimondása után beteszünk 0,2 sec várakozást a szöveg tagolása érdekében
  //nap*************************************************
  h_tiz=nap/10;
  h_egy=nap-((int)h_tiz*10);
  if ((h_tiz==1) & (h_egy==0)) {szo[index]=tiz;index++;}
  if ((h_tiz==1) & (h_egy>0)) {szo[index]=tizen;index++;}
  if ((h_tiz==2) & (h_egy==0)) {szo[index]=husz;index++;}
  if ((h_tiz==2) & (h_egy>0)) {szo[index]=huszon;index++;}
  if (h_tiz>2) {szo[index]=tiz+h_tiz-1;index++;}
  if (h_egy>0) {szo[index]=egy+h_egy-1;index++;}
  szo[index]=szunet;index++;
  //het napja*******************************************
  if (het_napja>0) {
    szo[index]=hetfo+het_napja-1;index++;
  }  
}


void hang_ir (byte hang, bool set_hang) { 
/******************************************************************************************************************   
 * Amikor az idő bemondás hangerejét állítjuk be, ez a függvény jeleníti meg a                                    *
 * hangszóró szimbólumot, valamint a hengerő érték számjegyét.                                                    *
 * A hangszóró szimbólumot a hang_font[] tömbből vesszük, a számjegyeket a font[] tömbből.                        *
 * A setupban villogtatni is kell a számjegyet amikor épp beállítjuk az értékét,                                  *
 * erre szolgál a set_hang paraméter. Amikor értéke 0, akkor a számjegyek bitsorozatai                            *
 * bemásoljuk a kijelzőre menő bitsorozatba, amikor értéke 1, akkor csupa 0-át másolunk be.                       *
 * Hol 1-el, hol 0-val hívjuk meg a függvényt így érhető el a villogás.                                           *
 * paraméterek:                                                                                                   *
 * hang:     a hangerő értéke 0-30 között                                                                         *
 * hang_set: amikor setup-ban vagyunk akkor kell ez a paraméter, 0 hatására bemásoljuk a bitsorozatba a           *
 *           a hangerő számjegyeit, míg 1 esetén csupa 0-át másolunk be. Így érjük el, hogy a                     *
 *           számjegyek villogjanak a képernyőn, mert egyszer 1-el, egyszer pedig 0-val hívjuk meg ezt a függvényt*
 ******************************************************************************************************************/
  byte a1,a2;         //paraméter érték számjegyekre bontásához
  byte s1,s2;         //ezekben tárolom a karakter tömbökből indexérték alapján kimásolt bitsorozatokat
  byte b1,b2,b3,b4;   //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                      //4 mátrix kijelző mosul van, így mindegyiknek van egy változója
  a1=hang/10;
  a2=hang-a1*10;
  for (byte sor=0;sor<8;sor++) {           //a matrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
    b1=hang_font[sor*3];                   //balról első kijelző adott sorának tartalma
    b2=hang_font[sor*3+1];                 //balról második kijelző adott sorának tartalma
    if (set_hang==1) { 
      b3=hang_font[sor*3+2];               //balról harmadik kijlző adott sorának tartalma
      b4=0;                                //a negyedik kijelzőn egyik led-et sem kapcsoljuk be
    }
    else {
      s1=hang_font[sor*3+2];
      s2=font[a1*8+sor];
      s2=s2>>3;
      b3=s1|s2;                            //balról harmadik kijlző adott sorának tartalma
      s1=font[a1*8+sor];
      s2=font[a2*8+sor];
      s1=s1<<5;
      s2=s2>>2;
      b4=s1|s2;                            //balról negyedik kijlző adott sorának tartalma
    }
    //kiléptetjük a bitsorozatot a négy mártix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel 
                                          //a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}

void bsta_ir (byte bsta, bool set_bsta) {    //az évet évszázadok nélkül kell megadni
  //Amikor az idő bemondás kezdő időpontját (óráját) állítjuk be (bemondás start időpont), 
  //ez a függvény jeleníti meg a hangszóró és faltól induló nyilacska szimbólumot, 
  //valamint kezdő óra érték számjegyét.
  //A szimbólumokat a bsta_font[] tömbből vesszük, a számjegyeket a font[] tömbből.
  //A setupban villogtatni is kell a számjegyet amikor épp beállítjuk az értékét, 
  //erre szolgál a set_bsta paraméter. Amikor értéke 0, akkor a számjegyek bitsorozatai
  //bemásoljuk a kijelzőre menő bitsorozatba, amikor értéke 1, akkor csupa 0-át másolunk be. 
  //Hol 1-el, hol 0-val hívjuk meg a függvényt így érhető el a villogás. 
  //paraméterek:
  //bsta:     a kezdő óra értéke, ami 0 és 24 és ezek közötti numerikus érték lehet
  //bsta_set: amikor setup-ban vagyunk akkor kell ez a paraméter, 0 hatására bemásoljuk a bitsorozatba a 
  //          a záró óra számjegyeit, míg 1 esetén csupa 0-át másolunk be. Így érjük el, hogy a 
  //          számjegyek villogjanak a képernyőn, mert egyszer 1-el, egyszer pedig 0-val hívjuk meg ezt a függvényt
  byte a1,a2;         //paraméter érték számjegyekre bontásához
  byte s1,s2;         //ezekben tárolom a karakter tömbökből indexérték alapján kimásolt bitsorozatokat
  byte b1,b2,b3,b4;   //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                      //4 mátrix kijelző modul van, így mindegyiknek van egy változója
  a1=bsta/10;
  a2=bsta-a1*10;
  for (byte sor=0;sor<8;sor++) {           //a mátrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
    b1=bsta_font[sor*3];
    b2=bsta_font[sor*3+1];
    if (set_bsta==1) {
      b3=bsta_font[sor*3+2];
      b4=0;
    }
    else {
      s1=bsta_font[sor*3+2];
      s2=font[a1*8+sor];
      s2=s2>>3;
      b3=s1|s2;
      s1=font[a1*8+sor];
      s2=font[a2*8+sor];
      s1=s1<<5;
      s2=s2>>2;
      b4=s1|s2;
    }
    //kiléptetjük a bitsorozatot a négy mátrix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}

void bsto_ir (byte bsto, bool set_bsto) {    //az évet évszázadok nélkül kell megadni
  //Amikor az idő bemondás záró időpontját (óráját) állítjuk be (bemondás stop időpont), 
  //ez a függvény jeleníti meg a hangszóró és falnak ütköző nyilacska szimbólumot, 
  //valamint záró óra érték számjegyét.
  //A szimbólumokat a bsto_font[] tömbből vesszük, a számjegyeket a font[] tömbből.
  //A setupban villogtatni is kell a számjegyet amikor épp beállítjuk az értékét, 
  //erre szolgál a set_bsto paraméter. Amikor értéke 0, akkor a számjegyek bitsorozatai
  //bemásoljuk a kijelzőre menő bitsorozatba, amikor értéke 1, akkor csupa 0-át másolunk be. 
  //Hol 1-el, hol 0-val hívjuk meg a függvényt így érhető el a villogás. 
  //paraméterek:
  //bsto:     a záró óra értéke, ami a kezdő óra (bsta) és 24 és ezek közötti numerikus érték lehet
  //bsto_set: amikor setup-ban vagyunk akkor kell ez a paraméter, 0 hatására bemásoljuk a bitsorozatba a 
  //          a záró óra számjegyeit, míg 1 esetén csupa 0-át másolunk be. Így érjük el, hogy a 
  //          számjegyek villogjanak a képernyőn, mert egyszer 1-el, egyszer pedig 0-val hívjuk meg ezt a függvényt
  byte a1,a2;         //paraméter érték számjegyekre bontásához
  byte s1,s2;         //ezekben tárolom a karakter tömbökből indexérték alapján kimásolt bitsorozatokat
  a1=bsto/10;
  a2=bsto-a1*10;
  byte b1,b2,b3,b4;   //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                      //4 mátrix kijelző modul van, így mindegyiknek van egy változója
  for (byte sor=0;sor<8;sor++) {           //a mátrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
    b1=bsto_font[sor*3];
    b2=bsto_font[sor*3+1];
    if (set_bsto==1) {
      b3=bsto_font[sor*3+2];
      b4=0;
    }
    else {
      s1=bsto_font[sor*3+2];
      s2=font[a1*8+sor];
      s2=s2>>3;
      b3=s1|s2;
      s1=font[a1*8+sor];
      s2=font[a2*8+sor];
      s1=s1<<5;
      s2=s2>>2;
      b4=s1|s2;
    }
    //kiléptetjük a bitsorozatot a négy mátrix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}



void aut_ir (bool aut,bool set_aut) {    
  //Amikor az automatikus nyári időszámítás beállítását  állítjuk be (automatikus be vagy ki), 
  //ez a függvény jeleníti meg a "NYARI" feliratot és a "BE" illetve "KI" karaktereket.
  //Ha a setup során hosszan nyomjuk a nyomógombot, akkor ciklikusan váltogatja a BE és a KI 
  //feliratokat, és ahol elengedjük a gombot az lesz beállítva.
  //A setupban villogtatni is kell az BE illetve KI felirat részeket, erre szolgál a set_aut
  // paraméter. Amikor értéke 0, akkor az BE illetve KI feliratot bemásoljuk a bitsorozatba,
  //amikor értéke 1, akkor csupa 0-át másolunk be. Hol 1-el, hol 0-val hívjuk meg a függvényt
  //így érhető el a villogás. A "NYÁRI" felirat az aut_font[] tömbben található, innen másoljuk
  //ki. A tömbben kétszer van meg minden, egy BE és egy KI karakter sorozattal az utolsó mátrix kijelzőre.
  //paraméterek:
  //aut:     0 esetén KI felirat, 1 esetén BE felirat
  //aut_set: amikor setup-ban vagyunk akkor kell ez a paraméter, 0 hatására bemásoljuk a bitsorozatba a BE 
  //         vagy KI bitképét, míg 1 esetén csupa 0-át másolunk be. Így érjük el, hogy a BE illetve KI betűk
  //         villogjanak a képernyőn, mert egyszer 1-el, egyszer pedig 0-val hívjuk meg ezt a függvényt
  byte b1,b2,b3,b4;   //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                      //4 mátrix kijelző modul van, így mindegyiknek van egy változója
  for (byte sor=0;sor<8;sor++) {           //a mátrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
    b1=aut_font[sor*5];
    b2=aut_font[sor*5+1];
    b3=aut_font[sor*5+2];
    if (set_aut==1) {b4=0;}
    else {
      if (aut==1) {b4=aut_font[sor*5+3];}
      else {b4=aut_font[sor*5+4];}
    }
    //kiléptetjük a bitsorozatot a négy mátrix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}

void ff_no_ir (bool ff_no,bool set_ff_no) {    
  //Amikor a bemondás hangját állítjuk be a setup során, ez a függvény jeleníti meg a hangszóró és
  //férfi, nő valamint az FF és NŐ karaktereket. Ha a setup során hosszan nyomjuk a nyomógombot,
  //akkor ciklikusan váltogatja a FF-t és a NŐ-t, és ahol elengedjük a gombot az lesz beállítva.
  //A setupban villogtatni is kell az FF illetve NŐ felirat részeket, erre szolgál a set_ff_no
  // paraméter. Amikor értéke 0, akkor az FF illetve NŐ feliratot bemásoljuk a bitsorozatba,
  //amikor értéke 1, akkor csupa 0-át másolunk be. Hol 1-el, hol 0-val hévjuk meg a függvényt
  //így érhető el a villogás. A szimbólumok (hangszóró, férfi és nő jel) az ff_no_font[] tömbben
  //találhatók, innen másoljuk ki. A tömbben kétszer van meg minden, egy FF és egy NŐ karakter 
  //sorozattal az utolsó mátrix kijelzőre.
  //paraméterek:
  //ff_no:     0 esetén FF felirat, 1 esetén NŐ felirat
  //ff_no_set: amikor setup-ban vagyunk akkor kell ez a paraméter, 0 hatására bemásoljuk a bitsorozatba az FF 
  //           vagy NŐ bitképét, míg 1 esetén csupa 0-át másolunk be. Így érjük el, hogy az FF illetve NŐ betűk
  //           villogjanak a képernyőn, mert egyszer 1-el egyszer 0-val hívjuk meg ezt a függvényt
  byte b1,b2,b3,b4;   //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                      //4 mátrix kijelző modul van, így mindegyiknek van egy változója
  for (byte sor=0;sor<8;sor++) {           //a mátrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
    b1=ff_no_font[sor*5];
    b2=ff_no_font[sor*5+1];
    b3=ff_no_font[sor*5+2];
    if (set_ff_no==1) {b4=0;}
    else {
      if (ff_no==1) {b4=ff_no_font[sor*5+3];}
      else {b4=ff_no_font[sor*5+4];}
    }
    //kiléptetjük a bitsorozatot a négy mátrix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}


void ido_ir (byte ora, byte perc,bool kettospont, bool set_ora, bool set_perc) {
  //Ez a függvény az időt (óra, perc) jeleníti meg a kijelzőn. Paraméterként megkapja
  //az órát és a percet, ezeket az adatokat számjegyekre bontja és a font[] tömbből 
  //kiveszi a számjegyek bitképét és összemásolja soronként egy 16 bites bitsorozatba.
  //Mivel az órabeállításkor villogtatni kell vagy az órát vagy a percet, ezért megkapja
  //a set_ora és a set_perc paraméterekben, hogy melyiket kell villogtatni. A villogás
  //jelzi a setup folyamatban, hogy a hosszan nyomjuk a nyomógombot, akkor melyik adat fog változni.
  //paraméterek:
  //ora: 0-tól 24-ig az óra
  //perc: 0-59.ig a perc
  //kettospont: ha értéke 1, akkor a képernyő közepén megjelenik egy kettőspont, ha 0 akkor nem. Másodpercenként
  //            váltogatva hívjuk meg a függvényt, így másodperces ciklusban villog a kettőspont az óra és a perc között.
  //set_ora:    amikor setup-ban vagyunk akkor kell ez a paraméter, 0 hatására bemásoljuk a bitsorozatba az óra 
  //            számjegyeinek bitképét, míg 1 esetén csupa 0-át másolunk be. Így érjük el, hogy az óra számjegyei
  //            villogjanak a képernyőn, mert egyszer 1-el egyszer 0-val hívjuk meg ezt a függvényt
  //set_perc:   ugyanúgy működik mint a set_ora, csak ez a percet villogtatja a setup azon részében, amikor a 
  //            percet állítjuk be
  byte b1,b2,b3,b4;   //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                      //4 mátrix kijelző modul van, így mindegyiknek van egy változója
  byte a1,a2,a3,a4;   //paraméter érték számjegyekre bontásához
  byte s1,s2;         //ezekben tárolom a karakter tömbökből indexérték alapján kimásolt bitsorozatokat
  a1=ora/10;
  a2=ora-a1*10;
  if (a1==0) {a1=10;}
  a3=perc/10;
  a4=perc-a3*10;
  for (byte sor=0;sor<8;sor++) {    //a mátrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
    if (set_ora==1) {b1=0;b2=0;kettospont=1;}
    else {
      s1=font[a1*8+sor];   //kiolvassuk a karakter tömbből a az óra számjegyének balról első számjegyét (tízes számjegy)
      s2=font[a2*8+sor];   //kiolvassuk a karakter tömbből az óra számjegyének balról második számjegyét (egyes számjegy)
      s2=s2>>7;            //az egyes számérték bitjeit 7-el jobbra toljuk mert az első mátrix kijelző első hét bitje a 
                           //tízes számjegy s1 első hét bitje, és e mögé kell egy bitet másolni
      b1=s1|s2;            //itt másoljuk a tízes számjegy első hét bitjéhez az egyes számjegy 1 bitjét
      s1=font[a2*8+sor];   //újra kiolvassuk az egyes számjegy bitsorozatát
      s1=s1<<1;            //itt meg balra toljuk egyet, mert egy bit az előző kijelzőn van, hat bit meg már a második kijelzőre szorul
      b2=s1;
    }
    if (set_perc==1) {b3=0;b4=0;kettospont=1;}
    else {
      s1=font[a3*8+sor];
      s1=s1>>3;
      b3=s1;
      s1=font[a3*8+sor];
      s2=font[a4*8+sor];
      s1=s1<<5;
      s2=s2>>2;
      b4=s1|s2;
    }
    if (kettospont==1){              //ha időt jelenítünk meg és a kettospont=1 akkor egy kettőspontot teszünk a kijelző közepére
      if (sor==1 or sor==2 or sor==5 or sor==6) {
        b2=b2|B00000001;
        b3=b3|B10000000;
      }
    }
    //kiléptetjük a bitsorozatot a négy mátrix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}

void ev_ir (byte ev, bool set_ev) {    
  //A függvény a paraméterként számként megkapja az év értékét évszázadok nélkül.  
  //Az adatot átalakítja számjegyekké, amiknek a bitképét előveszi a font[]
  //tömbből, amit aztán kiírunk a MAX7219 chip-be. 
  //Mivel 4 kijelzőre kell kiléptetni az adatokat, össze kell másolgatni az összes kijelző adott sorának bitképét
  //és egyben kiléptetni, tehát a kijelző láncra 16 bitet kell kiírni soronként.
  //paraméterek:
  //ev: 0-tól 99-ig az év (ebben a programban csak 50-ig megy, mert a setup-ban max 2050-et lehet beállítani)
  //set_ev: amikor setup-ban vagyunk akkor kell ez a paraméter, 0 hatására bemásoljuk a bitsorozatba az ev 
  //        karaktereinek bitképét, míg 1 esetén csupa 0-át másolunk be. Így érjük el, hogy az év
  //        villog a képernyőn, mert egyszer 1-el, egyszer 0-val hívjuk meg ezt a függvényt
  byte a1,a2;         //paraméter érték számjegyekre bontásához
  byte s1,s2;         //ezekben tárolom a karakter tömbökből indexérték alapján kimásolt bitsorozatokat
  byte b1,b2,b3,b4;   //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                      //4 mátrix kijelző modul van, így mindegyiknek van egy változója
  a1=ev/10;
  a2=ev-a1*10;
  for (byte sor=0;sor<8;sor++) {           //a mátrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
    b1=ev_font[sor*3];
    b2=ev_font[sor*3+1];
    if (set_ev==1) {
      b3=ev_font[sor*3+2];
      b4=0;
    }
    else {
      s1=ev_font[sor*3+2];
      s2=font[a1*8+sor];
      s2=s2>>3;
      b3=s1|s2;
      s1=font[a1*8+sor];
      s2=font[a2*8+sor];
      s1=s1<<5;
      s2=s2>>2;
      b4=s1|s2;
    }
    //kiléptetjük a bitsorozatot a négy mátrix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}

void start_ir (bool set_start) {    
  //a képernyőre a start feliratot írja ki azzal, hogy a start_font[] tömbből soronként kilépteti
  //a felirat bitképét. A feliratot villogtatni is kell a setup folyamat során, mert ez jelzi
  //hogy egy gombnyomással beírjuk a beállított értékeket és paramétereket a MAX7219 chip-be és az 
  //eeprom-ba, és ehhez kell a set_start bemenő paraméter. Ha értéke 0 akkor
  //megjelenik a felirat, ha értéke 1. akkor nem. Hol 0-val, hogy 1-el hívjuk meg a függvényt
  //így villog a felirat.
  byte b1,b2,b3,b4;   //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                      //4 mátrix kijelző modul van, így mindegyiknek van egy változója
  for (byte sor=0;sor<8;sor++) {           //a mátrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
    if (set_start==1) {b1=0;b2=0;b3=0;b4=0;}
    else {
    b1=start_font[sor*4];
    b2=start_font[sor*4+1];
    b3=start_font[sor*4+2];
    b4=start_font[sor*4+3];
    }
    //kiléptetjük a bitsorozatot a négy mátrix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}

void setup_ir (bool set_setup) {    
  //a képernyőre a setup feliratot írja ki azzal, hogy a setup_font[] tömbből soronként kilépteti
  //a felirat bitképét. A feliratot villogtatni is kell a setup folyamat során, mert ez jelzi
  //hogy elindult a folyamat, és ehhez kell a set_setup bemenő paraméter. Ha értéke 0 akkor
  //megjelenik a felirat, ha értéke 1. akkor nem. Hol 0-val, hogy 1-el hívjuk meg a függvényt
  //így villog a felirat.
  byte b1,b2,b3,b4;   //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                      //4 mátrix kijelző modul van, így mindegyiknek van egy változója
  for (byte sor=0;sor<8;sor++) {           //a mátrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
    if (set_setup==1) {b1=0;b2=0;b3=0;b4=0;}
    else {
    b1=setup_font[sor*4];
    b2=setup_font[sor*4+1];
    b3=setup_font[sor*4+2];
    b4=setup_font[sor*4+3];
    }
    //kiléptetjük a bitsorozatot a négy mátrix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}


void dat_ir (byte ho, byte nap, bool set_ho, bool set_nap) {
  //A függvény a paraméterként számként megkapja a hónapot és a hónap napját.  
  //Mindkét adatot átalakítja számjegyekké, amiknek a bitképét előveszi a honap_font[] és font[]
  //tömbökből, amit aztán kiírunk a MAX7219 chip-be. A hónap napjának karakter képét a 
  //font[] tömbben hoztuk létre, ebből emeli ki. A hónap rövidített három karakteres névvel jelenik meg,
  //ennek bitképe a honap_font[] tömbben található, minden egyes hóna külön-külön. 
  //Mivel 4 kijelzőre kell kiléptetni az adatokat, össze kell másolgatni az összes kijelző adott sorának bitképét
  //és egyben kiléptetni, tehát a kijelző láncra 16 bitet kell kiírni soronként.
  //paraméterek:
  //ho: 0-tól 12-ig a hónap
  //nap: az adott nap száma (dátum napja) 1-31
  //set_ho: amikor setup-ban vagyunk akkor kell ez a paraméter, 0 hatására bemásoljuk a bitsorozatba a ho 
  //        karaktereinek bitképét, míg 1 esetén csupa 0-át másolunk be. Így érjük el, hogy a hónap
  //        megnevezése villog a képernyőn, mert egyszer 1-el egyszer 0-val hívjuk meg ezt a függvényt
  //set_nap: ugyanúgy működik mint a set_ho, csak ez a napot villogtatja a setup azon részében, amikor a 
  //        napot állítjuk be
  byte a1,a2,a3,a4;   //paraméter érték számjegyekre bontásához
  byte s1,s2;         //ezekben tárolom a karakter tömbökből indexérték alapján kimásolt bitsorozatokat
  byte b1,b2,b3,b4;   //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                      //4 mátrix kijelző modul van, így mindegyiknek van egy változója
  a3=nap/10;
  a4=nap-a3*10;
  for (byte sor=0;sor<8;sor++) {           //a mátrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
    if (set_ho==1) {b1=0;b2=0;}
    else {
      b1=honap_font[(ho-1)*16+sor*2];
      b2=honap_font[(ho-1)*16+sor*2+1];
    }
    if (set_nap==1) {b3=0;b4=0;}
    else {
      if (nap<10) {a3=10;};
      s1=font[a3*8+sor];
      s1=s1>>3;
      b3=s1;
      s1=font[a3*8+sor];
      s2=font[a4*8+sor];
      s1=s1<<5;
      s2=s2>>2;
      b4=s1|s2;
    }
    if (sor==7) {b3=b3|B10000000;}
    //kiléptetjük a bitsorozatot a négy mátrix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}

void het_ir (byte nap, byte het_napja, bool set_het) {
  //A függvény a paraméterként számként megkapja a hónap napját és a hét napját (1-7). A hét napját 
  //átalakítja három karakteres névvé (hétfő-vasárnapig), és a hónap napját és a hét napját soronként 
  //megjelenítendő bitképpé amit aztán kiírunk a MAX7219 chip-be. A hónap napjának karakter képét a 
  //font[] tömbben hoztuk létre, ebből emeli ki. Először a hónap napját felbontjuk két különálló 
  //egyjegyű számra, és ezekkel lehet megcímezni a font[] tömböt, amiből soronként ki lehet emelni az 
  //adott karakter bitsorozatát. A hét napjainak bitképe a het_font[] tömbben van. Minden nap 3 betűre 
  //van lerövidítve, és hét ilyen bitsorozat van ebben a tömbben.
  //Mivel 4 kijelzőre kell kiléptetni az adatokat, össze kell másolgatni az összes kijelző adott sorának bitképét
  //és egyben kiléptetni, tehát a kijelző láncra 16 bitet kell kiírni soronként.
  //paraméterek:
  //nap: 0-31 (nem ellenőrzi a hónap napjait)
  //het: 1-7, 1=hétfő
  //set_het: ha értéke 0, akkor a hét napjainak bitsorozatát írjuk a mátrix kijelzőre
  //         ha értéke 1, akkor csupa 0-át léptetünk ki a betűk bitképe helyett. Ez a setupban a hét napjainak
  //         villogtatására lett kitalálva, de a hét napjait immár nem kell beállítani, mert a dátumból
  //         a program kiszámolja magának. Benne hagytam a villogtatás lehetőségét, de nem használom, ez a paraméter mindig 0.
  byte a1,a2;         //paraméter érték számjegyekre bontásához
  byte s1,s2;         //ezekben tárolom a karakter tömbökből indexérték alapján kimásolt bitsorozatokat
  byte b1,b2,b3,b4;   //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                      //4 mátrix kijelző modul van, így mindegyiknek van egy változója
  a1=nap/10;
  a2=nap-a1*10;
  for (byte sor=0;sor<8;sor++) {           //a matrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
      s1=font[a1*8+sor];
      s2=font[a2*8+sor];
      s2=s2>>7;
      b1=s1|s2;
      s1=font[a2*8+sor];
      s1=s1<<1;
      b2=s1;
    if (set_het==1) {b3=0;b4=0;}
    else {
      b3=het_font[(het_napja-1)*16+sor*2];
      b4=het_font[(het_napja-1)*16+sor*2+1];
    }
    if (sor==7) {b3=b3|B10000000;}
    //kiléptetjük a bitsorozatot a négy mátrix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}

void homeresklet_ir (float homerseklet) {
  //AZ a függvény a paraméterként kapott hőmérséklet számadatot alakítja át soronként megjelenítendő bitképpé
  //amit aztán kiírunk a MAX7219 chip-be. A karakter képet a font[] tömbben hoztuk létre, ebből emeli ki.
  //Először felbontjuk a float típusú hőmérséklet értéket számjegyekre, és ezekkel lehet megcímezni a font[]
  //tömböt, amiből soronként ki lehet emelni ez adott karakter bitsorozatát.
  //Mivel 4 kijelzőre kell kiléptetni az adatokat, össze kell másolgatni az összes kijelző adott sorának bitképét
  //és egyben kiléptetni, tehát a kijelző láncra 16 bitet kell kiírni.
  byte b1,b2,b3,b4;        //segédváltozók, amikbe a karakterkép adott sorát töltöm be, és ebből léptetem ki a MAX7219 chip-be,
                           //4 mátrix kijelző modul van, így mindegyiknek van egy változója
  int h0=(int)(homerseklet*10);
  byte h1=h0/100;
  byte h2=(h0-h1*100)/10;
  byte h3=h0-h1*100-h2*10;
  if (h1==0) {
    h1=10;
  }
  byte s1,s2;                         //ezekben tárolom a karakter tömbökből indexérték alapján kimásolt bitsorozatokat                   
  for (byte sor=0;sor<8;sor++) {      //a mátrix kijelzőkbe soronként lehet beléptetni az infót, de mind a négy kijelzőnek ugyanabba a sorába
    s1=font[h1*8+sor];                //első karakter
    s2=font[h2*8+sor];                //második karakter
    s2=s2>>7;                         //második karakterből csak egy oszlop kell, a legelső
    b1=s1|s2;                         //első karakter és a második karakter első oszlopának összemásolása
    s1=font[h2*8+sor];                //második karakter kiolvasása újra
    b2=s1<<1;                         //második karakterből csak a 2. oszloptól kell (tehát csak öt oszlop)
    if (sor==7 or sor==6) {b2=b2|B00000010;}    //második és harmadik karakter két oszlopának összemásolása a tizedesponttal
    b3=font[h3*8+sor];                //harmadik karakter kiolvasása újra
    b4=cfok_font[sor];                //celsius fok karakterkép 
    //kiléptetjük a bitsorozatot a négy mátrix kijelzőbe. Sorba vannak kötve, egymásnak adják tovább az infót!
    digitalWrite(cs_kimenet,0);       //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
    kileptet(sor+1,b1);
    kileptet(sor+1,b2);
    kileptet(sor+1,b3);
    kileptet(sor+1,b4);
    digitalWrite(cs_kimenet,1);       //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
  }
}


/**********************************************************************************************
 * Megméri az A6 bemenetre kötött fotó tranzisztor és ellenállásosztóban az ellenállás        *
 * feszültségét. Ellenállás értéke 1Kohm. A fotó tranzisztor 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;
    for (byte j=9;j>0;j--) {mert_fenyero[j]=mert_fenyero[j-1];}
    int fenyero=analogRead(A0);
    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<=4) {ledmatfeny=0;}
    if (fenyertek<=8 & fenyertek>4) {ledmatfeny=1;}  
    if (fenyertek<=15 & fenyertek>8) {ledmatfeny=2;}  
    if (fenyertek<=30 & fenyertek>15) {ledmatfeny=3;}  
    if (fenyertek<=45 & fenyertek>30) {ledmatfeny=4;}  
    if (fenyertek<=60 & fenyertek>45) {ledmatfeny=5;}  
    if (fenyertek<=75 & fenyertek>60) {ledmatfeny=6;}  
    if (fenyertek<=90 & fenyertek>75) {ledmatfeny=7;}  
    if (fenyertek<=105 & fenyertek>90) {ledmatfeny=8;}  
    if (fenyertek<=120 & fenyertek>105) {ledmatfeny=9;}  
    if (fenyertek<=135 & fenyertek>120) {ledmatfeny=10;}  
    if (fenyertek<=150 & fenyertek>135) {ledmatfeny=11;}  
    if (fenyertek<=165 & fenyertek>150) {ledmatfeny=12;}  
    if (fenyertek<=200 & fenyertek>165) {ledmatfeny=13;}  
    if (fenyertek<=300 & fenyertek>200) {ledmatfeny=14;}  
    if (fenyertek>300) {ledmatfeny=15;} 
    //árnyékos lakásban kellett az óra gyengén látónak, ezért az éjszaka kivitelével azt akartam
    //hogy teljes fényerővel világítson, ezért nagyon szűk fényintenzitáson belül szabályoz.
    //300 felett már max fényerő. Úgy tapasztaltam, hogy olyan helyen ahol soha nem süt a nap 
    //az érzékelőre, 200 és 400 között van a mért érték maximuma.
    matrix_setup(intenzity,ledmatfeny);      //Intenzitás minimum
} 


void kileptet(byte bitkep1, byte bitkep2)  {
  //adatokat léptetek ezzel a függvénnyel a MAX7219 chip-be. A chip 8 sort kezel
  //bitkep1=a sor sorszáma, amibe a megjelenítendő adatot írjuk (0-7-ig lehet címezni)
  //bitkep2=az adat, amit bele írunk a regiszterbe, ez jelenik meg az adott sor led-jein bitenként
  for (byte i=0;i<8;i++) { //először a felső byte adatot fogjuk kiléptetni bitenként jobbról balra
    digitalWrite(adat_kimenet,(bitkep1<<i) & 128);
    digitalWrite(clk_kimenet,1);      //órajel felfutóél (beolvassa az adatot)
    digitalWrite(clk_kimenet,0);      //órajel lefutóél
  }
  delayMicroseconds(idozites);   
  for (byte i=0;i<8;i++) { //először a felső byte adatot fogjuk kiléptetni bitenként jobbról balra
    digitalWrite(adat_kimenet,(bitkep2<<i) & 128);
    digitalWrite(clk_kimenet,1);
    digitalWrite(clk_kimenet,0);
  }
}


void matrix_setup(byte mode_reg, byte ertek) {
  //a matrix kijelzőt vezérlő MAX7219 chip mode regiszterébe írok ezzel a függvénnyel működési beállításokat, pl fényerő beállítás
  //mode_reg= a mód regsizter címe a chip-ben, ertek= az az érték, amit a regiszterbe írok
  digitalWrite(cs_kimenet,0);            //cs bemenetre 0-at kapcsolunk, kijelző kiválasztva, jöhetnek az adatok
  delayMicroseconds(idozites);           //várunk kicsit, hogy legyen idő a chipnek beállni az adatfogadásre
  for (byte i=0;i<4;i++) {               //négyszer küldünk ki minden adatot, mert négy kijelzőnk van sorba kötve 
    kileptet(mode_reg,ertek);            //kiléptetjük az adatvezetéken a parancsot és az adatot egymás után
  }  
  digitalWrite(cs_kimenet,1);           //cs bemenetet vissza állítjuk 0-ra, chip nincs kiválasztva, illetve ezzel a felfutó éllel jelenik meg a beléptetett adat a kijelzőn
}

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

Kattints egy csillagra az értékeléshez!

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