Обработка нажатия кнопки в прерывании. Часть 2

Расследуя поведение контактов кнопки и предотвращая пагубные последствия их поведения, в предыдущей статье было отмечено, что для обнаружения срабатывания неплохо использовать прерывания от внешнего источника. Так же было отмечено, что это «не лучший способ» работы с кнопкой…

Рассмотрим иной способ работы с кнопкой, на сей раз — в другом виде прерывания — прерывании от таймера.Принцип обработки прост: запускаем в обработке прерывания от таймера процедурку сохранения состояния входа контроллера, к которому подключен контакт кнопки. Если выбрать период прерываний разумным: 15-50 мс, то можно считать, что влияние дребезга контактов кнопки на считанное состояние будет отсутствовать. В самом деле: даже если считано ложное состояние, то оно совпадает с предыдущим, а в следующем периоде будет считано уже верное состояние… (сумбурно, но понять, думаю, можно).

#define pKey 4    //вывод для подключения кнопки

int sKey = 0;     //состояние кнопки (0-нажата)
int sKeyOld = 0;  //прежнее состояние кнопки
int iCt = 0;      //счетчик нажатий кнопки

//Установка Таймера2.
//Конфигурирует 8-битный Таймер2 ATMega для выработки прерывания
//с дискретом 64 мкс (период переполнения около 16мс)
void SetupTimer2()  {
  //Установки Таймер2: Делитель частоты /1024, режим 0
  //период дискретизации 64 мкс, т.е прер.16384мкс
  TCCR2A = 0; 
  TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20;   //на 1024
  //Подключение прерывания по переполнению Timer2
  TIMSK2 = 1<<TOIE2;
}

//Timer2 указатель вектора прерывания по переполнению
ISR(TIMER2_OVF_vect) {
  sKey = digitalRead(pKey);  //читаем кнопку
}

void setup() {
  Serial.begin(9600);
  pinMode(pKey, INPUT_PULLUP);  //вход кнопки с внутр.резистором
  pinMode(13, OUTPUT);   //к 13 подключен светодиод
  digitalWrite(13, LOW); // выкл светодиод
  SetupTimer2();  //инициализировать прерывания таймера 2
}

void loop() {
  if (sKey != sKeyOld) {  //состояние кнопки изменилось
    if (sKey == 0) {  //переход в состояние нажата
      sKeyOld = sKey; //запоминаем новое состояние
      iCt ++;         //счетчик нажатий увеличим
      Serial.println(iCt);   //выводим на экран
      digitalWrite(13, HIGH); // вкл светодиод
      }
    else {  //переход в состояние "отжата"
      sKeyOld = sKey; //запоминаем новое состояние  
      digitalWrite(13, LOW);  // выкл светодиод
      }
    }
}

В приводимом примере задействован второй таймер на прерывание по переполнению (пример описан в этой статье). При коэффициенте предделения 1024 и частоте кварца 16МГц, получаем прерывания с периодом чуть больше 16мс (таймер «крутится» сам по себе, счетчик мы  не перезагружаем). С этим периодом мы и сохраняем состояние кнопки в переменной sKey.

В основном цикле скетча отлавливается состояние перехода из «не нажато» в «нажато» и наращивается счетчик нажатий iCt. Заодно уж и включаем светодиод синхронно с нажатиями кнопки.

Получается довольно просто и «не затратно». В прерывании можно опросить всю матрицу кнопок (если их много) и определить текущее состояние клавиатуры…

Обработка нажатия кнопки в прерывании. Часть 2: 3 комментария

  1. Так… Получается таймер начинает работать сразу же после функции SetupTimer2() и каждые 16мс считывает новое состояние кнопки? Долго разбирался с настройками таймера, его регистрами, массой обработчиков прерываний. Но зато ардуино комьюнити говорит, что если разберешься с таймерами, то познаешь дзэн)
    Пока через delay() самый легкий способ устранения дребезга. Натыкался еще на аппаратное устранение дребезга, наверное это апогей этой темы)

  2. Программа клавиатурного драйвера реализована как программа обработки прерывания. Основная программа переводит микропроцессор в режим сна. При нажатии на кнопку драйвер клавиатуры пробуждает AVR микроконтроллер, получает скан-код и обновляет глобальные байты. После выполнения функций нажатых кнопок основная программа снова переводит микроконтроллер в режим сна.

  3. Попробуйте убрать из примера строчку 32 в конце обработчика, и тогда, сразу после первого нажатия кнопки, лампочки будут переключаться так, как будто вы постоянно нажимаете на кнопку.

Добавить комментарий

Ваш e-mail не будет опубликован.

Нажимая кнопку "Отправить" Вы даёте свое согласие на обработку введенной персональной информации в соответствии с Федеральным Законом №152-ФЗ от 27.07.2006 "О персональных данных".