#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/eeprom.h>

#define RS 6        //RS=PA6 - сигнал управления ЖКИ
#define E  5        //E=PA5  - строб-сигнал

#define BITSET(var,bitno)	((var) |= 1 << (bitno))   
#define BITCLR(var,bitno)	((var) &= ~(1 << (bitno)))
#define BITTST1(var,bitno)	((var) & (1 << (bitno))) 
#define BITTST0(var,bitno)	(!((var) & (1 << (bitno))))
#define BITINV(var,bitno)	var=(var^(1 << (bitno)))

/*

а0-а3 дата,
а4- вход,
а5-строб, 
а6-инф\дата,
в2-сброс 

*/
void lcd_pre_init(void);
void lcd_com (unsigned char lcd);
void lcd_dat (unsigned char lcd);
void lcd_show(void);
void lcd_init (void);
//---------------------------------------------------------
static char m = 0; 			// сотни метров
EEMEM  unsigned long  km; 		// расстояние в километрах полное в еепром
volatile unsigned long  km_full;		// расстояние в километрах полное
volatile unsigned int km_temp;			// расстояние в километрах за день
unsigned char dat;		// выводимый символ
volatile unsigned char cFlag;	
//---------------------------------------------------------
enum FLAGS{FLAG_READY=0,FLAG_END}FLAGS;
//ISR(EXT_INT0_vect)
//{
//	/* обнуление текущего пробега по нажатию кнопки  */
//
//	km_temp ++; // при нажатии на кнопку должно увеличиваться число перед запятой
//	// во 2-й строке. нужно только для отладки. в норм проге будет km_temp=0;
//	m = 0;
//	sei();
//}


ISR(TIM1_COMPA_vect)
{
	/*увеличение числа сотен метров. прерывание при достижении счетчиком значения max == 425*/
	TCNT1 = 0; // при скорости 250 км/ч инкримент счетчика каждые 3,33мс
	m++; 
	if (m == 10)
	{
		BITSET(cFlag,FLAG_READY);
		m = 0;
	}
}
//--------------------------------------------------------------------








int main (void)
{
	DDRA = 0xEF;	 					// порт А работает как выход
	DDRB = 0x00;						// порт В работает как вход
	PORTB = 0x0F;
//	GIMSK = 0x40;						// разрешение прерывания от INT0
//	MCUCR = 0x00;						// прерывание реагирует на 0 на INT0
					// Output Compare A Match Interrupt Enable
	BITCLR(cFlag,FLAG_READY);
	TCCR1A = 0;
	TCCR1B = 0x06;						// таймер считает импульсы от Т1 при переходе в нижний уровень
	OCR1A = 0x0425;
						// забиваем значение на сравнение
	TIMSK1 |= (1<<OCIE1A);			//Enable Int for OC1A

	km_full = eeprom_read_dword(&km);	//Чтение EEPROM
	lcd_pre_init();
	lcd_show();
	sei();
	while(1)
	{
		if(BITTST1(cFlag,FLAG_READY))
		{
			BITCLR(cFlag,FLAG_READY);
			km_temp++;
			km_full++;
		//	eeprom_write_dword(&km, km_full);	//Запись EEPROM
			lcd_show();
		}

	}

}

//--------------------------------------------------------------------
void lcd_pre_init(void)
{
	/*
	троекратная команда установки 8-битного режима для раздупления дисплея. Вместо 0x30 подается
	0x03, т.к. у меня выводам D5-D8 дисплея соответствуют выводы D0-D3 МК
	*/
	PORTA = ((0x03)&~(1<<RS))|(1<<E);		
	_delay_us(50);					 		
	PORTA = ((0x03)&~(1<<RS))&~(1<<E);
	_delay_ms(20);

	PORTA = ((0x03)&~(1<<RS))|(1<<E);		
	_delay_us(50);					 		
	PORTA = ((0x03)&~(1<<RS))&~(1<<E);
	_delay_ms(2);

	PORTA = ((0x03)&~(1<<RS))|(1<<E);		
	_delay_us(50);					 		
	PORTA = ((0x03)&~(1<<RS))&~(1<<E);
	_delay_ms(2);

	PORTA = ((0x02)&~(1<<RS))|(1<<E);		// установка 4-битного режима, далее дисплей работает в нем	
	_delay_us(50);					 		
	PORTA = ((0x02)&~(1<<RS))&~(1<<E);
	_delay_ms(2);						
	lcd_init(); 
}
//----------------------------------------------------------------------
void lcd_com (unsigned char lcd) 
{ 
	unsigned char temp;

	temp = ((lcd >> 4)&~(1<<RS))|(1<<E);	// RS=0 – это команда
	PORTA = temp;							// Выводим на portА старшую тетраду команды, сигналы RS, E 
	_delay_us(50);					 		// Небольшая задержка для стабилизации
	PORTA = temp&~(1<<E);					// Сигнал записи команды

	_delay_us(50);						// задержка между циклами записи

	temp=(((lcd<<4)>>4)&~(1<<RS))|(1<<E);// RS=0 – это команда 
	PORTA=temp;								// Выводим на portА младшую тетраду команды, сигналы RS, E 
	_delay_us(50);							// Небольшая задержка для стабилизации 
	PORTA = temp&~(1<<E);					// Сигнал записи команды 

	_delay_us(50);						//Пауза для выполнения команды
}
//------------------------------------------------------------------------
//Программа записи данных в ЖКИ
void lcd_dat (unsigned char lcd)
{ 
	unsigned char temp;
	temp=((lcd>>4)|(1<<RS))|(1<<E);		//RS=1 – это данные 
	PORTA=temp;								//Выводим на portА старшую тетраду данных, сигналы RS, E   
	_delay_us(50);							//Небольшая задержка для стабилизации 
	PORTA = temp&~(1<<E);					//Сигнал записи данных 
	_delay_us(50);						// задержка между циклами записи 
	temp=(((lcd<<4)>>4)|(1<<RS))|(1<<E);	//RS=1 – это данные 
	PORTA=temp;								//Выводим на portА младшую тетраду данных, сигналы RS, E   
	_delay_us(50);							//Небольшая задержка для стабилизации 
	PORTA = temp&~(1<<E);	 				//Сигнал записи данных 
	_delay_us(50);						//Пауза для вывода данных 
}
//------------------------------------------------------------------------------
void lcd_show(void)
{
	/*вывод полного пройденного расстояния*/
	lcd_dat (0x20);					// пустая ячейка
	dat = (km_full / 100000) % 10; // сотни тысяч км 
	lcd_dat (dat + 0x30);
	dat = (km_full / 10000) % 10; 	// десятки тысяч км
	lcd_dat (dat + 0x30);		
	dat = (km_full / 1000) % 10; 	// тысячи км
	lcd_dat (dat + 0x30);
	dat = (km_full / 100) % 10; 	// сотни км
	lcd_dat (dat + 0x30);		
	dat = (km_full / 10) % 10; 	// десятки км
	lcd_dat (dat + 0x30);
	dat = km_full % 10; 			// единицы км
	lcd_dat (dat + 0x30);
	lcd_com(0xC0);	//Ставим курсор на начало 2-й строки ЖКИ
	/*вывод расстояния, пройденного за день */
	lcd_dat (0x20);					// пустая ячейка
	dat = (km_temp / 1000) % 10; 	// тысячи км 
	lcd_dat (dat + 0x30);
	dat = (km_temp / 100) % 10;	// сотни км
	lcd_dat (dat + 0x30);		
	dat = (km_temp / 10) % 10; 	// десятки км
	lcd_dat (dat + 0x30);
	dat = km_temp % 10; 			// единицы км
	lcd_dat (dat + 0x30);
	lcd_dat (0x2C); 				// запятая в кодировке ASCII
	dat = m; 						// метры
	lcd_dat(dat + 0x30); 
}
//------------------------------------------------------
void lcd_init (void)
{

	lcd_com(0x28);		// 4-проводный интерфейс, 2 строки, 5х8 символ
	_delay_us(200);

	lcd_com(0x01);		// Очистить DDRAM и установить курсор на 0x00
	_delay_us(200);

	lcd_com(0x06);		// инкремент адреса, сдвиг экрана отключен
	_delay_us(200);

	lcd_com(0x0C);		// Показать изображение, курсор не показывать
	_delay_us(200);
}
//-------------------------------------------------------