Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: программный антидребезг
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Все остальные микроконтроллеры
krouli18
Нужно реализация программного антидребезгу при сканировании клавиатуры
kovigor
Цитата(krouli18 @ Mar 28 2013, 17:44) *
Нужно реализация программного антидребезгу при сканировании клавиатуры

Для какого МК ?
В Google введите нечто вроде: "Микроконтроллер подавление дребезга" и поищите готовый исходник, или напишите сами.
Само по себе подавление дребезга мало кому нужно, обычно оно входит в какой-то проект. Или это студенческий курсовой ?
Lmx2315
..фуу, первый успел пролезть в помошники.

Что конкретно надо???
В гугле смотрели??
?
Lotor
Цитата(krouli18 @ Mar 28 2013, 17:44) *
Нужно реализация программного антидребезгу при сканировании клавиатуры

Первое, что Вам нужно - разобраться в склонениях. После этого прислушаться к совету kovigor и попробовать вникнуть в то, что нагуглили. И если будет что-то не понятно - спрашивать на форуме. При этом не надо дублировать темы. Как-то так. =)
редактор
Алгоритм программного антидребезга может выглядеть примерно так.
Если состояние кнопки изменилось -> начать отсчет времени антидребезга
Иначеsad.gif Если состояние кнопки не менялось)
Если ведется отсчет времени и время истекло -> зафиксировать текущее состояние кнопки. Остановить таймер.

Отсчет времени можно вести по таймеру или по количеству опросов (особенно если они регулярные).
Более детальную реализацию думаю сами осилите.
ARV
обобщенный алгоритм опроса кнопки с подавлением дребезга контактов:
1. считать состояние кнопки, запомнить его

2. подождать 10-15 миллисекунд


3. считать снова состояние кнопки

4. сравнить это состояние с тем, что запомнено на 1 шаге

5. если состояния РАЗНЫЕ - закончить алгоритм, считая, что кнопка не нажата (либо считая, что состояние кнопки то же самое, что было при прошлом опросе кнопки)

6. если состояния одинаковые, то обработать это состояние (нажато или не нажато)

vladec
Еще более простой алгоритм: опрашивайте клавиатуру считывая состояние кнопок с интервалом 15 - 20 мс (или другое значение, превышающее время дребезга) и используйте считанные значения как истинные.
ARV
Цитата(vladec @ Mar 29 2013, 10:30) *
Еще более простой алгоритм: опрашивайте клавиатуру считывая состояние кнопок с интервалом 15 - 20 мс (или другое значение, превышающее время дребезга) и используйте считанные значения как истинные.
недопустимо

доводим до абсурда: опрашиваем кнопку 1 раз в час - ровно в 00 минут и 00 секунд и 00 миллисекунд. а я нажимаю кнопку ровно за 3 миллисекунды до этого момента - в итоге опрос попадает как раз на время, пока кнопка дребезжит, и что при этом "опросится" - не известно
Genadi Zawidowski
Вот кусок проекта с подавлениями и автоповторами разными. Будут вопросы - пишите.
Почему-то не аттачится ничего...

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;
}
ViKo
Имею три массива для обработки панели управления: массив нового состояния кнопок New, массив предыдущего состояния кнопок Old, массив обработанных кнопок Fix.
Опрашиваю кнопки с разумным интервалом, 64 раза в секунду, сохраняю в массиве New. Сравниваю со старым Old, полученным в прошлом опросе, и обработанными кнопками Fix. Если есть кнопка, состояние которой в New и Old одинаковое (устойчивое, не дребезжит), и отличается от Fix (еще не обработана), то выполняю обработку этой кнопки (посылаю по интерфейсу, в моем случае). После этого меняю состояние в массиве Fix. Дальше можно искать следующую кнопку с такими же свойствами. Ну, и в конце цикла не забываю перенести массив New в Old.
Таким образом, реагирую на любое нажатие или отпускание кнопок в любой комбинации. Для обнаружения изменившегося состояния кнопки мне нужно время (1/64 * 2 = 31 ms). Более частое дребезжание будет игнорировано.
P.S. Автоповтор, если нужно, делаю в программе, куда посылаю состояние кнопок. Пока кнопка нажата, можно с неким интервалом (первый больше) реагировать на кнопку. Когда придет информация, что кнопка отпущена, прекращаю.
Intel4004
Цитата(ARV @ Mar 29 2013, 11:08) *
недопустимо
доводим до абсурда: опрашиваем кнопку 1 раз в час - ровно в 00 минут и 00 секунд и 00 миллисекунд. а я нажимаю кнопку ровно за 3 миллисекунды до этого момента - в итоге опрос попадает как раз на время, пока кнопка дребезжит, и что при этом "опросится" - не известно

Вполне допустимо. Попали на дребезг сейчас - значит получим правильный результат в следующий опрос. Главное чтобы интервал опроса был заведомо больше времени дребезга и меньше времени реакции человека. 50-70 мсек - оптимум, при 100 уже чувствуется задержка...
ARV
Цитата(Intel4004 @ Apr 1 2013, 13:52) *
Вполне допустимо.
сколько себя помню, все время стараются с дребезгом бороться. а решение-то, оказывается, элементарное! спасибо вам за совет, теперь мир изменится...
dch
Цитата(ARV @ Apr 2 2013, 07:59) *
элементарное

Дай и я сюда плюну, обнаружители обычно просто строятся, в регистр вдвигается 0,1 (не нажата/нажата),
далее есть критерий обнаружения начала события (нажатия), продолжения (удерживания) и конца события (отпускания клавиши), обычно это столько единичек из столькото отчетов, например для начала нажатия можно
взять 2 единички из 3х отсчетов, аналогично для удержания и отжатия.
ilya-m
Удобный механизм подавления дребезга - вертикальные счетчики.

Почитать о них можно тут -
http://www.compuphase.com/electronics/debouncing.htm
http://www.dattalo.com/technical/software/pic/debounce.html
http://www.electro-tech-online.com/microco...debouncing.html
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.