//--------------------------BC.PRÁCE - AUTOMATIZACE KRBU------------------------------------------------------
#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h> // knihovny pro časové zpoždění
#define LCD
#include "C:\mojelib1.h" // LCD displej
//hlavičky funkcí --------------------------------------------------------------------------------------------
void reset (void); // funkce pro reset teplotního čidla
void zapis_1 (void); // zapise logickou 1 do zařízeni
void zapis_0 (void); // zapise logickou 0 do zařízeni
void cteni (int pozice); // přečti bit
void vysli (int prikaz); // vyšle daný kód do teplotního čidla
void teplota(void); // vypíše teplotu na displej BIN i dekadicky
void vykon(void);

// program ---------------------------------------------------------------------------------------------------
int16_t hodnotaV; // proměnná teplotní hodnoty (16 bitů)
int16_t hodnotaT;
int16_t posun = 1; // pomocna proměnná pro zápis do proměnné hodnota

int nastav = 25;
int pom = 0;
int main (void)
{
DDRA = 0xff;	// nastaví portA jako výstupní
DDRB = 0xff;
DDRC = 0xff; 
DDRD = 0xff; 
PORTA = 0xff;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
init_lcd(); // inicializace LCD
_delay_ms(20);

while(1)
{
hodnotaV = 0;	//hodnota 
hodnotaT = 0;



reset(); // reset puls
vysli(0xcc); // příkaz pro přeskočení identifikace (adresace)
vysli(0x44); // příkaz pro převod teploty
_delay_ms(200); // čas na převod teploty
_delay_ms(200); // maximální doba převodu = 750ms
_delay_ms(200);
_delay_ms(150);
// vyčtení dat z tabulky (zajímají nás první dva byty, tedy 16 bitů - teplota
reset();
vysli(0xcc); // příkaz pro přeskočení identifikace (adresace)
vysli(0xbe); // příkaz pro vyčtení dat
for(int i = 0;i<16;i++) // zachycení dat
{
cteni(i); // vyčti bit a ulož do proměnné hodnota
_delay_us(1); // nutná prodleva mezi rámci čtení
}
teplota(); // vypiš teplotu na LCD
}
return (1);
}

// operace pro manipulací se sběrnicí 1-wire -----------------------------------------
void reset (void) // reset puls
{
DDRA = 0xff; // vysílač (TX)
PORTA = 0x00; // nuluje PORT A
_delay_us(480); // nuluje po dobu 500us >480us
DDRA=0x00; // přepne do naslouchání (uvolní linku) -> RX přijímač
_delay_us(70); // počká 60us (zde lze ověřit, zda zařízení je na lince)
_delay_us(410); // počká do konce komunikace reset pulsu
}
void zapis_1 (void) // zápis logické 1 na sběrnici
{
DDRA = 0xff; // drž na 0 po 6 us
PORTA = 0x00;
_delay_us(6);
DDRA = 0x00; // uvolni na zbytek do 70us, tedy na 64us
_delay_us(64);
}
void zapis_0 (void) // zápis logické 0 na sběrnici
{
DDRA = 0xff; // zapiš logickou 0 po 60us
PORTA = 0x00;
_delay_us(60);
DDRA = 0x00; // uvolni na 10us
_delay_us(10);
}
void cteni (int pozice) // zaznamená příchozí data do proměnné hodnota
{
DDRA = 0xff;
PORTA = 0x00; // vyšli 0 na 6us
_delay_us(6);
DDRA = 0x00; // uvolni a počkej 9us
_delay_us(9);
// načti do pole aktuální hodnotu na sběrnici
if ((PINA & 0b10000000)!=0) hodnotaV|=(posun<<pozice);
if ((PINA & 0b01000000)!=0) hodnotaT|=(posun<<pozice);
_delay_us(55); // počkej do konce rámce
}
void vysli (int prikaz) // zapisuje příkaz do teplotního čidla
{
for(int i = 0; i<8;i++) // práce pouze s 8 bitovými povely (byte)
{ // pošle bit na i-té pozici, začíná s LSB a končí s MSB
if(((prikaz>>i)&0b00000001)==0) zapis_0();
else zapis_1();
}
}


void teplota(void) // výpis v binární a dekadické podobě
{
int celecisloV;
int celecisloT;
int x,y,a;
int tlreset=0;
int h=1,l=0;
unsigned char PWM [5] = {255,160,120,70,30};
unsigned char CER [4] = {255,190,135,30};
int ukazatelC = 0;
int ukazatel = 0;
int rozdil = 0;

// převod z 16bitové proměnné a rozdělení celé části a zlomkové
celecisloV=(hodnotaV>>4)&255; // výpočet celého čísla
celecisloT=(hodnotaT>>4)&255; // výpočet celého čísla


for(x=0;x<200;x++)
{
	_delay_ms(100);
		if (x <= 100)	// 10 sekund bude zobrazena teplota vzduchu
		{

			line_1();
			lcd_text("Teplota vzduchu:"); // výpis textu – Teplota:
			gotoxy(2,10);
			lcd_byt(celecisloV); // výpis celého čísla
			gotoxy(2,14);
			lcd_text("C");

		}  

		if (x >= 101)	//dalších 10 sekund bude zobrazena teplota topení
		{

			line_1();
			lcd_text("Teplota topeni :"); // výpis textu – Teplota:
			gotoxy(2,10);
			lcd_byt(celecisloT); // výpis celého čísla
			gotoxy(2,14);
			lcd_text("C");

		}
		
		if ((PINA&0b00100000)==0)	//po stisknutí tlačítka reset se rozsvítí dysplej na 15 sekund
			{
				_delay_ms(1000);
				for (y=0;y<15;y++)
				{

					PORTB = (PORTB & ~_BV(PB1)) | ((h) << PB1);	//zapnutí podsvícení dyspleje
					_delay_ms(1000);

					if((PINA&0b00100000)==0)
					{
						tlreset++;	
					}

					if(tlreset > 1)// po dvou vteřinách při stisknutém tlačítku reset naběhne mód nastavení teploty
					{
						line_1();
						lcd_text("Zadejte teplotu:");
						line_2();
						lcd_text("+    -       C  ");

							for(a=0;a<30;a++)	//uživatel má 30s na nastavení teploty
							{
								_delay_ms(1000);

									if ((PINA&0b00001000)==0)	// po stisknutí tlačítka "+" se přičte jeden stupeň teploty
									{
										nastav++;				//proměnná pro nastavení požadované hodnoty teploty
									}

									if ((PINA&0b00010000)==0)	// po stisknutí tlačítka "-" se přičte jeden stupeň teploty
									{
										nastav--;
									}

								gotoxy(2,10);
								lcd_byt(nastav);				//zobrazení požadované teploty na dyspleji
									if((PINA&0b00100000)==0)	//pokud je stisknuto tlačítko reset, dojde k ukončení módu nastavení teploty 
									{
										tlreset=0;
										goto SKOK;	
									}	
							}
						tlreset=0;
					}

				}
				SKOK:
				line_1();										// mazání dyspleje
				lcd_text("                ");
				line_2();
				lcd_text("                ");
				PORTB = (PORTB & ~_BV(PB1)) | ((l) << PB1);		// vypnutí podsvícení dyspleje
			}
		

		// PWM modulace

		TCCR1A=0b11110001;		// nastavení časovače
								// komparace s OCR1A a OCR1B
								// využívá se pouze 8 bytového průběhu PWM
		TCCR1B=0b00001101; 		// nastavena dělička 1024
		TIMSK=0b00011000;       // nastavení přerušení na porovnání OCR1A a OCR1B s TCNT1
		OCR1AH=0;				// horní polovina porovn. registru 16-bit časovače je prázdná
		OCR1AL=255; 			// naplnění porov. registru spodní části 16bit čítače
		OCR1BH=0;
		OCR1BL=255;
		

		if (celecisloT <= 41)	//pokud je teplota krbu menší než 40 °C, je čerpadlo vypnuto
		{
			ukazatelC = 0; 
		}
		if (celecisloT > 41 && celecisloT <= 46)
		{
			ukazatelC = 1;		//čerpadlo se zapíná od 41 °C na nejnižší výkon
					}
		if (celecisloT > 46 && celecisloT <= 51)
		{
			ukazatelC = 2;		//čerpadlo se zapíná od 46 °C na střední výkon
		}
		if (celecisloT > 51)
		{
			ukazatelC = 3;		//čerpadlo se zapíná od 51 °C na maximální výkon
		}
		OCR1BL=CER[ukazatelC];

		int e = 0;
		// 	nastavení výkonu ventilátoru 

		if (celecisloT > pom)
		{
			pom = celecisloT;		
		}

		if (ukazatelC != 0 && celecisloT >= pom)
	
		{
		
			rozdil = nastav - celecisloV;
			if (rozdil <= 1)
			{
				ukazatel = 1;
			}
			if (rozdil == 2)
			{
				ukazatel = 2;
			}
			if (rozdil == 3)
			{
				ukazatel = 3;
			}
			if (rozdil >= 4 && rozdil <= 30)
			{
				ukazatel = 4;
			}
			if (rozdil > 30)		//	informování uživatele o nevhodném zadání teploty
			{
				PORTB = (PORTB & ~_BV(PB1)) | ((h) << PB1);	//zapnutí podsvícení dyspleje
				line_2();
				lcd_text("SPATNA TEPLOTA!");				
				_delay_ms(1000);
				_delay_ms(1000);

				ukazatel = 0;
			}

			if(e == 0 && ukazatel != 0)
			{
				OCR1AL=PWM[4];
				_delay_ms(100);
				e++;
			}
		}

		//	snížení výkonu ventilátoru po ukončení topení

			if (ukazatelC != 0 && celecisloT < pom)
			{
		
			rozdil = pom - celecisloT;
		
			if (rozdil <= 5) 
			{
				ukazatel = 2;
			}

			if (rozdil > 5) 
			{
				ukazatel = 1;
			}

			} 

		// ventilátor bude vypnutý pokud je vypnuté čerpadlo (teplota v topení pod 42°C)

		if (ukazatelC == 0)
		{
			ukazatel = 0;
			e = 0;	
		}

		OCR1AL=PWM[ukazatel];	//výkon na výstupu  podle hodnoty ukazatele
		

	
		// 	LED teplomer
		if (celecisloV <= 15)
		{
			PORTD = (PORTD & ~_BV(PD1)) | ((h) << PD1); //modrá(vedle žluté)
			PORTD = (PORTD & ~_BV(PD0)) | ((h) << PD0); //modrá
			PORTD = (PORTD & ~_BV(PD3)) | ((l) << PD3); //červená
			PORTD = (PORTD & ~_BV(PD6)) | ((l) << PD6); //červená(vedle žluté)
			PORTD = (PORTD & ~_BV(PD7)) | ((l) << PD7); //žlutá(vedle červené)
			PORTD = (PORTD & ~_BV(PD2)) | ((l) << PD2); //žlutá(vedle modré)
		}

		if (celecisloV > 15 && celecisloV <=18)
		{
			PORTD = (PORTD & ~_BV(PD1)) | ((h) << PD1); //modrá(vedle žluté)
			PORTD = (PORTD & ~_BV(PD0)) | ((l) << PD0); //modrá
			PORTD = (PORTD & ~_BV(PD3)) | ((l) << PD3); //červená
			PORTD = (PORTD & ~_BV(PD6)) | ((l) << PD6); //červená(vedle žluté)
			PORTD = (PORTD & ~_BV(PD7)) | ((l) << PD7); //žlutá(vedle červené)
			PORTD = (PORTD & ~_BV(PD2)) | ((h) << PD2); //žlutá(vedle modré)
		}

		if (celecisloV > 18 && celecisloV <=21)
		{
			PORTD = (PORTD & ~_BV(PD1)) | ((l) << PD1); //modrá(vedle žluté)
			PORTD = (PORTD & ~_BV(PD0)) | ((l) << PD0); //modrá
			PORTD = (PORTD & ~_BV(PD3)) | ((l) << PD3); //červená
			PORTD = (PORTD & ~_BV(PD6)) | ((l) << PD6); //červená(vedle žluté)
			PORTD = (PORTD & ~_BV(PD7)) | ((h) << PD7); //žlutá(vedle červené)
			PORTD = (PORTD & ~_BV(PD2)) | ((h) << PD2); //žlutá(vedle modré)
		}

		if (celecisloV > 21 && celecisloV <=24)
		{
			PORTD = (PORTD & ~_BV(PD1)) | ((l) << PD1); //modrá(vedle žluté)
			PORTD = (PORTD & ~_BV(PD0)) | ((l) << PD0); //modrá
			PORTD = (PORTD & ~_BV(PD3)) | ((l) << PD3); //červená
			PORTD = (PORTD & ~_BV(PD6)) | ((h) << PD6); //červená(vedle žluté)
			PORTD = (PORTD & ~_BV(PD7)) | ((h) << PD7); //žlutá(vedle červené)
			PORTD = (PORTD & ~_BV(PD2)) | ((l) << PD2); //žlutá(vedle modré)
		}

		if (celecisloV > 24) 
		{ 
			PORTD = (PORTD & ~_BV(PD1)) | ((l) << PD1); //modrá(vedle žluté)
			PORTD = (PORTD & ~_BV(PD0)) | ((l) << PD0); //modrá
			PORTD = (PORTD & ~_BV(PD3)) | ((h) << PD3); //červená
			PORTD = (PORTD & ~_BV(PD6)) | ((h) << PD6); //červená(vedle žluté)
			PORTD = (PORTD & ~_BV(PD7)) | ((l) << PD7); //žlutá(vedle červené)
			PORTD = (PORTD & ~_BV(PD2)) | ((l) << PD2); //žlutá(vedle modré)
			
		} 
 	//	upozornění uživatele na nečinnost čerpadla

	if ((PINA&0b00000100) != 0 && ukazatelC != 0)
	{
	int i = 0;
 		for (i=0; i<1000; i++)	    // cyklus for - probiha 1000x 1ms = 1s
          {
		   PORTC = (PORTC & ~_BV(PC7)) | ((h) << PC7);	
           _delay_ms(0.5);		    
           PORTC = (PORTC & ~_BV(PC7)) | ((l) << PC7);		
           _delay_ms(0.5);			
	      }
	}

}
}

