
//----------------------------TEPLOTNÍ ČIDLO DALLAS DS18B20----------------------------------
#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>					// knihovny pro časové zpoždění
#define LCD
#include "LCD_knihovna.h"				// LCD displej

//hlavičky funkcí ---------------------------
void reset (void);						// funkce pro reset teplotního čidla
void zapis_1 (void);					// zapise logickou 1 do zarizeni
void zapis_0 (void);					// zapise logickou 0 do zarizeni
void cteni (int pozice);				// precti 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 tlacitko (void);

// samotný program --------------------------
										// hodnota pro vyčtenou teplotu až 16 bitů
int16_t hodnota;						// proměnná teplotní hodnoty (16 bitů)
int16_t posun = 1;						// pomocna proměnná pro zápis do proměnné hodnota
int presnost = 0b01111111;				// proměnná pro zadání přesnosti měřenní

int main (void)
{
	DDRB = 0xff;						// portB výstupní
	DDRC = 0xff;						// portC výstupní
	DDRD = 0xF0;						// horní polovina portuD jako výstupní, dolní vstupní
	PORTC = 0b11000010;					// povolení LCD displeje
			
	init_lcd();							// inicializace LCD
	_delay_ms(20);

	while(1)
	{
		hodnota = 0;					// nulování hodnoty
		PORTD = (presnost&0b01100000);	// robrazení aktuálního rozlišení na SMD LED

		// zahájení měření teploty
		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
		tlacitko();						// nastavení přesnosti měření (rozlišení)
	}
	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říjimač
	_delay_us(70);					// počká 60us po naskočení impulsu a vyslání odpovědi
	_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š logickou0 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 & 0b00000010)!=0) hodnota|=(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 tlacitko (void)				// změna přesnosti měření
{
	DDRD = 0xF0;					// horní polovina výstupní/ dolní vstupní
	int presnost_mer;				

	if((PIND&0b00000001)==0)		// je-li stisknuto tlačítko
		{
		_delay_ms(10);
									// vyčte z přesnost pouze 2 bity a přičte 1
		presnost_mer=((presnost>>5)&0b00000011)+1;		

		if(presnost==4) presnost=0;	// zamezení překročení rozsahu (00,01,10,11)

									// nastavím opět do stav registru
		presnost = (presnost_mer<<5)|0b00011111;		

		// aplikace změn přesnosti
		reset();						// reset sběrnice
		vysli(0xcc);					// přeskočí adresaci
		vysli(0x4e);					// zapiš do tabulky "scratchpad" Th,Tl,conf. registr
		vysli(0x00);					// hodnota Th
		vysli(0xF0);					// hodnota Tl
		vysli(presnost);				// konfigurační registr - přesnost měření(9,10,11,12 bitů)
		}
}

void teplota(void)							// výpis v binární a dekadické podobě
{
	int celecislo;
	int zbytek;
	
	line_2();								// výpis v binární podobě
	for(int i = 0; i<16; i++)
		{
			gotoxy(2,(14-i));				//14
			lcd_byt(((hodnota>>i)&0b00000001));
		} 

	//je-li číslo záporné
	if((hodnota>>15)) {
	hodnota=(~hodnota+1);	// převod z dvojkového doplňku
	hodnota|=0xF000;						// indikace záporného čísla (pro znaménko)
	}
	// poznámka: hodnota zobrazená na LCD displeji není převedená hodnota!!

	
	// převod z 16bitové proměnné a rozdělení celé části a zlomkové
	celecislo=(hodnota>>4)&255;				// výpočet celého čísla
	zbytek=10000*(hodnota&15)/16;			// výpočet desetinné části
	
	// výpis na LCD displej
	line_1();
	lcd_text("Teplota:");
	gotoxy(1,12);

	lcd_byt(zbytek/100);					// výpis 2 desetiných míst
	gotoxy(1,9);

	lcd_byt(celecislo);						// výpis celého čísla
	gotoxy(1,12);

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

	lcd_text("C");
	gotoxy(1,9);

	if ((hodnota>>15)) lcd_text("-");		// výpis znaménka
	 	else lcd_text("+");

	if((zbytek/100)<10) 					// ošetření výpisu 0 na LCD
	{
	gotoxy(1,13);
	lcd_text("0");
	}		
}
