#include <avr/io.h>
#include <stdio.h>
#include <avr/cpufunc.h> // Special AVR CPU functions _NOP
#include <util/delay.h> // pouziti funkce _delay_ms() 

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

#define SD0 PORTD |= (1<<PD7); // nastaveni bitu -vypnuti zarivky
#define SD1 PORTD &= ~(1<<PD7); // shozeni bitu -zapnuti zarivky

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

int N=1; // nastaveni delicky (neměnit)
long int xtal= 20000000;

//------nastavení parametrů---------------------
unsigned int zhav=55000; 	//zhavici freq		*
unsigned int zapal=48000; // zapalovací freq	*
unsigned int max= 48000; // 100% beh zarivky	*
unsigned int min= 55000; // 2% svitu zarivky	*
unsigned int freq=48000;//frekvence 			*
//----------------------------------------------

int per=100;	 //perioda
int stav=0;	 // stav zarivky (on/off) 0=OFF
int stisk1 = 0; // pomocna promena pro stisk
int b=0; // pomocny reg pro stridani zvys/sniz freq	 (stmivani)
long int a; // ukladání ADC do a
int t=0;  //  pokud byl pouzit ADC -> t=1
int Hystereze = 0; 
long int Prumer = 0;
int Prumer_citani = 0;
int Zmena_freq = 0;

//********************začátek programu************
//************************************************

int main (void)
{
	SD1; // zablokovani vystupu IR21XX
	DDRD=0b11110000; //nastaveni portu D -OCA,OCB,SD
	PORTB=(1<<PORTB0); // tlacitko na portu B0
	TCCR0A=(1<<WGM01)|(1<<COM0A0)|(1<<COM0B0); // nastaveni citace do CTC mode 2, port normal fce
	TCCR0B=1; // nastaveni delicky na 1 = deleno 1;(2=/8)
	ADMUX=0b01000111; //nastaveni ad7-vstup, Uref=Avcc
	ADCSRA=0b11100111; //zapnuti adc,


//**********************výpočet a nastavení timerů****************************
void osc(long int freq)
{	
		per=((xtal/freq)/(2*N))-1; //vypočet čísla do reg 
		while (TCNT0>50) //zamezuje přetečení čítače
			_NOP();		// čeká se na hodnotu menší 50ti
		OCR0A= per; 	// zapíše do registru vypočtenou hodnotu
}

//************************detekce stisku******************************
int stisk(void)
{							//na pinu je vysoka uroven v pripade nestisku
	stisk1 = PINB; 			// zapsani hodnoty z PINb do stisk
	stisk1 &= 0b00000001;	// maskovani->vsechny bity krom PINB nastavi na 0
	if (stisk1 == 0)		// stisk je přivedením 0 na pin
		return 1;			//je stisk 
	else					
		return 0;			//není stisk
}

//************************Debouncer******************************
int Stisk_tlacitka()
{unsigned char Vysledek = 0;
 unsigned char reg = 0;
  
	 do {reg <<= 1;
	 	 if(stisk() == 1) {reg |= 1;} else
		 	{reg &= 254;}
	 	 _delay_us(70);
		 }while(((reg != 0) && (reg != 255)) ); 

if(reg == 0) Vysledek = 0;
if(reg == 255) Vysledek = 1;

return Vysledek;
}
//*************************stmívání**************************
void stmivani(void)
{
	while (Stisk_tlacitka()) //zjištění stisku tlačítka na pinu D0
	{
	_delay_ms(2);   // určování prodlevy mezi další změnou frekvence
		switch (b)	// detekce predchoziho děje 
		{
			case 0:	if (freq<=min)
					osc(freq=freq+10);	//zvysovani freq(stmivani)
				break;					// hodnota 10 je optimální
			case 1:	if (freq>=max)
					osc(freq=freq-10);	//snizovani freq(svítání)
				break;
			default:	b=0;
		}
	}
if (b==1)		// po dokončení stmívání změní hodnotu	
		b=0;	// bylo rozsvěcováno, příští stisk=stmívání
	else		
		b=1;	// bylo stmíváno->příště bude rožínat
}

//**********************start s predehrevem*******************

void start(void)
{
	SD0;		// zapnuti ir21XX
	stav=1;		// nastaví stav zářivky na zapnuto
	freq=zhav;	
	osc(freq); //  žhavení
	_delay_ms(800); // čas predehrevu (optimálně 0,5-1,5s)!!!!!!
	freq=zapal;
	osc(freq); // zapálení
}
//************************začátek smyčky programu****************
//##############################################################

while(1)
{
	while (t>=1) // pokud byl zapnut AD,vypne zářivku
	{
		SD1;
		stav=0;
		t=0;
	}
a=ADC;
Hystereze = 0;
while (a>(110-Hystereze))
{	
	Hystereze = 25; // nastavení hystereze po překročení 0,5V
//	a=ADC;			//a=(min-(((ADC-102)*(min-max))/921));
	a= a-102;
	a=a*(min-max);
	a=a/921;
	a=min-a;
	Zmena_freq = 0;
	Prumer = Prumer + a; 							//Soucet a;
	Prumer_citani++;								//Zvýší o 1;
	if(Prumer_citani == 100)						//Průměrování a;
	{
		Prumer = Prumer/100;
			if((Prumer>=max) && (Prumer<=min))  
			{			//zamezeni zapsani frekvence mimo rozsah
				if((Prumer>(freq+50)) || (Prumer<(freq-50)))
				{		//nová frekvence se zapíše při změně>50
					freq = Prumer;	
				  	Zmena_freq = 1;
				}
			}
		Prumer = 0;
		Prumer_citani = 0;
	}	
	t=1;
	_delay_ms(5);
	 
	if (stav==0)	// pokud je zhasnuto, rozsvítí se
	{
		stav=1;
		start();	//start zářivky
	}
	else	//pokud je rožlé, zapíše se frekvence
	{	
		if(Zmena_freq == 1) //ale jen pokud je změna>50
	 	osc(freq);
	}
	a=ADC;			// zapíše novou hodnotu ADC
}
	while (Stisk_tlacitka()) //zjištění stisku tlačítka na pinu B0  **1**
	{
		switch (stav) //zjištění stavu
			{
				case 0:	start();	//vypnuto->rozsvítí				
						break;
				case 1:	_delay_ms(300); // detekce dlouheho stisku
						if (Stisk_tlacitka())
							stmivani();
						else			
							{			//pokud neni dlouhy stisk, vypne EP
							stav=0;
							SD1;
							}
						break;
				default:stav =0;
			}
				
		}		
	}
}



