Перейти к содержанию
    

Обработка прерывания кнопки

Может я засиделся сегодня у компа, но что-то меня заклинило: как правильно писать обработчик прерывания по нажатию кнопки? Суть вопроса сводится к расположению задержки (~30мс) для "устранения " дребезга контактов кнопки. Ведь существует неписанное правило о том, что обработчики прерывания должны быть как можно короче по времени исполнения, а введение "антидребезговой" задержки этому как-то не способствует. Или это неизбежное зло и таким обработчикам просто следует назначать наименьший приоритет? Если тема боян - ткните носом. Не нашел.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кто запрещает что-то другое делать, пока задержка. Почему обязательно всё это время висеть в прерывании.

Кто разрешил делать предположения о принципиальной возможности других подходов к.

 

Не нашел.
Длительность импульсов в "дребезге контактов" например заголовок, простой и логичный.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

 

 

// в .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 мсек

Изменено пользователем alexeyv

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может я засиделся сегодня у компа, но что-то меня заклинило: как правильно писать обработчик прерывания по нажатию кнопки? Суть вопроса сводится к расположению задержки (~30мс) для "устранения " дребезга контактов кнопки. Ведь существует неписанное правило о том, что обработчики прерывания должны быть как можно короче по времени исполнения, а введение "антидребезговой" задержки этому как-то не способствует. Или это неизбежное зло и таким обработчикам просто следует назначать наименьший приоритет? Если тема боян - ткните носом. Не нашел.

А задержка в вашем представлении это обязательно delay_ms()? Мне например за свою жизнь никогда подобные задержки не требовались. Запусти таймер на 30 мс и сравни значение кнопки до и после.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сама идея прерываний от кнопки не очень хороша. Из-за дребезга придётся или отрабатывать десятки прерываний на каждое нажатие или мутить с их разрешением/запрещением. Обычно проще оказывается просто регулярно опрашивать кнопки в низкоприоритетном процессе, благо мгновенной реакции не требуется, задержку до 100 .. 150 мс человек не замечает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо всем за ответы. Прокомментируйте, пожалуйста, следующий вариант обработки нажатия кнопки: по нажатию на кнопку устанавливаем в обработчике флаг соотв. кнопки и запускаем таймер (и выходим из прерывания), по прерыванию от которого проверяем состояние кнопки (чей флаг предварительно был установлен) и устанавливаем флаг нажатия кнопок, который (в паре с флагом соотв. кнопки) обрабатываем в основной программе.

 

P.S. Учитывая пост Sserge добавляем запрещение соотв. прерывания в первом обработчике и разрешение во втором.

Изменено пользователем Nikitoc

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо всем за ответы. Прокомментируйте, пожалуйста, следующий вариант обработки нажатия кнопки: по нажатию на кнопку устанавливаем в обработчике флаг соотв. кнопки и запускаем таймер (и выходим из прерывания), по прерыванию от которого проверяем состояние кнопки (чей флаг предварительно был установлен) и устанавливаем флаг нажатия кнопок, который (в паре с флагом соотв. кнопки) обрабатываем в основной программе.

 

P.S. Учитывая пост Sserge добавляем запрещение соотв. прерывания в первом обработчике и разрешение во втором.

 

Возможно, заработает. Возможно, будет даже немного лучше чем вообще без антидребезга. Возможно...

 

По хорошему алгоритм в следующем:

Опрос кнопки в прерывании от таймера, раз в 0.5-5мс

Счетчик - от 0 до N, где N задает время антидребезга (порядка 10-200мс)

Буфер - состояние кнопки после антидребезга.

 

1. Если кнопка нажата и счетчик меньше максимума - прибавляем счетчик

2. Если кнопка отжата и счетчик больше нуля - убавляем счетчик

3. Если счетчик в максимуме, устанавливаем буфер в '1'

4. Если счетчик в нуле, устанавливаем буфер в '0'

5. По переходу буфера '0' -> '1' или '1' -> '0' делаем вывод о нажатии/отжатии кнопки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я вообще не вижу смысла вешать кнопку на вход прерывания, кроме одного случая - когда это используется для вывода процессора из спячки.

Равно как и использование отдельного таймера под обработку.

У меня сделано так:

В прерывании от системного таймера (Т=1мс) сканируется порт клавиатуры, и если обнаружено изменение состояния (NextState != PrevState), выставляется соответствующий флаг.

По этому флагу в основном цикле запускается обработчик, который отмеряет задержки, анализирует длительность нажатия (single/fixed) и запускает необходимые функции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Запускаешь АЦП и никаких тебе дребезгов и задержек очена подходит к случаю описанному alexeyv

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Запускаешь АЦП и никаких тебе дребезгов и задержек очена подходит к случаю описанному alexeyv

Что-то я не совсем понял каким боком тут АЦП оказалось и как оно поможет с кнопкой.

Изменено пользователем whiteTigr

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то я не совсем понял каким боком тут АЦП оказалось и как оно поможет с кнопкой.

А я не понял , что не понятного?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Зачем целый АЦП выделять под кнопку?

А почему под кнопку? Я написал для кого проекта это удобно использовать.

Запускаешь АЦП и никаких тебе дребезгов и задержек очена подходит к случаю описанному alexeyv

И к тому же один канал на 8 кнопок. Если уж очень постараться то и 12 кнопок влезут. Учитывая , что каналы (8 шт.) можно переключать во время работы и никто не запрещал менять настройки АЦП , во время работы, то проще выделить просто один канал под кнопки , а с отальными I/O делать , что душе угодно. В том числе и просто как входы -выходы

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ни в одном проекте не использовал прерывания для кнопок, опрос в прерывании таймера самое оно как по мне, там же и дребезг и фильтрация от помех.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

прерывание требуется для обеспечения немедленной реакции на внешнее событие, причем "немедленно" - по меркам микроконтроллера, а не человека. назовите хотя бы какую-то ситуацию, где действительно необходимо реагировать на кнопку за 5-10 микросекунд. кстати - даже если придумаете, это будет бесполезно, т.к. подавление дребезга все равно заставит затянуть процесс до 10-15 миллисекунд, т.е. примерно в 1000 раз.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...