Axxel 0 Posted March 28, 2007 (edited) · Report post Привет всем! Написал небольшой кусочек кода для подавления дребезга контактов, IMHO данный код должен "фильтровать" ложные срабатывания менее заданного периода. Но почему-то не покидает ощущение того, что в коде могут оказаться грабли :) Какие еще есть правильные методы, либо можно это сделать проще или красивее? Пример для одного бита порта ввода: #define BOUNCE_CANCELLATION_PERIOD 20 unsigned char BITcounter=0; //счетчик состояний бита bit BITstate=0; //используемое (устойчивое) состояние бита (более 20 мсек) bit BITmemory=0; // промежуточная переменная, запоминающаяя предыдущее состояние бита bit toggled=0; //флаг,указывающий на изменение состояния бита interrupt Timer0() //возникает 1 раз в мсек { if(BITmemory^BITn){if(toggled){BITcounter=0;} toggled=1;} if(toggled ){BITcounter++;} if(BITcounter==BOUNCE_CANCELLATION_PERIOD){BITstate=BITn;BITcounter=0;toggled=0; } BITmemory=BITn; //чтение с порта } Вот, примерно так... Edited March 28, 2007 by Axxel Quote Ответить с цитированием Share this post Link to post Share on other sites
Oleg_IT 0 Posted March 28, 2007 · Report post Давно и хорошо работающий код. Обслуживает несколько клавиш. unsigned long int debounced_state = 0,debounced_stateOld = 0; unsigned long int A = 0x0; unsigned long int B = 0x0; unsigned long int C = 0x0; void debounce(unsigned long int new_sample) { unsigned long int delta; delta = new_sample ^ debounced_state; //Find all of the changes /* clock_A ^= clock_B; //Increment the counters clock_B = ~clock_B;*/ A = A^(B&C); B = B^C; C = ~C; A &= delta; //Reset the counters if no changes B &= delta; //were detected. C &= delta; //Preserve the state of those bits that are being filtered and simultaneously //clear the states of those bits that are already filtered. debounced_state &= (A|B|C); //Re-write the bits that are already filtered. debounced_state |= (~(A|B|C) & new_sample); } Quote Ответить с цитированием Share this post Link to post Share on other sites
Vade_nsk 0 Posted March 28, 2007 · Report post а я просто опрашиваю клавиатуру с интервалом большим, чем максимальное время дребезга. Скажем в первом примере вместо прерывания каждую 1 мс делать опрос раз в 20-50мс. Человек такую задержку не чувствует Quote Ответить с цитированием Share this post Link to post Share on other sites
IEC 0 Posted March 28, 2007 · Report post Контролировать один раз нажатие клавиши (совет NVade) глупо, т.к. любой дребезг вызовет событие нажатия. По хорошему необходимо контролировать время первого удержания клавиши (состояния порта) и через контрольный тайм-аут, если состояние ни разу не изменилось, принимать решение о нажатии клавиши. После этого необходимо переходить на другой этап и контролировать время отпускания. Через определенный тайм-аут принимать решение об завершении работы с клавишей. И уже после всего этого можно переходить к повторному ожиданию нажатия клавиши. Quote Ответить с цитированием Share this post Link to post Share on other sites
Axxel 0 Posted March 28, 2007 · Report post По хорошему необходимо контролировать время первого удержания клавиши (состояния порта) и через контрольный тайм-аут, если состояние ни разу не изменилось, принимать решение о нажатии клавиши. После этого необходимо переходить на другой этап и контролировать время отпускания. Через определенный тайм-аут принимать решение об завершении работы с клавишей. И уже после всего этого можно переходить к повторному ожиданию нажатия клавиши. Да, примерно так и сделано, т.е к примеру если BOUNCE_CANCELLLATION_PERIOD равен 20 то в течение за все 20 прерываний от таймера значение бита должно быть равно одному и тому же значению, только в этом случае состояние запоминается. Вопрос: нормально ли для этого алгоритма использование прерывания от таймера? Может есть способы без прерываний? Quote Ответить с цитированием Share this post Link to post Share on other sites
SergCom07 0 Posted March 28, 2007 · Report post Думаю лучший вариант реализуется при помощи прерываний от линий IO кнопок. В этом случае изменение состояния линии не пропустишь, а по таймеру только проверять время, прошедшее с момента последнего изменения состояния и через скажем 20 мс фиксировать логическое состояние кнопки (нажата/нет). Вопрос только в количестве кнопок и аппаратных прерываний, но у последних AVR их много. Quote Ответить с цитированием Share this post Link to post Share on other sites
Visor 0 Posted March 28, 2007 · Report post На самом деле достаточно ловить первый фронт изменения состояния и через таймаут проверить сохранилось ли состояние. И не надо ждать когда сигнал перестанет дребезжать, и только потом включать выдержку времени, это бессмысленно. Подумайте. :) Quote Ответить с цитированием Share this post Link to post Share on other sites
DeXteR 0 Posted March 29, 2007 · Report post На самом деле достаточно ловить первый фронт изменения состояния и через таймаут проверить сохранилось ли состояние. И не надо ждать когда сигнал перестанет дребезжать, и только потом включать выдержку времени, это бессмысленно. Подумайте. :) Если неждать то кто даст гарантию что после принятия решения о нажатой кнопке не происходит дребезга А с дребезгом при отжатии как быть ?? По моему мнению самый верный способ - запускать програмный таимер по нажатию Делать +1 если нажата и -1 если отжата Ограничить нулем и числом А снизу и сверху И принимать решение о точ что нажата кнопка когда таимер достигнет А Заодно можно и блительное нажатие обрабатывать Quote Ответить с цитированием Share this post Link to post Share on other sites
rezident 0 Posted March 29, 2007 · Report post На всех форумах одни и те же вопросы задаются :) http://www.telesys.ru/wwwboards/mcontrol/1...es/202772.shtml Quote Ответить с цитированием Share this post Link to post Share on other sites
Axxel 0 Posted March 30, 2007 · Report post У меня примерно так: Quote Ответить с цитированием Share this post Link to post Share on other sites
Visor 0 Posted March 31, 2007 · Report post Если неждать то кто даст гарантию что после принятия решения о нажатой кнопке не происходит дребезга А с дребезгом при отжатии как быть ?? Либо я не ясно выразился, либо одно из двух. :) Ловим фронт изменения входа (не важно какой), запоминаем новое состояние, ждем время достаточное чтоб дребезг успокоился, проверяем вновь состояние входа, если совпало, его и принимаем за текущее. Обрабытывается таким образом и вкл и выкл. Quote Ответить с цитированием Share this post Link to post Share on other sites
Axxel 0 Posted April 2, 2007 · Report post А если произойдет такое? Quote Ответить с цитированием Share this post Link to post Share on other sites
Visor 0 Posted April 2, 2007 · Report post А если произойдет такое? Объясните пожалуйста, как такое возможно? Quote Ответить с цитированием Share this post Link to post Share on other sites
=AK= 0 Posted April 2, 2007 · Report post Я проще делаю. В 8-битный сдвиговый регистр каждые 10 мс вдвигаю текущее состояние кнопки. Если в сдвиговом регистре все '1', то кнопка нажата, выходной сигнал устанавливаю в '1'. Если все '0', то кнопка отжата, выходной сигнал устанавливаю в '0'. Все другие комбинации игнорируются и не меняют состояние вых. сигнала. При опроcе каждые 10 мс и 8-ми битах время получается 80 мс, это отлично работает со всеми обычными кнопками, в т.ч. с мембранными клавами. Для массивных контактов, которые могут дребезжать с малой частотой (контактор какой-нибудь, например), время опроса можно увеличить до 20..30 мс. Quote Ответить с цитированием Share this post Link to post Share on other sites
Axxel 0 Posted April 2, 2007 · Report post Объясните пожалуйста, как такое возможно? Помехи например, ложные срабатывания от датчиков, ведь такое IMHO может быть Я проще делаю. В 8-битный сдвиговый регистр каждые 10 мс вдвигаю текущее состояние кнопки. Если в сдвиговом регистре все '1', то кнопка нажата, выходной сигнал устанавливаю в '1'. Если все '0', то кнопка отжата, выходной сигнал устанавливаю в '0'. Все другие комбинации игнорируются и не меняют состояние вых. сигнала. При опроcе каждые 10 мс и 8-ми битах время получается 80 мс, это отлично работает со всеми обычными кнопками, в т.ч. с мембранными клавами. Для массивных контактов, которые могут дребезжать с малой частотой (контактор какой-нибудь, например), время опроса можно увеличить до 20..30 мс. Можно кусочек кода? И еще вопрос: используя прерывания от аппаратного таймера для подавления дребезга, с какой частотой целесообразнее всего устраивать эти прерывания? И каков риск что пользовательская функция-обработчик не успеет обработаться до возникновения следующего прерывания? Quote Ответить с цитированием Share this post Link to post Share on other sites