//------------------------------------------------------------------------------------
// Пример использования библиотеки опроса кнопок button_lib
//
// Короткое нажатие - инвертирует соответствующий вывод
// Длинное нажатие - инвертирует все выводы
//
//
//------------------------------------------------------------------------------------
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>


//------------------------------------------------------------------------------------
//настройки параметров библиотеки 
#define BTN_LOCK_TIME   20						/* время обработки дребезга в милисекундах (10-100) */ 
#define BTN_LONG_TIME   1000					/* время фиксации длинного нажатия в милисекундах (1000 - 2500) */ 

//настройка портов и линий кнопок
#define BTN_PORT       PORTB					/* порт кнопок */ 
#define BTN_PIN        PINB 
	#define BTN_LINE1   	(1<<0)				/* линии кнопок */           
	#define BTN_LINE2   	(1<<1)                         
	#define BTN_LINE3   	(1<<2)                         
	#define BTN_LINE4   	(1<<3)                         


//----------------------------------------------------------------------------------------------------------------------- 
//глобальные переменные
volatile uint8_t BtnFlags;						//регистр флагов нажатых кнопок 
	#define BTN_SHRT1   	(1<<0)				/* флаги короткого нажатия кнопок */ 
	#define BTN_SHRT2   	(1<<1)  
	#define BTN_SHRT3   	(1<<2) 
	#define BTN_SHRT4   	(1<<3) 
	#define BTN_LONG1   	(1<<4)				/* флаги длинного нажатия кнопок */ 
	#define BTN_LONG2   	(1<<5) 
	#define BTN_LONG3   	(1<<6) 
	#define BTN_LONG4   	(1<<7) 


//объявления функций
void BtnInit (void);	//инициализация библиотеки 
uint8_t BtnGet (void);	//функция чтения маски нажатой кнопки 

 
//------------------------------------------------------------------------------------
int main(void)
{
	//настройка таймера на прерывание с частотой 100Гц
	OCR2 = F_CPU / 1024 / 100;					//формула для получения частоты 100Гц	
	TIMSK |= (1<<OCIE2);						//прерывание при совпадении
	TCCR2 = (1<<CS22)| (1<<CS21)| (1<<CS20)|	//предделитель на 1024
			(1<<WGM21)| (0<<WGM20);				//режим CTC (сброс при совпадении)


	//настройка библиотек
	BtnInit();
	DDRC = 255;									//выводы светиков


	//главный цикл
	sei ();										//разрешаем глобально прерывания
	while(1){

		uint8_t button = BtnGet();				//читаем значение кнопок

		if (button == BTN_SHRT1)				//если нажата кн1
			PORTC ^= 0x01;

		if (button == BTN_SHRT2)				//если нажата кн2
			PORTC ^= 0x02;

		if (button == BTN_SHRT3)				//если нажата кн3
			PORTC ^= 0x04;

		if (button == BTN_SHRT4)				//если нажата кн4
			PORTC ^= 0x08;

		if ((button == BTN_LONG1) ||			//если есть длительное удержание любой кнопки
			(button == BTN_LONG2) ||
			(button == BTN_LONG3) ||
			(button == BTN_LONG4))
			PORTC ^= 0xff;
	}
} 


//----------------------------------------------------------------------------------------------------------------------- 
//функция инициализации портов (вызвать перед использованием библиотеки) 
void BtnInit (void)                              
{    
    BTN_PORT |= (BTN_LINE1| BTN_LINE2| BTN_LINE3| BTN_LINE4);//подтяжка кнопок 
} 
  
  
//----------------------------------------------------------------------------------------------------------------------- 
//функция чтения маски нажатых кнопок  
//возвращает маску нажатых кнопок (биты 0-3 - коротк нажат, биты 4-7 - длинн нажат) 
uint8_t BtnGet (void)                               
{    
	cli ();
    uint8_t temp = BtnFlags; 
    BtnFlags = 0; 
	sei ();
    return temp; 
} 
  
  
//------------------------------------------------------------------------------------
//опрос состояния кнопок с частотой 100Гц
ISR (TIMER2_COMP_vect)							//interrupt 100hz
{
	static uint8_t BtnLockBit;                  //защелка (защита от дребезга) 
	static uint8_t BtnLockCoun;                 //счетчик защелки (защита от дребезга) 
	static uint8_t BtnLongCoun;                 //счетчик длинного нажатия 
	static uint8_t BtnMascLast;                 //запомнить маску нажатой кнопки для анализа после отжатия кнопки 

	uint8_t BtnMask = 0;  
	if (~BTN_PIN & BTN_LINE1) 	BtnMask = BTN_SHRT1;//формирование маски нажатых кнопок 
	if (~BTN_PIN & BTN_LINE2) 	BtnMask = BTN_SHRT2;
	if (~BTN_PIN & BTN_LINE3) 	BtnMask = BTN_SHRT3;
	if (~BTN_PIN & BTN_LINE4) 	BtnMask = BTN_SHRT4;

	//основной алгоритм обработки событий кнопки 
	if (BtnMask){                               //клавиша нажата 
		BtnMascLast = BtnMask;                  //запоминаем для использования после отпускания кнопки 

		if (BtnLockCoun < (BTN_LOCK_TIME/10)){ 
			BtnLockCoun++;                      //обработка дребезга 
			return; 
		} 

		BtnLockBit=1;                           //нажатие зафиксировано      
		if (BtnLongCoun >= (BTN_LONG_TIME/10))                                
			return; 
		
		if (++BtnLongCoun >= (BTN_LONG_TIME/10)) 
			BtnFlags |= (BtnMask << 4);         //установка бита длинного нажатия (старшие 4 бита флагов ButtonByte) 
	} 

	else{                                       //клавиша отжата             
		if (BtnLockCoun){                       //обработка дребезга 
			BtnLockCoun --; 
			return; 
		} 

		if (! BtnLockBit)                     	//отжатие зафиксировано 
			return; 

		BtnLockBit =0; 
		if (BtnLongCoun < (BTN_LONG_TIME/10)) 
			BtnFlags |= BtnMascLast;            //установка бита короткого нажатия (младшие 4 бита флагов ButtonByte) 
		
		BtnLongCoun = 0; 
	} 
}	


//------------------------------------------------------------------------------------
