//-------------- generátor frekvence s využitím enkodéru--------------------
//--------------------------------------------------------------------------
#define F_CPU 16000000		// frekvence krystalu
#include <avr/io.h>			// knihovna pro přerušení
#include <util/delay.h>		// knihovna časovače
#include <avr/interrupt.h>	// knihovna přerušení
#define LCD					
#include "LCD.h"			// knihovna pro práci s LCD
//---prototypy funkcí--------------------------------------------------------
void enkoder (void);		// čtení enkodéru
void posun (void);			// určení generované frekvence
void zobraz_LCD (void);		// zobrazení na LCD
//---- prototypy funkcí -----------------------------------------------------
unsigned char smer = 0;		// smer =1 doleva -----, smer =0 doprava // smer ==2 nehýbe se
unsigned char ton = 0;		// ukazatel na pole porovnávacích hladin
unsigned char frekvence[10] = {77,38,25,19,15,12,10,9,8,7};	// porovnávací hladiny - frekvence
//--- hlavní program --------------------------------------------------------
int main (void)
{
	DDRC = 0xff;;		// nastavení periférií
	PORTC = 0b11111110;
	DDRD |= 0x80;		// nastavení výstupu na PIEZO

	// nastavení časovače -------------------------------
	TCCR2 = 0b00011111;		// nastavení děličky 1024, CTC mód, změna OC2 při komparaci
	OCR2 = frekvence[ton];	// nastavení generované frekvence
	//---------------------------------------------------

	init_lcd();			// inicializace LCD
	_delay_ms(10);

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

	while(1)
	{
		enkoder();		// funkce enkodéru
		posun();		// změna frekvence
		zobraz_LCD();	// zobrazí na LCD
	}
}


void enkoder (void)
{
	DDRB |= 0xfc;		// nastaví vstupy výstupy (B0,B1 vstup)
	PORTB |= 0x03;		// aktivace vnitřních zvedacích odporů



	unsigned char pocitadlo;
	unsigned char enko_stav;	// nový přečtený stav enkodéru
	unsigned char enko_star;	// starý stav enkodéru - použit pro srovnání

	smer =2;					// smer =2 - enkodér je ve stejné poloze
	enko_star = (PINB&0b00000011);  // načtení první hodnoty do porovnávácí proměnné
	_delay_ms(80);				// počká několik ms

	for(pocitadlo = 0; pocitadlo<100; pocitadlo++)	// načítací cyklus
	  {
		enko_stav = (PINB &0b00000011);	// načtení nové hodnoty

	// vyhodnocení stavu enkodéru - dle grayova kódu tedy posloupnost 0,1,3,2 -> 0,1,3,2 -> atd...
		_delay_ms(1);

		if (enko_stav != enko_star)			// pokud se kód změní - točí se s enkodérem
		{									// následně je nutné určit na kterou stranu se točí
			if (enko_stav == 0)
			{
				if (enko_star == 2)	smer = 0;
				if (enko_star == 1)	smer = 1;
			}
			if (enko_stav == 1)
			{
				if (enko_star == 0)	smer = 0;
				if (enko_star == 3)	smer = 1;
			}
			if (enko_stav == 3)
			{
				if (enko_star == 1)	smer = 0;
				if (enko_star == 2)	smer = 1;
			}
			if (enko_stav == 2)
			{
				if (enko_star == 3)	smer = 0;
				if (enko_star == 0)	smer = 1;
			}
			enko_star = enko_stav;			// nová hodnota se stává starou hodnotou pro porovnání
			_delay_ms(5);					// menší prodleva
		}
	  }
}


void posun(void)				// posunutí v poli pro komparaci - změna frekvence
{
	if (smer == 1) ton--;		// směr vlevo, k nižším hodnotám f
	if (smer == 0) ton++;		// směr vpravo, k vyšším hodnotám f

	if (ton == 10) ton = 0;		// kruhová paměť, při MAX jdi na začátek
	if (ton >10) ton = 9;		// pokud je >10 nastav se na MAX (0-1=255) - unsigned char


	OCR2 = frekvence[ton];		// nastaví novou komparační hladinu
	
}

void zobraz_LCD (void)	// zobrazení na LCD displeji
{
	if (smer !=2)		// pokud se hodnota mění, maže displej
	{
		cls();			// mazání displeje
		_delay_ms(10);
	}

	line_1();			// nastaví první řádek a vypíše text
	lcd_text("Frekvence:");

	gotoxy(1,15);
	lcd_text("Hz");

	gotoxy(1,11);		// výpis hodnoty v Hz (hodnota může být max 255)
	lcd_byt((ton+1)*10);

	gotoxy(1,14);	
	lcd_text("0");		// dopisuje 0, pro zobrazení stovek

	_delay_ms(100);
}

