
// KNIHOVNA pro obsluhu digitálníhoteplotního čidla DALLAS (DS18B20)

// pro použití časových prodlev je použita knihovna util/delay.h

#include <util/delay.h>

# define DDRQ DDRA
# define PORTQ PORTA
# define PINQ PINA

// registry T_H a T_L
//8-bitové => 7-bit (MSB) =0 pokud je číslo kladné
// následné hledání alarmu je příkazem 0xEC

int presnost = 0b01111111;				// proměnná pro zadání přesnosti měřenní
int T_H = 0x7F;
int T_L = 0xF0;

// hlavní proměnná
int16_t hodnota;

// pomocná proměnná pro výpočty
int16_t posun =1;

//seznam použitých funkcí u teplotního čidla
void reset (void);						  // funkce pro reset teplotního čidla
int16_t teplot_cteni(void);        // přečte celou hodnotu teploty a uloží do hodnota, ta je typu int16_t	
void vysli (int prikaz);				// vyšle daný kód do teplotního čidla
void presnost_cidla(void);      // mění rozlišení čidla 9,10,11 a 12 bitová přesnost
void alarm_zmena(int T_hor, int T_dol); // změna nastavení mezí pro spuštění alarmu

// pomocné podrpogramy
void cteni (int pozice);				// precti bit
void zapis_1 (void);					  // zapise logickou 1 do zarizeni
void zapis_0 (void);				    // zapise logickou 0 do zarizeni
void zapis_scratch (void);
// samotné podprogramy ----------------------------------------------------------------
int16_t teplot_cteni (void)
{
  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í
			}
	return(hodnota);
}

void reset (void)					// reset puls
{
	DDRQ |= 0x02;					// vysílač TX
	PORTQ &= 0xfd;					// nuluje PORT A
	_delay_us(480);					// nuluje po dobu 500us >480us
	DDRQ &=0xfd;						// 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
{
	DDRQ |= 0x02;					// drž na 0 po 6 us
	PORTQ &= 0xfd;
	_delay_us(6);
	DDRQ &= 0xfd;					// uvolni na zbytek do 70us, tedy na 64us
	_delay_us(64);
}
void zapis_0 (void)					// zápis logické 0 na sběrnici
{
	DDRQ |= 0x02;					// zapiš logickou0 po 60us
	PORTQ &= 0xfd;
	_delay_us(60);
	DDRQ &= 0xfd;					// uvolni na 10us
	_delay_us(10);
}

void cteni (int pozice)				// zaznamená příchozí data do proměnné hodnota
{
	DDRQ |= 0x02;					
	PORTQ &= 0xfd;					// vyšli 0 na 6us
	_delay_us(6);
	DDRQ &= 0xfd;					// uvolni a počkej 9us
	_delay_us(9);
									// načti do pole aktuální hodnotu na sběrnici
	if ((PINQ & 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 presnost_cidla (void)				// změna přesnosti měření o stupeň posunout
{
	int presnost_mer;				    // pomocná proměnná

								// 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 a ten se následně pošle do teplotního čidla
		presnost = (presnost_mer<<5)|0b00011111;		

		// aplikace změnu přesnosti
		zapis_scratch();
}

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

void alarm_zmena(int T_hor, int T_dol)
{
	T_H = T_hor;    // změní horní mez  
	T_L = T_dol;    // změní dolní mez
	zapis_scratch();  // zapíše do EEPROM => scratchpad
}
