/**

http://electronix.ru/forum/index.php?showtopic=93624&view=findpost&p=964475

Примерно лет шесть делаю так:

*/

// в .h-файле:
  // кол-во времени до события "длинное нажатие"
  #define TIMER_COUNT 250
  // кол-во кнопок
  #define KEY_COUNT 4
  // время автоинкремента
  #define   TIMER_SCROLL  20

  // состояние кнопки
  enum {KN_DOWN =0, KN_UP =1,  KN_PRESS=2 };
  // тип функции кнопки
  typedef byte(KeyFunc)(void);

  // структура хранящая набор переменных для каждой кнопки
  typedef struct key_struct__
   {
    byte state; // состояние кнопки
    byte mask;  // маска клавиши
    byte pins;  // буфер значений с клавиши
    byte count; // счетчик нажатий
    KeyFunc * exec_down;
    KeyFunc * exec_up;
    KeyFunc * exec_pres;
   }key_struct;

// в .c-файле:
//*****************************************************************************
// Драйвер кнопок
//    назначение кнопок
//    1- MiNUS 2-PLUS  3- Select 4- Enter
//*****************************************************************************

//=============================================================================
// состояния кнопок
static key_struct key_mass [KEY_COUNT] = {
 //state  mask            pins count exec_down exec_up       exec_pres
  {KN_UP, PIN_KEY_MINUS,  0xFF,0x00, kn_empty, kn_minus_up  ,kn_minus_up    }
 ,{KN_UP, PIN_KEY_PLUS,   0xFF,0x00, kn_empty, kn_plus_up   ,kn_plus_up     }
 ,{KN_UP, PIN_KEY_SELECT, 0xFF,0x00, kn_empty, kn_select_up ,kn_empty       }
 ,{KN_UP, PIN_KEY_ENTER,  0xFF,0x00, kn_empty, kn_empty     ,kn_enter_press }
 };
//=============================================================================

ISR(TIMER1_COMPA_vect)
 {
  #define Sta     key->state
  #define Pin     key->pins
  #define Cnt     key->count
  #define Msk     key->mask
  #define Down    key->exec_down
  #define Up      key->exec_up
  #define Pres    key->exec_pres

  key_struct * key = key_mass;
  for(byte i=0; i< KEY_COUNT ; i++)
   {
    Pin *=2;        //  * or <<
    if(KEY_PIN & Msk) Pin |= 0x01;

    if(Sta == KN_UP)
     {
      if(!Pin)      // начало счета - нажатие
       {
        Down();
        Sta = KN_DOWN;
        Cnt = 0x00;
       }
     }
    else       // down or press
     {
      if(Pin==0xFF)  // отпустили
       {
        if(Sta == KN_DOWN) Up();
        Sta = KN_UP;
       }
      else// удерживаем
       {
        if(Cnt <= TIMER_COUNT) ++Cnt;
        if(Cnt == TIMER_COUNT) // длительное удержание - попадаем один раз!!
         {
          if(Pres()) Cnt = TIMER_COUNT - TIMER_SCROLL;
            else     Sta = KN_PRESS;
         }
       }
     }
key++;
   }
 }

/**
Таймер в CTC-режиме на порядка 5....15 мсек
*/
