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

Подавление дребезга контактов

Привет всем!

Написал небольшой кусочек кода для
подавления дребезга контактов, IMHO данный
код должен "фильтровать" ложные срабатывания
менее заданного периода.
Но почему-то не покидает ощущение того, что
в коде могут оказаться грабли smile.gif

Какие еще есть правильные методы,
либо можно это сделать проще или красивее?

Пример для одного бита порта ввода:

#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; //чтение с порта
}



Вот, примерно так...
Изменено пользователем Axxel

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


Ссылка на сообщение
Поделиться на другие сайты
Давно и хорошо работающий код. Обслуживает несколько клавиш.

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);
}

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


Ссылка на сообщение
Поделиться на другие сайты
а я просто опрашиваю клавиатуру с интервалом большим, чем максимальное время дребезга. Скажем в первом примере вместо прерывания каждую 1 мс делать опрос раз в 20-50мс. Человек такую задержку не чувствует

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


Ссылка на сообщение
Поделиться на другие сайты
Контролировать один раз нажатие клавиши (совет NVade) глупо, т.к. любой дребезг вызовет событие нажатия.

По хорошему необходимо контролировать время первого удержания клавиши (состояния порта) и через контрольный тайм-аут, если состояние ни разу не изменилось, принимать решение о нажатии клавиши. После этого необходимо переходить на другой этап и контролировать время отпускания. Через определенный тайм-аут принимать решение об завершении работы с клавишей.
И уже после всего этого можно переходить к повторному ожиданию нажатия клавиши.

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


Ссылка на сообщение
Поделиться на другие сайты
По хорошему необходимо контролировать время первого удержания клавиши (состояния порта) и через контрольный тайм-аут, если состояние ни разу не изменилось, принимать решение о нажатии клавиши. После этого необходимо переходить на другой этап и контролировать время отпускания. Через определенный тайм-аут принимать решение об завершении работы с клавишей.
И уже после всего этого можно переходить к повторному ожиданию нажатия клавиши.
[/quote]


Да, примерно так и сделано, т.е к примеру если BOUNCE_CANCELLLATION_PERIOD равен 20
то в течение за все 20 прерываний от таймера значение бита должно быть равно одному и тому
же значению, только в этом случае состояние запоминается.

Вопрос: нормально ли для этого алгоритма использование прерывания от таймера?
Может есть способы без прерываний?

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


Ссылка на сообщение
Поделиться на другие сайты
Думаю лучший вариант реализуется при помощи прерываний от линий IO кнопок.
В этом случае изменение состояния линии не пропустишь, а по таймеру только проверять время, прошедшее с момента последнего изменения состояния и через скажем 20 мс фиксировать логическое состояние кнопки (нажата/нет).
Вопрос только в количестве кнопок и аппаратных прерываний, но у последних AVR их много.

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


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

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(Visor @ Mar 28 2007, 20:56) <{POST_SNAPBACK}>
На самом деле достаточно ловить первый фронт изменения состояния и через таймаут проверить сохранилось ли состояние. И не надо ждать когда сигнал перестанет дребезжать, и только потом включать выдержку времени, это бессмысленно. Подумайте. smile.gif


Если неждать то кто даст гарантию что после принятия решения о нажатой кнопке не происходит дребезга
А с дребезгом при отжатии как быть ??

По моему мнению самый верный способ - запускать програмный таимер по нажатию
Делать +1 если нажата и -1 если отжата
Ограничить нулем и числом А снизу и сверху
И принимать решение о точ что нажата кнопка когда таимер достигнет А

Заодно можно и блительное нажатие обрабатывать

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(DeXteR @ Mar 30 2007, 00:19) <{POST_SNAPBACK}>
Если неждать то кто даст гарантию что после принятия решения о нажатой кнопке не происходит дребезга
А с дребезгом при отжатии как быть ??

Либо я не ясно выразился, либо одно из двух. smile.gif
Ловим фронт изменения входа (не важно какой), запоминаем новое состояние, ждем время достаточное чтоб дребезг успокоился, проверяем вновь состояние входа, если совпало, его и принимаем за текущее. Обрабытывается таким образом и вкл и выкл.

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


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

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(Axxel @ Apr 2 2007, 10:12) <{POST_SNAPBACK}>
А если произойдет такое?

Объясните пожалуйста, как такое возможно?

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


Ссылка на сообщение
Поделиться на другие сайты
Я проще делаю. В 8-битный сдвиговый регистр каждые 10 мс вдвигаю текущее состояние кнопки. Если в сдвиговом регистре все '1', то кнопка нажата, выходной сигнал устанавливаю в '1'. Если все '0', то кнопка отжата, выходной сигнал устанавливаю в '0'. Все другие комбинации игнорируются и не меняют состояние вых. сигнала.

При опроcе каждые 10 мс и 8-ми битах время получается 80 мс, это отлично работает со всеми обычными кнопками, в т.ч. с мембранными клавами. Для массивных контактов, которые могут дребезжать с малой частотой (контактор какой-нибудь, например), время опроса можно увеличить до 20..30 мс.

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(Visor @ Apr 2 2007, 09:09) <{POST_SNAPBACK}>
Объясните пожалуйста, как такое возможно?


Помехи например, ложные срабатывания от датчиков, ведь такое IMHO может быть

Цитата(=AK= @ Apr 2 2007, 09:25) <{POST_SNAPBACK}>
Я проще делаю. В 8-битный сдвиговый регистр каждые 10 мс вдвигаю текущее состояние кнопки. Если в сдвиговом регистре все '1', то кнопка нажата, выходной сигнал устанавливаю в '1'. Если все '0', то кнопка отжата, выходной сигнал устанавливаю в '0'. Все другие комбинации игнорируются и не меняют состояние вых. сигнала.

При опроcе каждые 10 мс и 8-ми битах время получается 80 мс, это отлично работает со всеми обычными кнопками, в т.ч. с мембранными клавами. Для массивных контактов, которые могут дребезжать с малой частотой (контактор какой-нибудь, например), время опроса можно увеличить до 20..30 мс.


Можно кусочек кода?

И еще вопрос: используя прерывания от аппаратного таймера для подавления
дребезга, с какой частотой целесообразнее всего устраивать эти прерывания?
И каков риск что пользовательская функция-обработчик не успеет обработаться
до возникновения следующего прерывания?

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


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

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация