|
|
 |
Ответов
(1 - 13)
|
Mar 29 2013, 04:41
|
Местный
  
Группа: Свой
Сообщений: 476
Регистрация: 3-07-07
Из: Санкт-Петербург
Пользователь №: 28 866

|
Цитата(krouli18 @ Mar 28 2013, 17:44)  Нужно реализация программного антидребезгу при сканировании клавиатуры Первое, что Вам нужно - разобраться в склонениях. После этого прислушаться к совету kovigor и попробовать вникнуть в то, что нагуглили. И если будет что-то не понятно - спрашивать на форуме. При этом не надо дублировать темы. Как-то так. =)
--------------------
Ковырял чукча отверткой в ухе, звук в телевизоре и пропал.
|
|
|
|
|
Mar 29 2013, 06:00
|
Местный
  
Группа: Участник
Сообщений: 356
Регистрация: 9-06-07
Пользователь №: 28 315

|
Алгоритм программного антидребезга может выглядеть примерно так. Если состояние кнопки изменилось -> начать отсчет времени антидребезга Иначе  Если состояние кнопки не менялось) Если ведется отсчет времени и время истекло -> зафиксировать текущее состояние кнопки. Остановить таймер. Отсчет времени можно вести по таймеру или по количеству опросов (особенно если они регулярные). Более детальную реализацию думаю сами осилите.
--------------------
Хорошую систему делают из стандартных блоков нестандартно мыслящие инженеры.
|
|
|
|
|
Mar 29 2013, 08:06
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Вот кусок проекта с подавлениями и автоповторами разными. Будут вопросы - пишите. Почему-то не аттачится ничего... CODE // #include "keyboard.h" #include "encoder.h" #include "hardware.h" /* зависящие от процессора функции работы с портами */
enum { KBD_BEEP_LENGTH = NTICKS(25), // длительность озвучивания нажатия
KBD_STABIL_PRESS = NTICKS(30), // was 20 время для регистраци нажатия KBD_STABIL_RELEASE = NTICKS(30), // was 20 время для регистраци отпускания
KBD_MAX_PRESS_DELAY_LONG = NTICKS(600), // время для регистрации удержания кнопки с медленным автоповтором KBD_PRESS_REPEAT_SLOW = NTICKS(400), // время между символами по медленному автоповтору
//KBD_MED_STAGE1 = NTICKS(200), // моменты, на которых вырабатывается очередной символ клавиши с быстрым автоповтором //KBD_MED_STAGE2 = NTICKS(300), //KBD_MED_STAGE3 = NTICKS(400), //KBD_MED_STAGE4 = NTICKS(500), KBD_TIME_SWITCH_QUICK = NTICKS(200), // с этого времени начинается быстрый автоповтор KBD_PRESS_REPEAT_QUICK1 = NTICKS(50), // время между символами по быстрому автоповтору KBD_PRESS_REPEAT_QUICK2 = NTICKS(5) // время между символами по очень быстрому автоповтору };
// сделаны по 8 бит - при 200 герц прерываний 600 мс всего 120 тиков. static uint_fast16_t kbd_press; /* время с момента нажатия */ static uint_fast16_t kbd_release; /* время после отпускания - запрет нового нажатия */
static uint_fast8_t kbd_last; /* последний скан-код (возврат при отпускании кнопки) */ static uint_fast8_t kbd_slowcount; /* количество сгенерированных символов с медленным автоповтором */
static uint_fast8_t kbd_beep; /* время с момента нажатия */
/* получение скан-кода клавиши или 0 в случае отсутствия. * если клавиша удержана, возвращается скан-код с добавленным битом 0x80 * ОТЛАЖИВАЕТСЯ */ static uint_fast8_t kbd_scan_local(uint_fast8_t * key) { const uint_fast8_t chinp = hardware_ged_pressed_key(); const uint_fast8_t notstab = (kbd_press < (KBD_STABIL_PRESS + 1));
if (chinp != KEYBOARD_NOKEY) { if (/*kbd_release != 0 && */ ! notstab && (kbd_last != chinp)) // клавиша сменилась в состоянии стабильного нажатия { // самое первое нажатие kbd_last = chinp; kbd_press = 1; kbd_release = 0; kbd_slowcount = 0; //dbg_putchar('t'); return 0; } else if (kbd_release != 0 && ! notstab) { // Уже было застабилизировавшееся значение - не меняем ничего. // kbd_last уже содержит правильное значение // Нажатие должно исчезнуть когда-то наконец. //dbg_putchar('k'); } else if (kbd_press == 0) { // самое первое нажатие kbd_last = chinp; kbd_press = 1; kbd_release = 0; kbd_slowcount = 0; //dbg_putchar('l'); return 0; } else if (notstab && (kbd_last != chinp)) // Ожидание стабилизации кода клавиши { kbd_last = chinp; kbd_press = 1; kbd_release = 0; kbd_slowcount = 0; //dbg_putchar('m'); return 0; }
kbd_release = KBD_STABIL_RELEASE; const uint_fast8_t flags = qmdefs [kbd_last].flags; /* сравнение кодов клавиш, для которых допустим медленный автоповтор при длительном удержании */ if ((flags & KIF_SLOW) != 0) //(is_slow_repeat(kbd_last)) { // клавиша может работать с медленным автоповтором switch (++ kbd_press) { case KBD_MAX_PRESS_DELAY_LONG + KBD_PRESS_REPEAT_SLOW: kbd_press = KBD_MAX_PRESS_DELAY_LONG; // позволяем ещё раз сюда попасть.
case KBD_MAX_PRESS_DELAY_LONG: * key = qmdefs [kbd_last].code; kbd_release = 0; return 1; } return 0; } /* сравнение кодов клавиш, для которых допустим быстрый автоповтор при длительном удержании */ else if ((flags & KIF_FAST) != 0) //(is_fast_repeat(kbd_last)) { #if KBD_ENCODER // клавиша может работать с быстрым автоповтором // Перестройка клавишами вместо валкодера switch (++ kbd_press) { case KBD_TIME_SWITCH_QUICK: if (kbd_slowcount < 20) { ++ kbd_slowcount; kbd_press = KBD_TIME_SWITCH_QUICK - KBD_PRESS_REPEAT_QUICK1; } else kbd_press = KBD_TIME_SWITCH_QUICK - KBD_PRESS_REPEAT_QUICK2; // формирование символа в автоповторе encoder_kbdctl(qmdefs [kbd_last].code, 1); //dbg_putchar('R'); //dbg_putchar('0' + kbd_last); break; default: //dbg_putchar('U'); break; } return 0; #endif } else { // клавиша может работать с длинным нажатием if (kbd_press == KBD_MAX_PRESS_DELAY_LONG) return 0; // lond_press symbol already returned if (kbd_press < KBD_MAX_PRESS_DELAY_LONG) { if (++ kbd_press == KBD_MAX_PRESS_DELAY_LONG) { * key = qmdefs [kbd_last].holded; // lond_press symbol // return 1; } } } return 0;
} else if (kbd_release != 0) // Нет нажатой клавишии - было нажатие { if (notstab) { kbd_press = 0; // слишком короткие нажатия игнорируем kbd_release = 0; //dbg_putchar('J'); return 0; } //dbg_putchar('r'); // keyboard keys released, time is not expire. if (-- kbd_release == 0) { // time is expire if ((qmdefs [kbd_last].flags & KIF_FAST) != 0) { #if KBD_ENCODER // Перестройка клавишами вместо валкодера //if (kbd_press < KBD_MED_STAGE1) if (kbd_slowcount == 0) { encoder_kbdctl(qmdefs [kbd_last].code, 0); //dbg_putchar('Q'); //dbg_putchar('0' + kbd_last); } //else // dbg_putchar('F');
kbd_press = 0; kbd_slowcount = 0; return 0; // уже было срабатывание по быстрому автоповтору #endif } else if (kbd_press < KBD_MAX_PRESS_DELAY_LONG) { * key = qmdefs [kbd_last].code; kbd_press = 0; kbd_slowcount = 0;
return 1; // срабатывание по кратковременному нажатию на клавишу. } else { kbd_press = 0; kbd_slowcount = 0; return 0; // уже было срабатывание по автоповтору или по длинному нажатию. } } return 0;
} else // нет нажатой клавиши и небыло нажатичя перед этим return 0; }
static volatile uint_fast8_t kbd_scancode = KBD_CODE_MAX; static volatile uint_fast8_t kbd_repeat; static volatile uint_fast8_t kbd_ready;
// вызывается с частотой TICKS_FREQUENCY герц // после завершения полного цикла ADC по всем входам. void kbd_spool(void) { uint_fast8_t code; if (kbd_scan_local(& code) != 0) { kbd_beep = KBD_BEEP_LENGTH; board_keybeep_enable(1); /* начать формирование звукового сигнала */ //if (code != KBD_CODE_BW_AGC) //{ // dbg_puts_impl("UPS!\n"); // for (;;) // ; //} if (kbd_scancode == code) ++ kbd_repeat; else { kbd_scancode = code; kbd_repeat = 1; } } else { if (kbd_beep != 0 && -- kbd_beep == 0) board_keybeep_enable(0); } kbd_ready = 1; }
uint_fast8_t kbd_is_tready(void) { #if CPUSTYLE_ATXMEGA #warning TODO: remove this return 1; #endif
uint_fast8_t f;
//disableIRQ(); f = kbd_ready; //enableIRQ(); return f; }
/* получение скан-кода клавиши и количества её повторов. */ uint_fast8_t kbd_scan(uint_fast8_t * key) { disableIRQ(); uint_fast8_t repeat; if ((repeat = kbd_repeat) != 0) { * key = kbd_scancode; kbd_repeat = 0; kbd_scancode = KBD_CODE_MAX; } enableIRQ(); return repeat; }
/* Проверка, нажата ли клавиша c указанным флагом // KIF_ERASE или KIF_EXTMENU */ uint_fast8_t kbd_get_ishold(uint_fast8_t flag) { uint_fast8_t r; disableIRQ(); r = (kbd_press != 0) && (qmdefs [kbd_last].flags & flag); enableIRQ(); return r; }
/* инициализация переменных работы с клавиатурой */ void kbd_initialize(void) { // todo: все присвоения нулями могут быть убраны.
////kbd_press = 0; ////kbd_release = 0; ////kbd_repeat = 0; //kbd_scancode = KBD_CODE_MAX;
// таймер. Просто тут живёт. ////timer_0p1_s_repeat = 0; }
|
|
|
|
|
Mar 29 2013, 09:10
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Имею три массива для обработки панели управления: массив нового состояния кнопок New, массив предыдущего состояния кнопок Old, массив обработанных кнопок Fix. Опрашиваю кнопки с разумным интервалом, 64 раза в секунду, сохраняю в массиве New. Сравниваю со старым Old, полученным в прошлом опросе, и обработанными кнопками Fix. Если есть кнопка, состояние которой в New и Old одинаковое (устойчивое, не дребезжит), и отличается от Fix (еще не обработана), то выполняю обработку этой кнопки (посылаю по интерфейсу, в моем случае). После этого меняю состояние в массиве Fix. Дальше можно искать следующую кнопку с такими же свойствами. Ну, и в конце цикла не забываю перенести массив New в Old. Таким образом, реагирую на любое нажатие или отпускание кнопок в любой комбинации. Для обнаружения изменившегося состояния кнопки мне нужно время (1/64 * 2 = 31 ms). Более частое дребезжание будет игнорировано. P.S. Автоповтор, если нужно, делаю в программе, куда посылаю состояние кнопок. Пока кнопка нажата, можно с неким интервалом (первый больше) реагировать на кнопку. Когда придет информация, что кнопка отпущена, прекращаю.
|
|
|
|
|
Apr 1 2013, 09:52
|

Участник

Группа: Участник
Сообщений: 48
Регистрация: 7-09-07
Из: Наб.Челны
Пользователь №: 30 364

|
Цитата(ARV @ Mar 29 2013, 11:08)  недопустимо доводим до абсурда: опрашиваем кнопку 1 раз в час - ровно в 00 минут и 00 секунд и 00 миллисекунд. а я нажимаю кнопку ровно за 3 миллисекунды до этого момента - в итоге опрос попадает как раз на время, пока кнопка дребезжит, и что при этом "опросится" - не известно Вполне допустимо. Попали на дребезг сейчас - значит получим правильный результат в следующий опрос. Главное чтобы интервал опроса был заведомо больше времени дребезга и меньше времени реакции человека. 50-70 мсек - оптимум, при 100 уже чувствуется задержка...
|
|
|
|
|
Apr 6 2013, 03:20
|

Профессионал
    
Группа: Участник
Сообщений: 1 179
Регистрация: 15-09-04
Из: 141070 г. Королев МО, улица Горького 39-121
Пользователь №: 661

|
Цитата(ARV @ Apr 2 2013, 07:59)  элементарное Дай и я сюда плюну, обнаружители обычно просто строятся, в регистр вдвигается 0,1 (не нажата/нажата), далее есть критерий обнаружения начала события (нажатия), продолжения (удерживания) и конца события (отпускания клавиши), обычно это столько единичек из столькото отчетов, например для начала нажатия можно взять 2 единички из 3х отсчетов, аналогично для удержания и отжатия.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|