реклама на сайте
подробности

 
 
> Подавление дребезга кнопок 20 мс (8 выводов – кнопок)
Alex ma
сообщение Mar 18 2007, 15:26
Сообщение #1


Частый гость
**

Группа: Новичок
Сообщений: 81
Регистрация: 9-08-06
Пользователь №: 19 445



Лог. 0 – кнопка нажата.
1 Считать и запомнить.
2 ждать 20мс
3 Считать и OR с ранее запомненным значением
4 результат, где нажата кнопка 0.

Есть наверное лучше способ подавления дребезга кнопок.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 10)
el34
сообщение Mar 18 2007, 15:40
Сообщение #2


инженер
****

Группа: Свой
Сообщений: 717
Регистрация: 4-03-05
Пользователь №: 3 064



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


--------------------
........поужинали вяленой рыбой, кот лежал рядом, молчали.......
Go to the top of the page
 
+Quote Post
rezident
сообщение Mar 18 2007, 19:53
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Ну вначале нужна инициализация портов/переменных и etc. smile.gif
Для работы процедуры нужны как минимум две статических переменных. а) Предыдущее состояние кнопок и б) предыдущее устойчивое состояние кнопок.
1. С выбранным периодом (у вас это 20мс) , который должен быть не меньше времени дребезга контактов считываем/сканируем текущее состояние кнопок. Для удобства представляем состояния кнопок так, чтобы нажатая кнопка давала лог.1 , а не нажатая лог.0. При необходимости инвертируем состояния во время сканирования.
2. XORим текущее состояние с предыдущим состоянием? Если нуль, то состояния совпадают (устойчивое состояние) -> начинаем анализ. Если не нуль (состояния не совпадают, неустойчивое), то записываем текущее состояние как предыдущее и на п5 (выход из процедуры).
3. Первым делом проверяем нажата ли хоть одна кнопка (опять сравнение текущего с нулем). Если нуль (ни одна не нажата), то и обрабатывать нечего переход на п4.
Если иначе, то XORим текущее состояние с предыдущим устойчивым состоянием. Если не нуль (т.е. в устойчивом состоянии произошли изменения), то побитно в цикле обрабатываем состояние кнопок и складываем коды нажатых (при необходимости и отжатых тоже) в буфер клавиатуры. Обработку делаем как циклический сдвиг битовой маски и накладывание ее на текущее состояние проXORенное с предыдущим устойчивым состоянием. Этим мы устраняем повторную обработку уже нажатых и обработанных в предыдущей процедуре клавиш. При таком способе можно генерировать специальные коды при нажатии и удержании комбинации клавиш и отдельно фиксировать нажатие и отпускание нескольких клавиш.
4. Записываем текущее состояние как предыдущее устойчивое состояние.
5. Выход из процедуры.
Вот такой примерно алгоритм я когда-то реализовывал. Кроме собственно обработки нажатия клавиш у меня был реализован автоповтор последней нажатой клавиши.
Go to the top of the page
 
+Quote Post
Alex ma
сообщение Mar 18 2007, 20:01
Сообщение #4


Частый гость
**

Группа: Новичок
Сообщений: 81
Регистрация: 9-08-06
Пользователь №: 19 445



Спасибо, что разяснили
Go to the top of the page
 
+Quote Post
el34
сообщение Mar 18 2007, 20:22
Сообщение #5


инженер
****

Группа: Свой
Сообщений: 717
Регистрация: 4-03-05
Пользователь №: 3 064



rezident>3. Первым делом проверяем нажата ли хоть одна кнопка (опять сравнение текущего с нулем).
rezident>Если нуль (ни одна не нажата), то и обрабатывать нечего переход на п4.

ну и как у Вас после этого автоповтор остановливался???

rezident>то побитно в цикле обрабатываем состояние кнопок

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


--------------------
........поужинали вяленой рыбой, кот лежал рядом, молчали.......
Go to the top of the page
 
+Quote Post
rezident
сообщение Mar 18 2007, 20:46
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(el34 @ Mar 18 2007, 22:22) *
ну и как у Вас после этого автоповтор остановливался???

А у меня в алгоритме описан автоповтор? wink.gif

Цитата(el34 @ Mar 18 2007, 22:22) *
да не надо побитно в цикле....достаточно результат предыдущего XORа(когда засекли изменение) проANDить с прямым и инверсным значением последнего стабильного состояния и будет в результате в одтном регистре еденицы только там , где поизошло нажатие в другом - отпускание

Ну и что это дает? Только индикацию наличия/отсутствия. А если нажато/отпущенно несколько клавиш одновременно, то все равно придется определять их позиционный код. Конечно если только у вас нет заранее определенного запрета на одновременное нажатие (обработку) нескольких клавиш.
Go to the top of the page
 
+Quote Post
el34
сообщение Mar 18 2007, 21:06
Сообщение #7


инженер
****

Группа: Свой
Сообщений: 717
Регистрация: 4-03-05
Пользователь №: 3 064



rezident>А у меня в алгоритме описан автоповтор?

rezident>Вот такой примерно алгоритм я когда-то реализовывал. Кроме собственно обработки нажатия клавиш у меня был реализован автоповтор последней нажатой клавиши.

в таком примерно алогритме он не работает....


--------------------
........поужинали вяленой рыбой, кот лежал рядом, молчали.......
Go to the top of the page
 
+Quote Post
rezident
сообщение Mar 18 2007, 21:26
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(el34 @ Mar 18 2007, 23:06) *
в таком примерно алогритме он не работает....

Да работает автоповтор, работает. Я же указал, что в примерно таком, а не конкретно в этом алгоритме. Могу по сырцам более подробно (точно) алгоритм автоповтора восстановить, но это уже завтра будет.
Go to the top of the page
 
+Quote Post
el34
сообщение Mar 18 2007, 21:32
Сообщение #9


инженер
****

Группа: Свой
Сообщений: 717
Регистрация: 4-03-05
Пользователь №: 3 064



rezident>Да работает автоповтор, работает. Я же указал, что в примерно таком

У Вас в примерно таком работает , а у задавшего вопрос в таком работать не будет....

я не с Вами спорю.... я автору вопроса помогаю.....


--------------------
........поужинали вяленой рыбой, кот лежал рядом, молчали.......
Go to the top of the page
 
+Quote Post
xemul
сообщение Mar 18 2007, 23:22
Сообщение #10



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Код
// Vertical Counters
// идея Scott Dattalo, http://www.dattalo.com
// добавлен PInChg для упрощения обработки изменений в PIn

#define IMask (1<<IBtn0) | (1<<IBtn1) | ...

// независимое устранение дребезга по 8 входам:
// состояние входа считается установившимся при получении
// 4 последовательных одинаковых выборок
void vcountr2(void)
{
// глобальные переменные:
// PIn    - отфильтрованные входы
// PInChg - изменения по входам

   static uint8_t CntA=0, CntB=0; // vertical counters
   uint8_t t1, t2;

   CntA ^= CntB;
   CntB = ~CntB;
   t1 = InPort & IMask;
   PInChg = t1 ^ PIn.i;
   CntA &= PInChg;
   CntB &= PInChg;
   t2 = CntA | CntB;
   t1 &= ~t2;
   PIn &= t2;
   PIn |= t1;
   PInChg &= ~t2;
// если убрать CntB, получим вариант rezident'a - фильтрация по двум выборкам
// если добавить CntC, получится фильтрация по 8 выборкам
// на ассемблере получается ну очень коротенько:)
}

// --------------------
// пример использования
// --------------------

uint8_t PIn, PInChg;
// хотя я обычно их обзываю
// union
// {
//    uint8_t i;
//    struct
//    {
//       uint8_t Btn0 :1;
//       uint8_t Btn1 :1;
//...
//    } b;
// } PIn, PInChg;

void main (void)
{
// инициализация
   PIn = InPort & IMask;  // PIn.i = InPort & IMask;
   PInChg = 0;            // PInChg.i = 0;
...
// рабочий цикл
   for(;;)
   {
// период опроса входов - по вкусу
// я для устранения дребезга кнопок устраиваю опрос с периодом 8-10 мс
// т.е. установившееся состояние входа получаем не менее чем через 32-40 мс
      if(Flags.b._8ms)
      {
         Flags.b._8ms = 0;
         vcountr2();
         ...   // другие 8-мс задачи
      }
...
// обработка PIn, PinChg
      if(PInChg & (1<<IBtn0)) // if(PInChg.b.Btn0)
      {
         if(PIn & (1<<IBtn0)) // if(PIn.b.Btn0)
         {
            // в условиях задачи "Лог. 0 – кнопка нажата"
            // сюда попадем при отпускании кнопки на входе Btn0
         }
         else
         {
            // а сюда - при нажатии
         }
      }
      if(PInChg & (1<<IBtn1)) // аналогично
      {
         if(PIn & (1<<IBtn1))
         {
         }
         else
         {
         }
      }
...
   } // end for(;;)
} // end main()
Go to the top of the page
 
+Quote Post
exSSerge
сообщение Mar 19 2007, 23:07
Сообщение #11


Частый гость
**

Группа: Новичок
Сообщений: 136
Регистрация: 18-08-06
Из: Novosibirsk
Пользователь №: 19 655



Подавление дребезга кнопок - это в любом случае та или иная разновидность ФНЧ. Для небольшого числа кнопок можно при периодическом опросе просто задвигать в байтовую переменную текущее состояние входа, таким образом накапливая последние 8 отсчётов. Если они все равны 1 - значит кнопка нажата, если все 0 - отпущена, если другое значение - дребезг ещё продолжается, этакий вырожденный случай фильтра скользящего среднего на 8 отсчётов.
Пример, простой терминал о четырёх кнопках и LCD-индикаторе (на AVR):
Код
/* кнопки, 4 штуки, подключены к выводам порта D и земле */
#define iBTN1         PIND_Bit2
#define iBTN2         PIND_Bit3
#define iBTN3         PIND_Bit4
#define iBTN4         PIND_Bit5

#define ON   (0xff)
#define OFF  (0)

volatile char   btn1 = 0;
volatile char   btn2 = 0;
volatile char   btn3 = 0;
volatile char   btn4 = 0;
enum   {not_pressed, pressed};
char   keys_state = not_pressed;

#pragma vector = TIMER0_OVF_vect
__interrupt void TIMER0_OVF(void)
{
   btn1 = (btn1 << 1) | ! iBTN1; // кнопки подключены к земле,
   btn2 = (btn2 << 1) | ! iBTN2; // сразу инвертируем состояние входов iBTNx
   btn3 = (btn3 << 1) | ! iBTN3;
   btn4 = (btn4 << 1) | ! iBTN4;
}

__C_task void main(void)
{
/* ..инициализация периферии пропущена...*/
   while(1)
   {
      int ch;
      if( (ch = getc()) != EOF )
         LCD_putchar(ch);

      if( keys_state == pressed )
      {  
         // нажатие кнопки уже отработано, ничего не делаем пока не отпустят
         if( (btn1 == OFF) && (btn2 == OFF) && (btn3 == OFF) && (btn4 == OFF) )
            keys_state = not_pressed;
      }
      else
      {
        if( btn1 == ON )
           { putc('\r');   keys_state = pressed; }
        else if( btn2 == ON )
           { putc('[');     keys_state = pressed; }
        else if( btn3 == ON )
           { putc('-');     keys_state = pressed; }
        else if( btn4 == ON )
           { putc('+');    keys_state = pressed; }
      }
   } // while(1)
}
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 06:32
Рейтинг@Mail.ru


Страница сгенерированна за 0.01449 секунд с 7
ELECTRONIX ©2004-2016