Jump to content

    
Sign in to follow this  
Axxel

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

Recommended Posts

Привет всем!

 

Написал небольшой кусочек кода для

подавления дребезга контактов, 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 by Axxel

Share this post


Link to post
Share on other sites

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

 

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

}

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

 

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

И уже после всего этого можно переходить к повторному ожиданию нажатия клавиши.

Share this post


Link to post
Share on other sites

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

И уже после всего этого можно переходить к повторному ожиданию нажатия клавиши.

 

 

Да, примерно так и сделано, т.е к примеру если BOUNCE_CANCELLLATION_PERIOD равен 20

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

же значению, только в этом случае состояние запоминается.

 

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

Может есть способы без прерываний?

Share this post


Link to post
Share on other sites

Думаю лучший вариант реализуется при помощи прерываний от линий IO кнопок.

В этом случае изменение состояния линии не пропустишь, а по таймеру только проверять время, прошедшее с момента последнего изменения состояния и через скажем 20 мс фиксировать логическое состояние кнопки (нажата/нет).

Вопрос только в количестве кнопок и аппаратных прерываний, но у последних AVR их много.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
На самом деле достаточно ловить первый фронт изменения состояния и через таймаут проверить сохранилось ли состояние. И не надо ждать когда сигнал перестанет дребезжать, и только потом включать выдержку времени, это бессмысленно. Подумайте. :)

 

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

А с дребезгом при отжатии как быть ??

 

По моему мнению самый верный способ - запускать програмный таимер по нажатию

Делать +1 если нажата и -1 если отжата

Ограничить нулем и числом А снизу и сверху

И принимать решение о точ что нажата кнопка когда таимер достигнет А

 

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

Share this post


Link to post
Share on other sites
Если неждать то кто даст гарантию что после принятия решения о нажатой кнопке не происходит дребезга

А с дребезгом при отжатии как быть ??

Либо я не ясно выразился, либо одно из двух. :)

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

Share this post


Link to post
Share on other sites

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

 

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

Share this post


Link to post
Share on other sites
Объясните пожалуйста, как такое возможно?

 

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

 

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

 

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

 

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

 

И еще вопрос: используя прерывания от аппаратного таймера для подавления

дребезга, с какой частотой целесообразнее всего устраивать эти прерывания?

И каков риск что пользовательская функция-обработчик не успеет обработаться

до возникновения следующего прерывания?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this