#include <avr/io.h>
#include <inttypes.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/pgmspace.h>		//pro ulozeni do programove pameti
#include <math.h>				//matematické operace
#include <stdlib.h>
#include <util/atomic.h>
#include <eeprom.h>
#include <string.h>
#include <wdt.h>

///////////////////////////////////////////////////////////////////////////
//*************************************************************************
/////////////////////////NASTAVIT!!!///////////////////////////////////////
//*************************************************************************
#define zobraz_kratce	300//doba zobrazeni hodnot po stisku tlačítek --> 300=cca 2.5 vteřiny
#define zobraz_dlouho	3000//3000//délka zobrazení=doba mezi měřeními (ideálně 3000= cca 25 vteřin) - (100=cca 1 s pro kontrolu f-ce)
#define zobraz_logo		100//doba zobrazeni loga "tiPA"

#define prumerovani_procento	3 //o kolik se může lišit posledních 5 měření vlhkosti (aby se pořád nespínaly relé)
//*************************************************************************
/////////////////////////NASTAVIT!!!///////////////////////////////////////
//*************************************************************************
///////////////////////////////////////////////////////////////////////////

#define CIDLO_DDR			DDRC	//definování portu s čidlem
#define CIDLO_PORT			PORTC	//definování portu s čidlem
#define CIDLO_IN			PINC	//definování portu s čidlem
#define DATA_pin			4		//definování pinu pro datový pin (DATA)
#define SCK_pin				5		//definování pinu pro pin sériového časování (SCK)

#define DISP_DDR			DDRD	//definování portu s displejem (A-G)
#define DISP_PORT			PORTD	//definování portu s displejem (A-G)

#define DISP_rizeni_PORT	PORTB	//definování portu pro spínání anod
#define DISP_rizeni_DDR		DDRB	//definování portu pro spínání anod
#define levy_disp_pin		0		//definování pinu pro levý displej
#define pravy_disp_pin		1		//definování pinu pro pravý displej

#define TEMP_or_HUMI_switch_PORT	PORTD//definování portu s přepínačem teplota/vlhkost
#define TEMP_or_HUMI_switch_DDR		DDRD//definování portu s přepínačem teplota/vlhkost
#define TEMP_or_HUMI_switch_IN		PIND//definování portu s přepínačem teplota/vlhkost
#define TEMP_or_HUMI_switch_pin		7	//definování pinu s přepínačem teplota/vlhkost

#define SET_switch_PORT				PORTB//definování portu s tlačítkem SET
#define SET_switch_DDR				DDRB//definování portu s tlačítkem SET
#define SET_switch_IN				PINB//definování portu s tlačítkem SET
#define SET_switch_pin				3	//definování pinu s tlačítkem SET

#define HYS_switch_PORT				PORTB//definování portu s tlačítkem HYS
#define HYS_switch_DDR				DDRB//definování portu s tlačítkem HYS
#define HYS_switch_IN				PINB//definování portu s tlačítkem HYS
#define HYS_switch_pin				2	//definování pinu s tlačítkem HYS

#define REL_PORT					PORTC//definování portu pro relé
#define REL_DDR						DDRC//definování portu pro relé
#define zvlhcovac_REL				0	//definování pinu zvlhčování
#define vysousec_REL				1	//definování pinu vysoušení
#define ohrev_REL					2	//definování pinu ohřevu
#define klima_REL					3	//definování pinu klimatizace

#define LED_PORT					PORTB//definování portu pro LED 
#define LED_DDR						DDRB//definování portu pro LED 
#define zvlhcovac_LED				6	//definování pinu pro LED se zvlčováním
#define vysousec_LED				7	//definování pinu pro LED s vysušováním
#define ohrev_LED					4	//definování pinu pro LED s ohřevem
#define klima_LED					5	//definování pinu pro LED s klimatizací


#define wait				_delay_us(5)	//prodleva pro vzestupné a sestupné hrany
#define cekej				_delay_ms(4)	//prodleva pro multiplexní zobrazování


#define levy_disp_ON		DISP_rizeni_PORT |= 1<<(levy_disp_pin)		//zapíná levou cifru displeje
#define pravy_disp_ON		DISP_rizeni_PORT |= 1<<(pravy_disp_pin)		//zapíná pravou cifru displeje

#define levy_disp_OFF		DISP_rizeni_PORT &= ~1<<(levy_disp_pin)		//vypíná levou cifru displeje
#define pravy_disp_OFF		DISP_rizeni_PORT &= ~1<<(pravy_disp_pin)	//vypíná pravou cifru displeje


#define setSCK				CIDLO_PORT |= 1<<(SCK_pin)					//nastav pin pro SCK (na log. 1)
#define clrSCK				CIDLO_PORT &= ~(1<<(SCK_pin)) 				//nuluj pin pro SCK (na log. 0)

#define setDATA				CIDLO_PORT |= 1<<(DATA_pin)					//nastav pin pro DATA (na log. 1)
#define clrDATA				CIDLO_PORT &= ~(1<<(DATA_pin))				//nuluj pin pro DATA (na log. 0)
#define checkDATA			((CIDLO_IN & (1<<(DATA_pin)))>>DATA_pin)	//přečti pin DATA


#define set_zvlhcovac_LED	LED_PORT |= 1<<(zvlhcovac_LED)		//vypne LED pro zvlhčování (nastaví na log 1)
#define clr_zvlhcovac_LED	LED_PORT &= ~(1<<(zvlhcovac_LED))	//zapne LED pro zvlhčování (nastaví na log 0)
#define set_vysousec_LED	LED_PORT |= 1<<(vysousec_LED)		//vypne LED pro vysušování (nastaví na log 1)
#define clr_vysousec_LED	LED_PORT &= ~(1<<(vysousec_LED))	//zapne LED pro vysušování (nastaví na log 0)
#define set_ohrev_LED		LED_PORT |= 1<<(ohrev_LED)			//vypne LED pro ohřev (nastaví na log 1)
#define clr_ohrev_LED		LED_PORT &= ~(1<<(ohrev_LED))		//zapne LED pro ohřev (nastaví na log 0)
#define set_klima_LED		LED_PORT |= 1<<(klima_LED)			//vypne LED pro klimatizaci (nastaví na log 1)
#define clr_klima_LED		LED_PORT &= ~(1<<(klima_LED))		//zapne LED pro klimatizaci (nastaví na log 0)


#define set_zvlhcovac_REL	REL_PORT |= 1<<(zvlhcovac_REL)		//vypne RELÉ pro zvlhčování (nastaví na log 1)
#define clr_zvlhcovac_REL	REL_PORT &= ~(1<<(zvlhcovac_REL))	//zapne RELÉ pro zvlhčování (nastaví na log 0)
#define set_vysousec_REL	REL_PORT |= 1<<(vysousec_REL)		//vypne RELÉ pro vysušování (nastaví na log 1)
#define clr_vysousec_REL	REL_PORT &= ~(1<<(vysousec_REL))	//zapne RELÉ pro vysušování (nastaví na log 0)
#define set_ohrev_REL		REL_PORT |= 1<<(ohrev_REL)			//vypne RELÉ pro ohřev (nastaví na log 1)
#define clr_ohrev_REL		REL_PORT &= ~(1<<(ohrev_REL))		//zapne RELÉ pro ohřev (nastaví na log 0)
#define set_klima_REL		REL_PORT |= 1<<(klima_REL)			//vypne RELÉ pro klimatizaci (nastaví na log 1)
#define clr_klima_REL		REL_PORT &= ~(1<<(klima_REL))		//zapne RELÉ pro klimatizaci (nastaví na log 0)



#define TEMP_or_HUMI		((TEMP_or_HUMI_switch_IN & (1<<TEMP_or_HUMI_switch_pin))>>TEMP_or_HUMI_switch_pin)//přečte přepínač mezi zobrazením vlhkosti nebo teploty - hodnoty jen 1/0
#define SET					((SET_switch_IN & (1<<SET_switch_pin))>>SET_switch_pin)		//přečte tlačítko SET - hodnoty jen 1/0
#define HYS					((HYS_switch_IN & (1<<HYS_switch_pin))>>HYS_switch_pin)		//přečte tlačítko HYS - hodnoty jen 1/0

//obecné nastavení libovolného portu a pinu 
#define setb(bajt,bit)		bajt |= 1<<(bit)    //nastav bit na portu
#define clrb(bajt,bit)		bajt &= ~(1<<(bit)) //nuluj bit na portu
#define negb(bajt,bit)		bajt ^= 1<<(bit)    //neguj bit na portu
#define checkb(bajt,bit)	(bajt &=(1<<bit))	//přečti bit na portu

//příkazy pro čidlo (viz datasheet)
#define MEASURE_TEMP	0b00000011		//příkaz pro čidlo pro měření teploty
#define MEASURE_HUMI	0b00000101		//příkaz pro čidlo pro měření vlhkosti
#define SOFT_RESET		0b00011110		//resetovací příkaz pro čidlo (po něm čekat minimálně 11 ms)

#define TEPLOTA			255		//makra pro výběr měření teploty (na čísle nezáleží)
#define VLHKOST			254		//makra pro výběr měření vlhkosti (na čísle nezáleží)

#define	nic				DISP_PORT=vypis_7seg(12)	//zhasíná displej


//**************************************
//definování globálních proměnných
float real_teplota, rel_vlhkost;	//proměnné pro zobrazované veličiny
float predchozi_rel_vlhkost=0, predchozi_real_teplota=0;		//pro zapamatování predchozích hodnot
float predchozi_rel_vlhkost1=0, predchozi_rel_vlhkost2=0, predchozi_rel_vlhkost3=0;////pro zapamatování predchozích hodnot

unsigned int zobrazovaci_cykly;		//řídí délku zobrazení
float teplotni_prah=0;				//prah pro spínání relé
unsigned char vlhkostni_prah=0;		//prah pro spínání relé//******************
unsigned char teplotni_hyst=1, vlhkostni_hyst=1;	//pro zjisťování hystereze
unsigned char zobraz_prah, zobraz_hyst;				//pro délku zobrazení veličin po stisku tlačítek

unsigned char prvni_cteni_prepinace=0, druhe_cteni_prepinace=0;	//pro zapamatování hodnoty přepínače TEPLOTA/VLHKOST, děláno pro dvojité čtení

//***********************************************

unsigned char vypis_7seg(unsigned char znak)//vrátí hodnotu dekódovanou pro 7 segmentovku 
{
	unsigned char tab[]={	//tabulka pro dekódované hodnoty	
		0b11000000,//0
		0b11111001,//1
		0b10100100,//2
		0b10110000,//3
		0b10011001,//4
		0b10010010,//5
		0b10000010,//6
		0b11111000,//7
		0b10000000,//8
		0b10010000,//9
		0b10111111,//'-'//10
		0b10111001,//'-1'//11
		0b11111111,//'nic'//12
		0b10000110,//'E'//13
		0b10101111, //'r'//14
		0b10000111,//'t'//15
		0b11101111,//'i_'//16
		0b11111011,//'_i'//17
		0b10001100,//'P'//18
		0b10001000,//'A'//19
	};
	
	if(znak>19)		//pokud je příchozí číslo > 13, vypíše pomlčku (protože se nenachází v tabulce
		znak=10;	//vypíše pomlčku

	return tab[znak];	//vrátí dekódovanou hodnotu
}

void vypis_nic()		//vypíše "nic", vypne se displej
{
	levy_disp_OFF;
	pravy_disp_OFF;
	nic;
}

void vypis_napravo(char znak)	//vypíše číslo na pravou pozici na displeji
{	
	levy_disp_OFF;
	DISP_PORT=znak;
	pravy_disp_ON;
	cekej;	//chvíli počká
}

void vypis_nalevo(char znak)		//vypíše číslo na levou pozici na displeji
{	
	pravy_disp_OFF;
	DISP_PORT=znak;
	levy_disp_ON;
	cekej;	//chvíli počká
}
	
void vypis_cislo(float cislo, unsigned int jak_dlouho)//vypíše číslo na displej, interval <-19;99>, desetinná čísla budou ořezána, nikoli zaokrouhlena! (-18.8 se vypíše jako -18)
{
	zobrazovaci_cykly=jak_dlouho;	//délka výpisu podle vstupního čísla

	while(zobrazovaci_cykly--)//smyčka pro zobrazování(cca 3000 pro dlouhé zobrazení)
	{
		sei();

		wait;	//malé zpoždění

		prvni_cteni_prepinace=TEMP_or_HUMI;  //načte hodnotu přepínače

		if(prvni_cteni_prepinace!=druhe_cteni_prepinace)//pokud se stavy dvojitého čtení liší, přeruší smyčku
		{
			zobrazovaci_cykly=0;	//vynuluje počet cyklů pro smyčku
			prvni_cteni_prepinace=0;//vynuluje hodnoty po čtení přepínače
			druhe_cteni_prepinace=0;//vynuluje hodnoty po čtení přepínače
		}
		
		if(cislo==111)	//pokud je číslo 111, vypne displej
		{
			vypis_napravo(vypis_7seg(12));
			vypis_nalevo(vypis_7seg(12));
		}
		else if(cislo>99 || cislo<-19)	//pokud je číslo mimo rozsah, vypíše pomlčky
		{
			vypis_napravo(vypis_7seg(10));
			vypis_nalevo(vypis_7seg(10));
		}
		else if(cislo<0 && cislo>-10)	//vypisování pro záporná čísla
		{
			vypis_napravo(vypis_7seg((char)-cislo%10));
			vypis_nalevo(vypis_7seg(10));
		}
		else if(cislo<=-10)	//vypisování pro záporná čísla menší než -10
		{
			vypis_napravo(vypis_7seg((char)-cislo%10));
			vypis_nalevo(vypis_7seg(11));
		}
		else //jinak vypiš číslo
		{
			vypis_napravo(vypis_7seg((char)cislo%10));

			if(cislo>9)//nebudou zobrazeny vodící nuly
				vypis_nalevo(vypis_7seg((char)cislo/10));
		}
	}
	
	nic; //zhasni displej

	druhe_cteni_prepinace=TEMP_or_HUMI; //druhé načtení přepínače
}	


void zvlhcuj() //f-ce pro zvlčovač
{
	set_vysousec_REL;	//vypni RELÉ pro vysoušeč
	set_vysousec_LED;	//vypni LEDku pro vysoušeč
	clr_zvlhcovac_LED;	//zapni LEDku pro vysoušeč
	clr_zvlhcovac_REL;	//zapni RELÉ pro vysoušeč
}

void vysusuj() //f-ce pro vysoušeč
{
	set_zvlhcovac_REL;
	set_zvlhcovac_LED;
	clr_vysousec_LED;
	clr_vysousec_REL;
}

void ohrivej() //f-ce pro ohřívač
{
	set_klima_REL;
	set_klima_LED;
	clr_ohrev_LED;
	clr_ohrev_REL;
}

void ochlazuj() //f-ce pro klimatizaci
{
	set_ohrev_REL;
	set_ohrev_LED;
	clr_klima_LED;
	clr_klima_REL;
}

void odpoj_rizeni_vlhkosti() //f-ce pro vypnutí řízení vlhkosti
{
	set_zvlhcovac_REL;
	set_zvlhcovac_LED;
	set_vysousec_LED;
	set_vysousec_REL;
}

void odpoj_rizeni_teploty()	//f-ce pro vypnutí vízení teploty
{
	set_ohrev_REL;
	set_ohrev_LED;
	set_klima_LED;
	set_klima_REL;
}


void pulz()	//jeden pulz SCK, zapíše hodnotu DATA beze změny
{
	wait;
	setSCK;	//nastavení pinu SCK do log.1
	wait;	// kratke zpozdeni pro komunikaci
	clrSCK;	//nastavení pinu SCK do log.0
	wait;	// kratke zpozdeni pro komunikaci
}

void start_prenosu()//generuje startovaci podminku
{
//       _____         ________
// DATA:     |_______|
//           ___     ___
// SCK : ___|   |___|   |______

	setDATA;	//nastavení pinu DATA do log.1
	clrSCK;   	//vynulování pinu SCK (do log. 0)
	wait;		//počkání, aby byla změna registrovatelná pro čidlo	

	setSCK;		//nastav pin SCK do log. 1
	wait;		//krátké počkání

	clrDATA;	//nulování DATA pinu
	wait;

	clrSCK;
	wait;//

	setSCK;
	wait;

	setDATA;
	wait;

	clrSCK;
	wait;
}


void zapis_bajt(char bajt)		//zapíše bajt na sběrnici s čidlem
{
	unsigned char i;//hodnota pro cyklus for

	for (i=0b10000000;i>0;i/=2)	//rotující maskovací bit
	{ 
		if (i & bajt) 			//pokud je bajt po vymaskování >0
			setDATA;			//zapiš 1 na sběrnici
		else 
			clrDATA;			//zapiš 0 na sběrnici
	
		setSCK;					//hodinový pulz
		_delay_us(5);			//počkání na zpracování

		clrSCK;					//vynulování SCK pinu
	}
}

//***********************************************
/* WATCHDOG register:
Bit: 			7 		6 		5 		4 		3 		2 		1 		0
WDRCSR:			WDIF 	WDIE 	WDP3 	WDCE 	WDE 	WDP2 	WDP1 	WDP0
Initial Value: 	0 		0 		0 		0 		X 		0 		0 		0
*/
//***********************************************

int zmer_velicinu(char velicina)//f-ce pro změření veličiny
{
	char i;//proměná pro cykly for
	int velicina8bit1=0, velicina8bit=0; //proměnné pro příjem dat z čidla

	cli();

	WDTCSR = 0b00011000;//povolení změny v registru WDT
	WDTCSR = 0b01001111;//zapnutí WATCHDOGu na 2 vteřiny
	wdt_reset();

	sei();


	CIDLO_DDR |= (1<<DATA_pin);	//nastavení DATA pinu jako výstupní

	start_prenosu();	//použije inicializační f-ci a začne přenos
	
	if(velicina==TEPLOTA)	
		zapis_bajt(MEASURE_TEMP);	//zapsání příkazu do čidla podle zadaného parametru - měření TEPLOTY
	else if(velicina==velicina)
		zapis_bajt(MEASURE_HUMI);	//zapsání příkazu do čidla podle zadaného parametru - měření VLHKOSTI

	setDATA;					//uvolni datový pin, nastaví jej na log. 1

	CIDLO_DDR &= ~(1<<DATA_pin);//nastavení pinu DATA jako vstupního

	pulz();						//9. pulz pro ACK (pro potvrzení pro čidlo)

	while(checkDATA);			//čekání na konverzi prováděnou čídlem, po konverzi čidlo vynuluje DATA pin

	for(i=8;i>0;i--)			//příjem 8 bitů --> příjem prvního bajtu
	{
		setSCK;					//nastavení pinu SCK do log. 1
		velicina8bit1 |= checkDATA<<(i);	//přičtení prijatého bitu posunutého doleva o hodnotu i, která se snižuje
		wait;					//krátké počkání
		clrSCK;					//nastavení pinu SCK do log. 0
		wait;					//krátké počkání
	}

	CIDLO_DDR |= (1<<DATA_pin);	//nastavení DATA pinu jako výstupního

	clrDATA;
	pulz();	//provedení potvrzovacího pulzu pro čidlo, ACK bit

	CIDLO_DDR &= ~(1<<DATA_pin); //nastavení DATA pinu jako vstupního

	for(i=8;i>0;i--) //příjem dalšího bajtu (obdobné jako předchozí)
	{
		setSCK;
		velicina8bit |= checkDATA<<(i);
		wait;
		clrSCK;
		wait;
	}

	WDTCSR = 0b00011000;//povolení změny v registru WDT
	WDTCSR = 0b00000111;//vypnutí WATCHDOGu
	wdt_reset();

	return ((velicina8bit) + (velicina8bit1<<8))>>1; //vrací 16-bitovou hodnotu - sečte 8-bitovou proměnnou a dalších 8 bitů je posunuto o 8 míst doleva (nahoru)
}


void prepocti_hodnoty(int vlhkost, int teplota)//přepočet hodnot z čidla na reálné veličiny:
{//vlhkost je 12-bit, teplota 14-bit
	//konstanty pro přepočet hodnot na reálné veličiny
	float C1 = -4.0;
	float C2 = 0.0405;
	float C3 = -0.0000028;
	float T1 = -0.01;
	float T2 = 0.00008;
	float lin_vlhkost;	//lineární vlhkost

	real_teplota = round((float)(teplota)*0.01 - 41.1);					//výpočet skutečné teploty
//	real_teplota = (((float)(teplota)*0.01 - 40.1)*10)-200;					//výpočet pro kontrolu desetinného místa

	lin_vlhkost = C3*(vlhkost)*(vlhkost) + C2*(vlhkost) + C1;			//vypocet vlhkosti s téměř lineární závislostí

	rel_vlhkost = round((real_teplota-25)*(T1+T2*vlhkost)+lin_vlhkost);	//korekce lineárně závislé vlhkosti na teplotu --> relativní vlhkost
}


void inicializace_portu() //inicializační definice
{
	DDRC=0;//vstupně/výstupní registr (1=výstupní, 0=vstupní)
	DDRB=0;
	DDRD=0;

	PORTB=0xFF;//logická hodnota na portu
	PORTD=0xFF;
	PORTC=0xFF;

	//definování hodnot pro čidlo
	CIDLO_DDR |= (1<<SCK_pin);
	CIDLO_DDR |= (1<<DATA_pin);
	CIDLO_PORT |= ((1<<SCK_pin) | (1<<DATA_pin));

	//definování hodnot pro displej
	DISP_DDR |= 0b01111111;
	DISP_PORT |= 0b01111111;
	DISP_rizeni_PORT |= ((1<<levy_disp_pin) | (1<<pravy_disp_pin));
	DISP_rizeni_DDR |= ((1<<levy_disp_pin) | (1<<pravy_disp_pin));

	//nastavení pro přepínač TEPLOTA/VLHKOST
	TEMP_or_HUMI_switch_DDR &= ~(1<<TEMP_or_HUMI_switch_pin);
	SET_switch_DDR &= ~(1<<SET_switch_pin);
	HYS_switch_DDR &= ~(1<<HYS_switch_pin);

	TEMP_or_HUMI_switch_PORT |= (1<<TEMP_or_HUMI_switch_pin);
	SET_switch_PORT |= (1<<SET_switch_pin);
	HYS_switch_PORT |= (1<<HYS_switch_pin);
	
	//nastavení pinů pro LED a RELÉ jako výstupní a jejich hodnotu na log. 1
	REL_DDR |= ((1<<zvlhcovac_REL) | (1<<vysousec_REL) | (1<<ohrev_REL) | (1<<klima_REL));
	LED_DDR |= ((1<<zvlhcovac_LED) | (1<<vysousec_LED) | (1<<ohrev_LED) | (1<<klima_LED));

	REL_PORT |= ((1<<zvlhcovac_REL) | (1<<vysousec_REL) | (1<<ohrev_REL) | (1<<klima_REL));
	LED_PORT |= ((1<<zvlhcovac_LED) | (1<<vysousec_LED) | (1<<ohrev_LED) | (1<<klima_LED));
}


ISR(SIG_OUTPUT_COMPARE1A)	//cca 0.15 s se provede kontrola tlačítek pomocí přerušení čítače 1
{	
	if(TEMP_or_HUMI==0)//výběr mezi TEPLOTOU a VLHKOSTÍ (0=teplota, 1=vlhkost)
	{
		if(SET==0)//pokud je stisknuto tlačítko SET (nastavení teplotního prahu (jeho inkrementace))
		{
			zobraz_hyst=0;//vypnutí zobrazování hystereze (aby nedošlo k přepisu na displeji)
			teplotni_prah==97 ? teplotni_prah=-17 : teplotni_prah++;//nastavování prahu od <-17;97>
			zobraz_prah=1;//slouží pro vypsání na displej v main()

			eeprom_write_byte(0,teplotni_prah);//zápis hodnoty do EEPROM, pro výpadek proudu

			zobrazovaci_cykly=1;//vyskočí z vypisování libovolného čísla, vynuluje hodnotu pro while
		}

		if(HYS==0)//pokud je stisknuto tlačítko HYS (nastavení teplotní hystereze (její inkrementace))
		{
			zobraz_prah=0;//vypnutí zobrazování teplotního prahu (aby nedošlo k přepisu na displeji)
			teplotni_hyst==20 ? teplotni_hyst=1 : teplotni_hyst++;//nastavování prahu od <1;20>
			zobraz_hyst=1;//slouží pro vypsání na displej v main()

			eeprom_write_byte(1,teplotni_hyst);//zápis hodnoty do EEPROM, pro výpadek proudu

			zobrazovaci_cykly=1;//vyskočí z vypisování libovolného čísla, vynuluje hodnotu pro while
		}
	}
	else
	{	
		//definice pro tlačítka podobné teplotě
		if(SET==0)//pokud je stisknuto tlačítko SET (nastavení vlhkostního prahu (jeho inkrementace))
		{
			zobraz_hyst=0;
			vlhkostni_prah==97 ? vlhkostni_prah=2 : vlhkostni_prah++;
			zobraz_prah=1;//slouží pro vypsání na displej v main()

			eeprom_write_byte(2,vlhkostni_prah);//zápis hodnoty do EEPROM, pro výpadek proudu
		
			zobrazovaci_cykly=1;//vyskočí z vypisování libovolného čísla, vynuluje hodnotu pro while
		}

		if(HYS==0)//pokud je stisknuto tlačítko HYS (nastavení vlhkostní hystereze (její inkrementace))
		{
			zobraz_prah=0;
			vlhkostni_hyst==20 ? vlhkostni_hyst=1 : vlhkostni_hyst++;
			zobraz_hyst=1;
			
			eeprom_write_byte(3,vlhkostni_hyst);//zápis hodnoty do EEPROM, pro výpadek proudu

			zobrazovaci_cykly=1;
		}
	}
}

ISR(WDT_vect)//vektor přerušení pro WATCHDOG
{
	odpoj_rizeni_teploty();
	odpoj_rizeni_vlhkosti();//odpojení okruhů
	while(1)//donekonečna vypisuje "Er", ale po chvíli WATCHDOG provede reset mikrokontroléru	
	{
		vypis_nalevo(vypis_7seg(13));
		vypis_napravo(vypis_7seg(14));
	}
}

char prumer()//vypočítá průměr z předchozích měření
{
	return (predchozi_rel_vlhkost3 + predchozi_rel_vlhkost2 + predchozi_rel_vlhkost1 + 
			predchozi_rel_vlhkost + rel_vlhkost)/5; //výpočet průměru pro zjištění, zda jsou neměřené hodnoty odlišné jen minimálně
}

int main(void)//hlavní smyčka
{
	unsigned char horni_teplotni_prah=0, spodni_teplotni_prah=0;
	unsigned char horni_vlhkostni_prah=0, spodni_vlhkostni_prah=0;

	WDTCSR = 0b00000000;//vypnutí WATCHDOGu
	wdt_reset();
	MCUSR = 0;//vynulování WDT reset flag

	_delay_ms(15);//11ms nesmí čidlo nic dostat, probíhá jeho interní spouštění, započítán i pomalejší náběh napájecího napětí
	
	inicializace_portu();//odkazuje na inicializaci vspně/výstupních pinů


	//pro MEGU8 --> TIMSK ||| pro MEGU168 --> TIMSK1
	TIMSK1 = _BV(OCIE1A);//povolení přerušení pro čítač/časovač1, přerušení bude generováno pomocí SIG_OUTPUT_COMPARE1A
    TCCR1B = _BV(CS12) | _BV(CS10) | _BV(WGM12);// Clock/1024, 0.001024 sekund za jeden pulz, Mód=CTC
    OCR1A = 150;// 0.001024*150 ~= 0.15 SIG_OUTPUT_COMPARE1A bude proveden každých 0.15 sekund

    sei();			//povolení všech přerušení

	pravy_disp_OFF;	//vypne pravou 7segmentovku
	levy_disp_OFF;	//vypne levou 7segmentovku

	//načítání nastavených hodnot z EEPROM paměti
	if(eeprom_read_byte(0)>=0 && eeprom_read_byte(0)<=98)
		teplotni_prah = eeprom_read_byte(0);
	else if(eeprom_read_byte(0)>98 && eeprom_read_byte(0)!=0xFF)
		teplotni_prah =  eeprom_read_byte(0) - 256;
	if(eeprom_read_byte(1)!=0xFF)
		teplotni_hyst = eeprom_read_byte(1);
	if(eeprom_read_byte(2)!=0xFF)
		vlhkostni_prah = eeprom_read_byte(2);
	if(eeprom_read_byte(3)!=0xFF)
		vlhkostni_hyst = eeprom_read_byte(3);


	prepocti_hodnoty(zmer_velicinu(VLHKOST),zmer_velicinu(TEPLOTA));//měření a přepočet nových hodnot

	predchozi_rel_vlhkost3 = rel_vlhkost;
	predchozi_rel_vlhkost2 = rel_vlhkost;
	predchozi_rel_vlhkost1 = rel_vlhkost;
	predchozi_rel_vlhkost = rel_vlhkost;//načtení hodnoty pro půměrování

//	_delay_ms(100);	

	while(1)
	{	
		//zapamatování předchozích měření
		predchozi_rel_vlhkost3 = predchozi_rel_vlhkost2;
		predchozi_rel_vlhkost2 = predchozi_rel_vlhkost1;
		predchozi_rel_vlhkost1 = predchozi_rel_vlhkost;
		predchozi_rel_vlhkost = rel_vlhkost;
		
		predchozi_real_teplota = real_teplota;//potřeba pro určení, zda se otepluje nebo ne

		if(zobraz_hyst<=0 && zobraz_prah<=0)
			prepocti_hodnoty(zmer_velicinu(VLHKOST),zmer_velicinu(TEPLOTA));//měření a přepočet nových hodnot
		
		_delay_ms(10);	


//*******************************************************
		if(real_teplota<=0)	//pokud je teplota pod nulou, tak jsou vypnuty okruhy pro řízení vlhkosti
			odpoj_rizeni_vlhkosti();	//odpojí řízení vlhkosti	
//*******************************************************

		if(teplotni_prah+teplotni_hyst>=real_teplota && teplotni_prah-teplotni_hyst<=real_teplota)//oblast hystereze
		{
			if(teplotni_prah+teplotni_hyst+1==real_teplota)//pro nereálné změny, přetopeno/přechlazeno...
				horni_teplotni_prah=1;

			if(teplotni_prah-teplotni_hyst-1==real_teplota)
				spodni_teplotni_prah=1;

			if(teplotni_prah==real_teplota)
			{
				horni_teplotni_prah=0;
				spodni_teplotni_prah=0;
			}

			if(predchozi_real_teplota>real_teplota)//ochlazování
			{
				if(real_teplota>teplotni_prah && horni_teplotni_prah==1)//tepleji než práh
					ochlazuj();//zapnutí klimatizace
				else if(real_teplota<teplotni_prah)//chladněji než práh
					odpoj_rizeni_teploty();
			}
			else if(predchozi_real_teplota<real_teplota)//oteplování
			{
				if(real_teplota>teplotni_prah)//detekce, zda se ochlazuje nebo otepluje
					odpoj_rizeni_teploty();
				else if(real_teplota<teplotni_prah && spodni_teplotni_prah==1)
					ohrivej();//zapnutí topení
			}			
		}
		else//oblast mimo hysterezi
		{
			if(teplotni_prah+teplotni_hyst>=real_teplota)//pod hysterezí
				ohrivej();//zapne topení
			else if(teplotni_prah-teplotni_hyst<=real_teplota)//nad hysterezí
				ochlazuj();//zapne klimatizaci
		}

//*******************************************************************************
		if(prumer()+prumerovani_procento >= rel_vlhkost && prumer()-prumerovani_procento <= rel_vlhkost && vlhkostni_prah!=0 && real_teplota>0)//ověření, zda se vlhkost výrazně nezměnila, aby se zbytečně nespínaly zvlhčovače nebo vysoušeče a zda není teplota pod nulou
		{
			if(vlhkostni_prah+vlhkostni_hyst>=rel_vlhkost && vlhkostni_prah-vlhkostni_hyst<=rel_vlhkost)//oblast hystereze
			{
				if(vlhkostni_prah+vlhkostni_hyst+1==rel_vlhkost)//pro nereálné změny, převlhčeno/přesušeno...
					horni_vlhkostni_prah=1;

				if(vlhkostni_prah-vlhkostni_hyst-1==rel_vlhkost)
					spodni_vlhkostni_prah=1;

				if(vlhkostni_prah==rel_vlhkost)
				{
					horni_vlhkostni_prah=0;
					spodni_vlhkostni_prah=0;
				}

				if(predchozi_rel_vlhkost>rel_vlhkost)//vysoušení
				{
					if(rel_vlhkost>vlhkostni_prah && horni_vlhkostni_prah==1)//vlhčeji než práh
						vysusuj();//zapne vysoušeče
					else if(rel_vlhkost<vlhkostni_prah)//chladněji než práh
						odpoj_rizeni_vlhkosti();
				}
				else if(predchozi_rel_vlhkost<rel_vlhkost)//zvlhčování
				{
					if(rel_vlhkost>vlhkostni_prah)//detekce, zda se ochlazuje nebo otepluje
						odpoj_rizeni_vlhkosti();
					else if(rel_vlhkost<vlhkostni_prah && spodni_vlhkostni_prah==1)
						zvlhcuj();//zapne zvlhčovače
				}
				
				if(rel_vlhkost==vlhkostni_prah)
					odpoj_rizeni_vlhkosti();
			}
			else//oblast mimo hysterezi
			{
				if(vlhkostni_prah+vlhkostni_hyst>=rel_vlhkost)//oblast pod hysterezí
					zvlhcuj();//zapnutí zvlhčování
				else if(vlhkostni_prah-vlhkostni_hyst<=rel_vlhkost)//oblast nad hysterezí
					vysusuj();//zapnutí vysušování
			}
		}
		else//pokud jsou příliž velké rozdíly v měření vlhkosti
			odpoj_rizeni_vlhkosti();//odpojení zvlhčování a vysušování

//*********************************************************
		if(TEMP_or_HUMI==0)//přečtení stavu přepínače TEPLOTA/VLHKOST
		{//zobrezení teploty
			if(zobraz_prah>0)//pokud bylo stisknuto tlačítko SET
			{
				zobraz_prah=0;//vynulování proměnné -->zobrazí se jen jednou				

				vypis_cislo(teplotni_prah,zobraz_kratce);//krátké vypsání hodnoty teplotního prahu
				
				nic;//vypnutí displeje
			}
			else if(zobraz_hyst>0)//pokud bylo stisknuto tlačítko HYS
			{
				zobraz_hyst=0;//vynulování proměnné -->zobrazí se jen jednou

				vypis_cislo(teplotni_hyst,zobraz_kratce);//krátké vypsání hodnoty teplotní hystereze

				nic;//vypnutí displeje
			}
			else //pokud nebylo stisknuto ani jedno tlačítko
				vypis_cislo(real_teplota,zobraz_dlouho);//vypíše skutečnou teplotu, zobrazí ji dlouho
								
		}//********************************************************	
		else
		{//zobrazení vlhkosti
			if(zobraz_prah>0)//pokud bylo stisknuto tlačítko SET
			{
				zobraz_prah=0;//vynulování proměnné -->zobrazí se jen jednou				

				vypis_cislo(vlhkostni_prah,zobraz_kratce);//krátké vypsání hodnoty vlhkostního prahu	
				
				nic;//vypnutí displeje
			}
			else if(zobraz_hyst>0)//pokud bylo stisknuto tlačítko HYS
			{
				zobraz_hyst=0;//vynulování proměnné -->zobrazí se jen jednou

				vypis_cislo(vlhkostni_hyst,zobraz_kratce);//krátké vypsání hodnoty vlhkostní hystereze

				nic;//vypnutí displeje
			}
			else //pokud nebylo stisknuto ani jedno tlačítko
				vypis_cislo(rel_vlhkost,zobraz_dlouho);//vypíše relativní vlhkost, zobrazí ji dlouho
		}
	}
}
