//--------------------------------------------------------------------------------------------------
//	PROGRAM : I2C + PCF8583 routines
//	VERSION : 1.0
//	AUTHOR  : Bc. Pazour Zbyněk
//	DATE	: 07.09.2009
//--------------------------------------------------------------------------------------------------

#include "i2c.h"
#include <util/twi.h>
volatile unsigned char  sec, min, hour, day,year, month,year_,eeadr;	//promenne
#define MENU    PINB3												//definice tlacitek
#define ESC 	PINB2
#define UP 		PINB1
#define DOWN 	PINB0
static char b;
int rok=0;

//--------------------------------------------------------------------------------------------------
// Inicializace I2C
//--------------------------------------------------------------------------------------------------

void i2c_init (void)
{
	
	TWCR = 0b01000100;
	TWAR = 0b01010100;
	TWBR = 100;
	TWSR = 0b11111000;

}
void ERROR (void)
{
	lcd_gotoxy(1,1);
	lcd_puts("Chyba I2C");
}

void kontrola (unsigned short STAV)
{
	if ((TWSR & 0xF8) != STAV)
	ERROR();
}

void twi_start (void)
{
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);			//Start
}

void hotovo (void)									//Ceka dokud neskonci komunikace
{
	while (!(TWCR & (1<<TWINT)));
}

void vysli (unsigned short ADR)						//vysláni řetězce dat
{
	TWDR = ADR;
	TWCR = (1<<TWINT)|(1<<TWEN);
}

void cti_data_ACK (void)							//Načtení řetězce dat s potvrzením přijetí ACK
{
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
}

void cti_data_NACK (void)							//Načtení řetězce dat s bez potvrzení přijetí ACK
{
	TWCR = (1<<TWINT)|(1<<TWEN);
}

void twi_stop (void)								//Konec I2C komunikace
{
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
}

//--------------------------------------------------------------------------------------------------
// Inicializace RTC PCF 8583
//--------------------------------------------------------------------------------------------------


void init_RTC (void)
{
	twi_start();
	hotovo();
	kontrola(TW_START);


	vysli(0xA0);				//Adresa RTC obvodu pro zápis dat
	hotovo();
	kontrola(TW_MT_SLA_ACK);

	vysli(0x00);				//Adresa kontrolního registru
	hotovo();
	kontrola(TW_MT_DATA_ACK);
	
	
	vysli(0x0C);				//Nastaveni oscilatoru 32.768 kHz
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	twi_stop();
	delay_ms(10);

	twi_start();
	hotovo();
	kontrola(TW_START);


	vysli(0xA0);				//Adresa RTC obvodu pro zápis dat
	hotovo();
	kontrola(TW_MT_SLA_ACK);

	vysli(0x08);				//Adresa kontrolního registru přerušení od RTC
	hotovo();
	kontrola(TW_MT_DATA_ACK);
	
	
	vysli(0b11000011);			//Nastavení přerušení(porovníní čítače s periodou, čítání minut)
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	twi_stop();
   	delay_ms(10);
}
//********************************
//**Nastavení periody přerušení
//*******************************
void nastav_citac (char citac)
{
	citac = ((citac/10)<<4) | (citac%10 & 0x0f);
	twi_start();
	hotovo();
	kontrola(TW_START);


	vysli(0xA0);				//Adresa RTC obvodu pro zápis dat
	hotovo();
	kontrola(TW_MT_SLA_ACK);

	vysli(0x0F);				//Adresa kontrolního registru
	hotovo();
	kontrola(TW_MT_DATA_ACK);
	
	
	vysli(citac);				
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	twi_stop();
	delay_ms(10);
}

//******************************
//***Vynulování čítače a příznaku přerušení
//******************************
void nul_citac (void)
{
	twi_start();
	hotovo();
	kontrola(TW_START);


	vysli(0xA0);				//Adresa RTC obvodu pro zápis dat
	hotovo();
	kontrola(TW_MT_SLA_ACK);

	vysli(0x07);				//Adresa čítače
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	vysli(0x00);				//Vynulování čítače
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	twi_stop();
	delay_ms(10);

	twi_start();     
	hotovo();
	kontrola(TW_START);	
	
	vysli(0xA0);					//nastaveni adresy rtc pro zapis
	hotovo();
	kontrola(TW_MT_SLA_ACK);
	
	vysli(0x00);					//adresa kontrolního registru
	hotovo();
	kontrola(TW_MT_DATA_ACK);
	
	vysli(0x0C);					//vynulování příznaku přerušení
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	twi_stop();
	delay_ms(10);
}


//*************************************************
//*  Načtení hodnot RTC
//*************************************************


void nacti_RTC (void)
{
//-----------------------------------
// cteni sekund
//-----------------------------------

	twi_start();     
	hotovo();
	kontrola(TW_START);				//start i2c
	

	vysli(0xA0);					//nastaveni adresy rtc pro zapis
	hotovo();
	kontrola(TW_MT_SLA_ACK);
	
	vysli(0x02);					//adresa sekund
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	twi_start();					//repeticni start
	hotovo();
	kontrola(TW_REP_START);

	vysli(0xA1);					//adresa rtc pro čtení dat z rtc
	hotovo();
	kontrola(TW_MR_SLA_ACK);

	cti_data_ACK();					//Nacteni aktualni hodnoty sekund
	hotovo();
	kontrola(TW_MR_DATA_ACK);
	sec = TWDR;						//ulozeni do sec
	
//-----------------------------------
// cteni minut            adresa se automaticky inkrementuje v RTC
//-----------------------------------

	cti_data_ACK();					//Minuty
	hotovo();
	kontrola(TW_MR_DATA_ACK);
	min = TWDR;						//uložení BCD hodnoty minut do min

//-----------------------------------
// cteni hodin
//-----------------------------------
	cti_data_ACK();					//Hodiny
	hotovo();
	kontrola(TW_MR_DATA_ACK);
	hour = TWDR;

//-----------------------------------
// cteni dnu v mesici a roku
//-----------------------------------
	cti_data_ACK();					//Den v mesici prvnich 6 bitu
	hotovo();						//Rok posledni dva bity
	kontrola(TW_MR_DATA_ACK);
	day= TWDR;
	
//-----------------------------------
// cteni mesice
//-----------------------------------
	cti_data_NACK();				//mesic
	hotovo();
	kontrola(TW_MR_DATA_NACK);
	month = TWDR;	
	twi_stop();						//Konec I2c komunikace

	delay_ms(10);


	twi_start();     
	hotovo();
	kontrola(TW_START);				
	

	vysli(0xA0);					
	hotovo();
	kontrola(TW_MT_SLA_ACK);
	
	vysli(0x10);					//Adresa 0x10 ve volné paměti RAM rtc obvodu,
	hotovo();
	kontrola(TW_MT_DATA_ACK);		// kam ukládám BCD hodnotu rokú v rozmezí 0-99

	twi_start();					
	hotovo();
	kontrola(TW_REP_START);

	vysli(0xA1);					
	hotovo();
	kontrola(TW_MR_SLA_ACK);
	
	cti_data_NACK();				
	hotovo();
	kontrola(TW_MR_DATA_NACK);
	year = TWDR;
	
	twi_stop();	
	
		//cyklus pro kontrolu, zda nenastal nový rok, pokud nastal, tak inkrementuji rok

	if (((month>>4)*10+(month&0x0f))==12)
	{
		if ((((day&0x3f)>>4)*10+(day&0x0f))==31)
		{
			if (((hour>>4)*10+(hour&0x0f))==23)
			{
				if (((min>>4)*10+(min&0x0f))==59)
				{
					if (((sec>>4)*10+(sec&0x0f))==56)
					{
						delay_ms(1000);
						year_ = (year>>4)*10+(year&0x0f);
						year_++;
						year = ((year_/10)<<4) | (year_%10 & 0x0f);
						if(rok>3)
						{
						rok++;
						}
						else rok=0;
						zapis_rok();
					}
				}
			}	
		}	
	}
	delay_ms(10);			
}
//--------------------------------------------------------------------------------------------------
// Zapsani noveho roku
// V případě, že nastal nový rok, tak jeho hodnotu inkrementuji a uložím do RAM rtc na adresu 0x10
//--------------------------------------------------------------------------------------------------
void zapis_rok (void)
{
	day=(day|(rok<<6));

	twi_start();     
	hotovo();
	kontrola(TW_START);	
	
	vysli(0xA0);					//nastaveni adresy rtc pro zapis
	hotovo();
	kontrola(TW_MT_SLA_ACK);
	
	vysli(0x05);					
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	vysli(day);		//dny
	hotovo();
	kontrola(TW_MT_DATA_ACK);
	twi_stop();	

	delay_ms(10);

	twi_start();     
	hotovo();
	kontrola(TW_START);	
	
	vysli(0xA0);					//nastaveni adresy rtc pro zapis
	hotovo();
	kontrola(TW_MT_SLA_ACK);
	
	vysli(0x10);					
	hotovo();
	kontrola(TW_MT_DATA_ACK);
	
	vysli(year);					
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	twi_stop();
	delay_ms(10);
}
//--------------------------------------------------------------------------------------------------
// Zobrazeni casu a datumu
//--------------------------------------------------------------------------------------------------
void zobraz_cas (void)
{

	

	lcd_gotoxy(0,0);
	lcd_putc(0x30+(hour >> 4));			//prevedeni a zobrazeni BCD formatu hodin
	lcd_putc(0x30+(hour & 0x0f));
	lcd_putc(':');
	lcd_putc(0x30+(min >>4));
	lcd_putc(0x30+(min & 0x0f));
	lcd_putc(':');
	lcd_putc(0x30+(sec >> 4));
	lcd_putc(0x30+(sec & 0x0f));
	
	lcd_gotoxy(0,1);
	lcd_putc(0x30+((day&0x3f)>> 4));	//prevedeni a zobrazeni BCD formatu hodin
	lcd_putc(0x30+(day & 0x0f));		//poslední dva bity určují rok
	lcd_putc('.');

	lcd_putc(0x30+(month>> 4));			
	lcd_putc(0x30+(month & 0x0f));
	lcd_putc('.');
	lcd_putc(0x30+(year >> 4));			
	lcd_putc(0x30+(year & 0x0f));		
	

}
//--------------------------------------------------------------------------------------------------
// Zapsani casu a datumu
//--------------------------------------------------------------------------------------------------

void zapis_RTC (void)
{
	twi_start();     
	hotovo();
	kontrola(TW_START);	
	
	vysli(0xA0);					//nastaveni adresy rtc pro zapis
	hotovo();
	kontrola(TW_MT_SLA_ACK);
	
	vysli(0x02);					//adresa sekund
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	vysli(sec);						//Sekundy
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	vysli(min);						//Minuty
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	vysli(hour);					//Hodiny
	hotovo();
	kontrola(TW_MT_DATA_ACK);
	
	vysli(day);						//dny
	hotovo();
	kontrola(TW_MT_DATA_ACK);
	
	vysli(month);					//mesice
	hotovo();
	kontrola(TW_MT_DATA_ACK);

	twi_stop();	

	delay_ms(10);

	zapis_rok();	
}

//--------------------------------------------------------------------------------------------------
// Nastaveni casu a data
//--------------------------------------------------------------------------------------------------

void nastav_cas(void)
{

nacti_RTC();
zobraz_cas();
lcd_command(0x0E);
lcd_gotoxy(0,0);
b=0;
	unsigned char month_,min_,sec_,hour_,day_;						// definice pomocných proměnných
	while (b < 7)
	{

//Tlacitko NAHORU 
		if (!(PINB&(1<<UP)))
			{
			switch (b)
				{
					
						case 0:
						{
							hour_ = (hour>>4)*10+(hour&0x0f);		// konverze BCD hodnoty na dekadickou
							if (hour_ < 23) hour_++;				// kontrola zda už není další den
								else hour_ = 0;
							hour = ((hour_/10)<<4) | (hour_%10 & 0x0f);	// konverze zpět na BDC hodnotu hodin
							lcd_putc(0x30+(hour >> 4));					// zobrazení na displej
							lcd_putc(0x30+(hour & 0x0f));				// zobrazení na displej
							lcd_gotoxy(0,0);
						}break;
						
						case 1:
						{
							min_ = (min>>4)*10+(min&0x0f);
							if (min_ < 59) min_++;
								else min_ = 0;
							min = ((min_/10)<<4) | (min_%10 & 0x0f);
							lcd_putc(0x30+(min >> 4));
							lcd_putc(0x30+(min & 0x0f));
							lcd_gotoxy(3,0);
						}break;
						
						case 2:
						{
							sec_ = (sec>>4)*10+(sec&0x0f);
							if (sec_ < 59) sec_++;
								else sec_ = 0;
							sec = ((sec_/10)<<4) | (sec_%10 & 0x0f);
							lcd_putc(0x30+(sec >> 4));
							lcd_putc(0x30+(sec & 0x0f));
							lcd_gotoxy(6,0);
						}break;

						case 3:
						{
							day_ = ((day&0x3f)>>4)*10+(day&0x0f);
							if (day_ < 31) day_++;
								else day_ = 1;
							day = ((day_/10)<<4) | (day_%10 & 0x0f);
							lcd_putc(0x30+(day >> 4));
							lcd_putc(0x30+(day & 0x0f));
							lcd_gotoxy(0,1);
						}break;

						case 4:
						{
							month_ = (month>>4)*10+(month&0x0f);
							if (month_ < 12) month_++;
								else month_ = 1;
							month = ((month_/10)<<4) | (month_%10 & 0x0f);
							lcd_putc(0x30+(month >> 4));
							lcd_putc(0x30+(month & 0x0f));
							lcd_gotoxy(3,1);
						}break;

						case 5:
						{
							year_ = (year>>4)*10+(year&0x0f);
							if (year_ < 99) year_++;
								else year_ = 1;
							if (rok< 3) rok++;
								else rok = 0;
							year = ((year_/10)<<4) | (year_%10 & 0x0f);
							lcd_putc(0x30+(year >> 4));
							lcd_putc(0x30+(year & 0x0f));
							lcd_gotoxy(6,1);
						}break;
				
				}
				delay_ms(170);
			}

//Tlacitko DOLU			
			if (!(PINB&(1<<DOWN)))
			{
				switch (b)
				{
						case 0:
						{
							hour_ = (hour>>4)*10+(hour&0x0f);
							if (hour_ > 1) hour_--;
								else hour_ = 23;
							hour = ((hour_/10)<<4) | (hour_%10 & 0x0f);
							lcd_putc(0x30+(hour >> 4));
							lcd_putc(0x30+(hour & 0x0f));
							lcd_gotoxy(0,0);
						}break;
						
						case 1:
						{
							min_ = (min>>4)*10+(min&0x0f);
							if (min_ > 1) min_--;
								else min_ = 59;
							min = ((min_/10)<<4) | (min_%10 & 0x0f);
							lcd_putc(0x30+(min >> 4));
							lcd_putc(0x30+(min & 0x0f));
							lcd_gotoxy(3,0);
						}break;
						
						case 2:
						{
							sec_ = (sec>>4)*10+(sec&0x0f);
							if (sec_ > 1) sec_--;
								else sec_ = 59;
							sec = ((sec_/10)<<4) | (sec_%10 & 0x0f);
							lcd_putc(0x30+(sec >> 4));
							lcd_putc(0x30+(sec & 0x0f));
							lcd_gotoxy(6,0);
						}break;

						case 3:
						{
							day_ = ((day&0x3f)>>4)*10+(day&0x0f);
							if (day_ > 1) day_--;
								else day_ = 31;
							day = ((day_/10)<<4) | (day_%10 & 0x0f);
							lcd_putc(0x30+(day >> 4));
							lcd_putc(0x30+(day & 0x0f));
							lcd_gotoxy(0,1);
						}break;

						case 4:
						{
							month_ = (month>>4)*10+(month&0x0f);
							if (month_ > 1) month_--;
								else month_ = 12;
							month = ((month_/10)<<4) | (month_%10 & 0x0f);
							lcd_putc(0x30+(month >> 4));
							lcd_putc(0x30+(month & 0x0f));
							lcd_gotoxy(3,1);
						}break;

						case 5:
						{
							year_ = (year>>4)*10+(year&0x0f);
							if (year_ > 1) year_--;
								else year_ = 99;
							if (rok> 0) rok--;
								else rok = 3;
							year = ((year_/10)<<4) | (year_%10 & 0x0f);
							lcd_putc(0x30+(year >> 4));
							lcd_putc(0x30+(year & 0x0f));
							lcd_gotoxy(6,1);
						}break;
					}	

				delay_ms(170);
			}
//Tlacitko MENU 
			if (!(PINB&(1<<MENU)))
			{
			b++;
			delay_ms(170);
					switch (b)
					{
						case 0: lcd_gotoxy(0,0); break;
						case 1: lcd_gotoxy(3,0); break;
						case 2: lcd_gotoxy(6,0); break;
						case 3: lcd_gotoxy(0,1); break;
						case 4: lcd_gotoxy(3,1); break;
						case 5: lcd_gotoxy(6,1); break;
						case 6: b=9;
					}
			
			
			}
//Tlacitko ESC 		
			if (!(PINB&(1<<ESC)))
			{	
			b--;
			delay_ms(170);
					switch (b)
					{
						case 0: lcd_gotoxy(0,0); break;
						case 1: lcd_gotoxy(3,0); break;
						case 2: lcd_gotoxy(6,0); break;
						case 3: lcd_gotoxy(0,1); break;
						case 4: lcd_gotoxy(3,1); break;
						case 5: lcd_gotoxy(6,1); break;
						case 6: b=9;
					}
				
			
			}
	}
lcd_command(0x0C);
lcd_clrscr();
zapis_RTC();
}


//--------------------------------------------------------------------------------------------------
// Smazani casu a data
//--------------------------------------------------------------------------------------------------	
void smaz_cas(void)
{
sec=0;
min=0;
hour=0;
day=0;
year=0;
month=0;

zapis_RTC();


}
	
	



