#include <iom8v.h>
#include <macros.h>
#include <stdlib.h>
#include <eeprom.h>
#include <math.h>

#define SetBit(x,y) (x|=y)
#define ClrBit(x,y) (x&=~y)
#define TestBit(x,y) (x&y)

#define PORT_LCD PORTC
#define LCD_E   0b00010000
#define LCD_RW  0b01000000  
#define LCD_RS  0b00100000

// Скан-коды клавиатуры
// PINB
#define KEY_UP 	  0b00000100
#define KEY_LEFT  0b00001000
#define KEY_ENTER 0b00000010
#define KEY_DOWN  0b00000001
//PIND
#define KEY_RIGHT 0b10000000
#define KEY_START 0b00100000
#define KEY_STOP  0b01000000

// Макросы Запуска/Останова АЦП
#define StartADC ADCSR = 0b11101011;
#define StopADC  ADCSR = 0;

// Макросы Запуска/Останова Т2
#define StartTimer TIMSK = 0x40; 
#define StopTimer  TIMSK = 0; 

#define LedTime 0b00000010
#define LedTerm 0b00000100
#define Zummer  0b00001000

// Макрос чтения клавиатуры
#define ReadKey key=0b00010000; key|=(PINB&0b00001111); key|=(PIND&0b11100000); key^=0xff

#include "lcd.h"
#include "delay.h"
//#include "menu.h"
unsigned int term=0; 						  // Текущая температура
unsigned int time=0; 						  // Текущее время [сек]
unsigned int timeR[4];  					  // Время таймеров режима
unsigned int termR[4]; 						  // Температуры режима
unsigned char key;							  // Скан-код клавиши
unsigned char status=0;						  // Режим работы контроля: 2 - Старт, 1 - Пауза, 0 - Стоп
unsigned char reshim=5;						  // Текущий режим
unsigned int ACP;							  // Результат преобразования АЦП
char i=0,j,k;
unsigned char str[10],str1[10];			 	  // буфера

void DigitTerm(unsigned int Term)
{
 utoa(str,Term,10);
 if(Term>=0)strcpy(str1,"00");
 if(Term>=10)strcpy(str1,"0");
 if(Term>=100)strcpy(str1,"");
 strcat(str1,str); 
 lcd_rus(str1); 
}

void DigitTime(unsigned int Time)
{
 utoa(str,Time/60,10);
 if((Time/60)>=0)strcpy(str1,"0");
 if((Time/60)>=10)strcpy(str1,"");
 strcat(str1,str);  
 lcd_rus(str1);
 WriteSym(':');
 utoa(str,Time%60,10);
 if((Time%60)>=0)strcpy(str1,"0");
 if((Time%60)>=10)strcpy(str1,"");
 strcat(str1,str); 
 lcd_rus(str1); 
}

void menu(void)
{
  WriteDDR(0x81);
  WriteSym('0'+j);
  WriteDDR(0xc1);
  WriteSym('0'+j);
  
  if(termR[j]>300)termR[j]=300;
  if(termR[j]<0)termR[j]=0; 
    
  WriteDDR(0x83);
  DigitTerm(termR[j]);
   
  
  if(timeR[j]>5999)timeR[j]=5999;
  if(timeR[j]<0)timeR[j]=0;
    
  WriteDDR(0xc3);
  DigitTime(timeR[j]);
  
}

void adc_init(void)
{
 ADCSR = 0x00; 	   	  						  // Отключаем АЦП
 ADMUX = 0b11000111;  						  // Внутренний ИОН, AD7 (только для TQFP)
 ACSR  = 0b10000000;  						  // Отключаем компаратор
 ADCSR = 0b11101011;  						  // Вкл АЦП,режим непрерывного преобразования,время преобразования: 104uS
}

void timer1_init(void)
{
 TCCR1B = 0x00; //stop
 TCNT1H = 0xCF; //setup
 TCNT1L = 0x2C;
 OCR1AH = 0x30;
 OCR1AL = 0xD4;
 OCR1BH = 0x30;
 OCR1BL = 0xD4;
 ICR1H  = 0x30;
 ICR1L  = 0xD4;
 TCCR1A = 0x00;
 TCCR1B = 0x02; //start Timer
}

void timer2_init(void)
{
 TCCR2 = 0x00; //stop
 ASSR  = 0x08; //set async mode
 TCNT2 = 0xE0; //setup
 OCR2  = 0x20;
 TCCR2 = 0x07; //start
}

#pragma interrupt_handler timer2_ovf_isr:5
void timer2_ovf_isr(void)
{
 //1 Гц
 TCNT2 = 0xE0; //reload counter value
 
 WriteDDR(0x80);
 WriteSym(' '); 
 DigitTerm(term);
 WriteSym(1);
 lcd_rus(" / "); 
 DigitTerm(termR[j]);
 WriteSym(1);
 lcd_rus("   ");
 
 WriteDDR(0xc0); 
 WriteSym(' '); 
 DigitTime(timeR[j]-time);
 
 WriteSym(' ');
 WriteSym('0'+j);
 WriteSym('/');
 WriteSym('0'+status);
 WriteSym(' ');
 
 if(i==1)
 {
  SetBit(PORTD,LedTime);
 }
 else
 {
  ClrBit(PORTD,LedTime);
  //ClrBit(PORTD,LedTerm);
  //PORTD=0;
 }
 
 if(timeR[j]==0)
 {
  status=0;
  return;
 }
 
 if((status==2)&&(i==1))
 {
  time++;
  if(timeR[j]==time)
  {   
   if(j==2)status=0;
   j++;
   i=0;
   time=0;
  }
 } 
}

#pragma interrupt_handler adc_isr:15
void adc_isr(void)
{  
 ACP=ADCL;            	   					  //Чтение младшиго байта преобразования
 ACP|=(int)ADCH << 8; 	  					  //Чтение страршего байта преобразования
 
 if(ACP<232)ACP=232;  						  // Ограничение нижнего предела -40 град
 if(ACP>1215) ACP=1215; 					 // Ограничение верхнего предела 400 град
 
 term=((ACP*44)/100)-135;
 
 if(status==2)
 {
  if(term < termR[j])
  {   
   SetBit(PORTD,0b00010000);
   SetBit(PORTD,LedTerm);
  }
  else
  {
   i=1;
   ClrBit(PORTD,0b00010000);
   ClrBit(PORTD,LedTerm);   
  }  
 }
 else
 {
  ClrBit(PORTD,0b00010000);
  //ClrBit(PORTD,LedTerm); 
 }
 
 ReadKey;
  
  switch(key)
  {
   case KEY_STOP:
   Delay_ms(40);
   ReadKey;
   if(key==KEY_STOP)
   {
    if(status>0)status--;	
	while(key==KEY_STOP)
	{
	 ReadKey;
	}
	Delay_ms(30);
   }
   break;
   
   case KEY_START:   
   Delay_ms(50);
   ReadKey;
   if(key==KEY_START)
   {
    if(status==1)status=2;
	
	Delay_ms(50);
   }
  } 
 
}

void main()
{  
 DDRC=0xff;			   	 					  // Порт С на выход
 DDRD=0b00011110;
 ClrBit(PORTD,0b00011110);
 Delay_ms(50);
 lcd_init();  		  						  // Инициализация ЖК
 Write_CGRAM(); 							  // Рисуем в патяти стрелку и знак градуса
 adc_init();  		   						  // Инициализация АЦП
 timer1_init();								  // Инициализация Т1
 timer2_init();								  // Инициализация Т2
 ClrCur;									  // Отключаем курсор, сторока обязательна 
 //TIMSK = 0x40; 							  // Разрешаем прерывание от Т2
 SEI();
 Delay_mks(50);
  
 menu0: 	   								  ////////////////// Главное меню///////////////////////
 
 StopADC;
 i=0;  
 ClrCur;
 WriteDDR(0x80);
 lcd_rus(" Установки  "); 
 WriteDDR(0xc0);
 lcd_rus(" Режимы     ");    								  
 while(1) 
 {  
  WriteDDR(0x80+i*0x40);
  WriteSym(0);
  ReadKey;
  
  switch(key)
  {
   case KEY_DOWN:   
   Delay_ms(30);
   ReadKey;   
   if(key==KEY_DOWN)
   { 
    WriteDDR(0x80+i*0x40);
    WriteSym(' ');
	i^=1;  
   } 
   break;
   
   case KEY_UP:
   Delay_ms(30);
   ReadKey;
   if(key==KEY_UP)
   {
    WriteDDR(0x80+i*0x40);
    WriteSym(' ');
	i^=1;
   } 
   break;
   
   case KEY_ENTER:
   Delay_ms(30);
   ReadKey;
   if(key==KEY_ENTER) 
   {
    if(i)
	{
	 goto menu02;	  						  // Меню выбора режимов
	}
	else
	{
	 goto menu01;							  // Меню установки режимов	
	}
   }
   break;
   
   case KEY_START:
   Delay_ms(20);
   ReadKey;
   if(key==KEY_START)
   {
    if(reshim==5)
	{
	 WriteDDR(0x80);
	 lcd_rus("   Режим    ");	 
	 WriteDDR(0xc0);
	 lcd_rus(" не выбран! ");	 
	 Delay_ms(300);
	 goto menu0;
	}
	WriteDDR(0x80);
	lcd_rus(" Запуcтить  ");	
	WriteDDR(0xc0);
	lcd_rus("  Режим  ?  ");	
	WriteDDR(0xc8);
	WriteSym('1'+reshim);
	Delay_ms(60);
	while(1)
	{
			
	 ReadKey;
	 
	 switch(key)
	 {	  
	  case KEY_START:
	  Delay_ms(20);
	  ReadKey;
	  if(key==KEY_START)
	  {
	   
	   status=2;	   
	   time=0;
	   Delay_ms(20);
	   goto start;
	  }
	  break;
	  
	  case KEY_STOP:	  
	  ReadKey;
	  if(key==KEY_STOP)
	  {
	   Delay_ms(30);
	   goto menu0;
	  }	 
	 }	 
	}
   }
  }   
 }
 
 menu02:			  			 		  		//Меню выбора режима
 
 BrigCur;
 StopADC;
 WriteDDR(0);								  // Очищаем экран
 Delay_ms(1);
 WriteDDR(0x80);
 lcd_rus("  Режимы:   ");
 WriteDDR(0xc0);
 i=0;
 lcd_rus(" 1 2 3 4"); 
 while(1)
 {   	
  WriteDDR(0xc0+i*2+1);
  BrigCur;
  ReadKey;
  
  switch(key)
  {
   
   case KEY_RIGHT:
   Delay_ms(20);
   ReadKey;
   if(key==KEY_RIGHT)
   {
    if(i<3)
	{
	 WriteDDR(0xc0+i*2);
	 WriteSym(' ');
	 i++;
	}
	Delay_ms(20);
   }
   break;
   
   case KEY_LEFT:
   Delay_ms(20);
   ReadKey;
   if(key==KEY_LEFT)
   {
    if(i>0)
	{
	 WriteDDR(0xc0+i*2);
	 WriteSym(' ');
	 i--;
	}
	Delay_ms(20);
   }   
   
   case KEY_ENTER:   
   Delay_ms(20);
   ReadKey;
   if(key==KEY_ENTER) 
   {
    Delay_ms(20);
	goto menu020;
   }
   break;
   
   case KEY_STOP:   
   Delay_ms(20);
   ReadKey;
   if(key==KEY_STOP) 
   {
    Delay_ms(20);
	goto menu0;
   }
   break;
   
  }				  
 }
  
 menu01:		  	 	  		  ////////////////////// Установка режима/////////////////////////////
 BrigCur;
 StopADC;
 //WriteDDR(0);								  // Очищаем экран
 //Delay_ms(1);
 WriteDDR(0x80);
 lcd_rus(" Установка: "); 
 WriteDDR(0xc0);
 lcd_rus(" 1 2 3 4"); 
 Delay_ms(20);
 while(1)
 {   	
  WriteDDR(0xc0+i*2+1);
  BrigCur;
  ReadKey;
  
  switch(key)
  {
   
   case KEY_RIGHT:
   Delay_ms(20);
   ReadKey;
   if(key==KEY_RIGHT)
   {
    if(i<3)
	{
	 WriteDDR(0xc0+i*2);
	 WriteSym(' ');
	 i++;
	 Delay_ms(20);
	}
   }
   break;
   
   case KEY_LEFT:
   Delay_ms(30);
   ReadKey;
   if(key==KEY_LEFT)
   {
    if(i>0)
	{
	 WriteDDR(0xc0+i*2);
	 WriteSym(' ');
	 i--;
	 Delay_ms(20);
	}
   }   
   
   case KEY_STOP:   
   Delay_ms(20);
   ReadKey;
   if(key==KEY_STOP) 
   {
    Delay_ms(20);
	goto menu0;
   }
   break;
   
   case KEY_ENTER:   
   Delay_ms(20);
   ReadKey;
   if(key==KEY_ENTER) 
   {
	Delay_ms(20);
	goto menu010;	
   }
   break;
   
  }				  
 } 
  
 menu020:				   //////////////////////Просмотр выбраного	режима//////////
 j=0;
 k=0;
 ClrCur;
 if(i>4)i=4;
 if(i<0)i=0;
 
 EEPROM_READ(0x1+i*13,timeR);
 EEPROM_READ(0x1+i*13+6,termR);  
 
 WriteDDR(0x80);
 lcd_rus("T =   \1C    "); 
 WriteDDR(0xc0);
 lcd_rus("t =  :      "); 
 Delay_ms(50);
 while(1)
 {
  
  menu();  
     
  Delay_ms(10);
  ReadKey;
  switch(key)
  {
   case KEY_ENTER:
   Delay_ms(20);
   ReadKey;
   if(key==KEY_ENTER)
   {    
    if(j==2)
	{
	 reshim=i;
	 Delay_ms(20);
	 goto menu0;
	}
    j++;
	Delay_ms(20);
   }
   break;    
   
   case KEY_STOP:
   Delay_ms(20);
   ReadKey;
   if(key==KEY_STOP)
   {
    Delay_ms(20);
	goto menu02;
   } 
   break;
  }
 } 
 
 menu010:				   ////////////////////Установки выбранного режима////////////
 
 j=0;
 k=0; 
 
 if(i>4)i=4;
 if(i<0)i=0;
 
 WriteDDR(0x80);
 lcd_rus("T =   \1C    ");
 WriteDDR(0xc0);
 lcd_rus("t =  :      ");
 
 EEPROM_READ(0x1+i*13,timeR);
 EEPROM_READ(0x1+i*13+6,termR);
  
 Delay_ms(50);
 while(1)
 {
 
  BrigCur;  
  
  menu();  
  
  if(k<3)WriteDDR(0x83+k);
  if((k>=3))WriteDDR(0xc0+k+k/5);  
  Delay_ms(10);
  ReadKey;
   
  switch(key)
  {
   case KEY_STOP:
   Delay_ms(20);
   ReadKey;
   
   if(key==KEY_STOP)
   {
    Delay_ms(20);
    goto menu01;
   }
	
   case KEY_LEFT:
   Delay_ms(20);
   ReadKey;
   if(key==KEY_LEFT)
   {    
	if(k>0)k--;	
	Delay_ms(20);
   }
   break;
   
   case KEY_RIGHT:
   Delay_ms(20);
   ReadKey;
   if(key==KEY_RIGHT)
   {
    if(k<6)k++;	
	Delay_ms(20);
   }
   break;
   
   case KEY_DOWN:
   Delay_ms(20);
   ReadKey;
   
   if(key==KEY_DOWN)
   {  
    	 
	switch(k)
	{
	 case 0:
	 if(termR[j]>=100)termR[j]-=100;
	 break;
	 
	 case 1:
	 if(termR[j]>=10)termR[j]-=10;
	 break;
	 
	 case 2:
	 if(termR[j]>0)termR[j]--;
	 break;
	 
	 case 3:
	 if(timeR[j]>=600)timeR[j]-=600;
	 break;
	 
	 case 4:
	 if(timeR[j]>=60)timeR[j]-=60;
	 break;
	 
	 case 5:
	 if(timeR[j]>=10)timeR[j]-=10;
	 break;
	 
	 case 6:
	 if(timeR[j]>0)timeR[j]--;
	 break;	 
	}	
	
	Delay_ms(20);
   }
   
   case KEY_UP:
   Delay_ms(20);
   ReadKey;
   
   if(key==KEY_UP)
   {  
      
	switch(k)
	{
	 case 0:
	 termR[j]+=100;
	 break;
	 
	 case 1:
	 termR[j]+=10;
	 break;
	 
	 case 2:
	 termR[j]++;
	 break;
	 
	 case 3:
	 timeR[j]+=600;
	 break;
	 
	 case 4:
	 timeR[j]+=60;
	 break;
	 
	 case 5:
	 timeR[j]+=10;
	 break;
	 
	 case 6:
	 timeR[j]++;
	 break;	 
	}	
	
	Delay_ms(20);
   }
   
   break;
   
   case KEY_ENTER:
   Delay_ms(20);
   ReadKey;
   
   if(key==KEY_ENTER)
   {
    
	WriteDDR(0x80);
	lcd_rus("  Записано  ");	
	WriteDDR(0xc0);
	lcd_rus("  ");
	WriteSym('t');
	WriteSym('0'+j);
	lcd_rus(" и T");	
	WriteSym('0'+j);
	WriteSym(' ');
	ClrCur;
	Delay_ms(250);	
	
	EEPROM_WRITE(0x1+i*13,timeR);
    EEPROM_WRITE(0x1+i*13+6,termR);
	
    if(j==2)
	{
	 Delay_ms(20);
	 goto menu0;
	}
    j++;
	WriteDDR(0x80);
    lcd_rus("T =   \1C    ");	
    WriteDDR(0xc0);
    lcd_rus("t =  :      ");		
	Delay_ms(20);
   }
    break;  
  }
 }
 
 start:			  	  	   ///////////////////////Старт контроля////////////////////
 StartADC;
 StartTimer;
 ClrCur;
 i=0;
 j=0;
 time=0;
 status=2;
 PORTD=0;
 
 while(1)
 {
 
  if(status==0)
  {
   CLI();
   StopADC;
   StopTimer;
   i=0;
   //ClrBit(PORTD,LedTime);
   PORTD=0;
   Delay_ms(20);
   //CLI();
   //ClrBit(PORTD,(0b00010000+LedTerm));   
   j=0;
   while(j<8)
   {
    PORTD^=Zummer;
	j++;
	Delay_ms(100);
   }
   ClrBit(PORTD,Zummer);
   j=0;
   goto menu0;
  }
  SEI();
 } 
}