реклама на сайте
подробности

 
 
> Дребезг контактов..., Или ошибка в программе???
Зверюга
сообщение Dec 25 2006, 21:40
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 413
Регистрация: 15-12-06
Пользователь №: 23 563



Господа, подскажите, как написать программу обработки клавиш устойчивую к дребезгу?

Смысл в чем - есть переменная mode=0; при однократном нажатии на клавишу (подаче сигнала на PB5) значение mode должно увеличиваться на единицу.

ВОт фрагмент моего кода

Код
// Проверяем режим

char ButtonPressed;

............................

ButtonPressed=0;

while (1)

{

DisplayLCD(Mode);

if (bit_is_set(PINB,5))
{
PORTA |=_BV(PA3);
ButtonPressed=1;
}

else

{
PORTA &=~_BV(PA3);
  if (ButtonPressed==1)
   {
     Mode++;
     ButtonPressed=0;
   }
}

}




Ну... помимо всего программа зажигает диод (PA3). В начале цикла отображает на LCD значение mode. ВОт только при нажатии клавиши у меня получается не числовоя ряд, а постоянная последовательность -1..3..7.. Дребезг?

Как решить проблему?

Спасибо!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 12)
prottoss
сообщение Dec 25 2006, 21:45
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(Зверюга @ Dec 26 2006, 01:40) *
Господа, подскажите, как написать программу обработки клавиш устойчивую к дребезгу?


Кроме фиксирования состояния вывода порта, необходимо анализировать длительность этого состояния, и, если оно более, допустим, 50 милисекунд, принимать решение о том, что состояние порта изменилось... В каком то аппноте на http://atmel.com есть пример обработки клавиатуры... Правда, на ассемблере...


--------------------
Go to the top of the page
 
+Quote Post
Screw
сообщение Dec 25 2006, 22:36
Сообщение #3


Частый гость
**

Группа: Свой
Сообщений: 149
Регистрация: 29-11-06
Из: Барнаул
Пользователь №: 22 916



Самый простой вариант - я делаю вот так:
if (PINA.4)
{
delay_ms(50)
if (PINA.4)
{
Обработка события
}
}

Если порос клавиатуры - можно допустим 256 раз опрашивать циклически клавиатуру и сравнивать текущее состояние с предъидущим.... Если одинаковые - значит все нормально

Сообщение отредактировал Screw - Dec 25 2006, 22:37
Go to the top of the page
 
+Quote Post
arttab
сообщение Dec 26 2006, 06:54
Сообщение #4


Профессионал
*****

Группа: Свой
Сообщений: 1 432
Регистрация: 7-12-04
Из: Новосибирск
Пользователь №: 1 371



если нажата - к inc к максимуму,
иначе dec к минумуму.
если > порога,
то нажата


--------------------
OrCAD, Altium,IAR, AVR....
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 26 2006, 07:24
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Есть два широкораспространенных метода устранения дребезга.
1. Выбирается интервал времени, заведомо превышающий дребезг данного типа контактов. Опрос контакта производится через промежуток времени равный или больший, чем этот интервал. Если состояние контакта в двух "соседних" опросах одинаково, то оно считается устойчивым.
2. По выбранному уровню сигнала от контакта (спад/фронт/сработал/разомкнут) запускается цикл опроса контакта. Цикл с заранее определенным интервалом времени. В цикле опрашивается состояние контакта на заданный уровень и ведется счетчик совпадений. Пока состояния одинаковы, то счетчик увеличивается (или уменьшается) до порогового значения. При любом несовпадении счетчик сбрасывается (или устанавливается) и счет состояний возобновляется в пределах выделенного интервала времени. Состояние считается устойчивым, если счетчик достиг порогового значения (опять же за выделенный интервал времени). Если за выделенный интервал счетчик состояний порога не достиг, то состояние считается неопределенным.

Первый способ применяется чаще всего при наличии в программе "системного" прерывания с периодом 0,01-0,3с. Чаще 100Гц опрашивать состояние клавитуры не имеет смысла, т.к. дребезг многих типов кнопок составляет до 10 мс. Реже 3Гц тоже не стоит, т.к. реакция на нажатие клавиши будет неудобна для пользователя.

Второй способ можно применять совместно с прерыванием от к.-либо пина МК, к которому подключен контакт. Только не забывайте очищать флаги прерываний перед выходом из обработчика прерывания.
Go to the top of the page
 
+Quote Post
fantasy
сообщение Dec 26 2006, 11:26
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 69
Регистрация: 17-09-05
Из: Kirov
Пользователь №: 8 659



гляньте http://electronix.ru/forum/index.php?showt...18450&st=15

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


--------------------
В голове слышался грохот: рушились грандиозные планы...
Go to the top of the page
 
+Quote Post
tag
сообщение Dec 26 2006, 15:48
Сообщение #7


Частый гость
**

Группа: Свой
Сообщений: 151
Регистрация: 21-02-06
Пользователь №: 14 561



Цитата(rezident @ Dec 26 2006, 07:24) *
Есть два широкораспространенных метода устранения дребезга.
1. Выбирается интервал времени, заведомо превышающий дребезг данного типа контактов. Опрос контакта производится через промежуток времени равный или больший, чем этот интервал. Если состояние контакта в двух "соседних" опросах одинаково, то оно считается устойчивым.
2. По выбранному уровню сигнала от контакта (спад/фронт/сработал/разомкнут) запускается цикл опроса контакта. Цикл с заранее определенным интервалом времени. В цикле опрашивается состояние контакта на заданный уровень и ведется счетчик совпадений. Пока состояния одинаковы, то счетчик увеличивается (или уменьшается) до порогового значения. При любом несовпадении счетчик сбрасывается (или устанавливается) и счет состояний возобновляется в пределах выделенного интервала времени. Состояние считается устойчивым, если счетчик достиг порогового значения (опять же за выделенный интервал времени). Если за выделенный интервал счетчик состояний порога не достиг, то состояние считается неопределенным.

Первый способ применяется чаще всего при наличии в программе "системного" прерывания с периодом 0,01-0,3с. Чаще 100Гц опрашивать состояние клавитуры не имеет смысла, т.к. дребезг многих типов кнопок составляет до 10 мс. Реже 3Гц тоже не стоит, т.к. реакция на нажатие клавиши будет неудобна для пользователя.

Второй способ можно применять совместно с прерыванием от к.-либо пина МК, к которому подключен контакт. Только не забывайте очищать флаги прерываний перед выходом из обработчика прерывания.




...на самом деле второй способ не всегда применим, потому что приходится останавливать все процессы для проверки на дребезг. А первый очень даже универсален, я обычно по системному таймеру делаю выборки с периодом меньшим чем время дребезга и сохраняю эти выборки в массиве каждый раз контролируя совпадение выборок. Если все выборки совпали - значит дребезг исчез. Этот метод действенен еще когда существует множество датчиков типа "сухой контакт" или "провод-команда" и они существенно удалены от контроллера, он исключает влияние переходных процессов в проводах.
Go to the top of the page
 
+Quote Post
okela
сообщение Dec 26 2006, 16:41
Сообщение #8


Частый гость
**

Группа: Свой
Сообщений: 165
Регистрация: 11-01-05
Из: Украина, г. Одесса
Пользователь №: 1 896



Цитата(tag @ Dec 26 2006, 16:48) *
...на самом деле второй способ не всегда применим, потому что приходится останавливать все процессы для проверки на дребезг. А первый очень даже универсален, я обычно по системному таймеру делаю выборки с периодом меньшим чем время дребезга и сохраняю эти выборки в массиве каждый раз контролируя совпадение выборок. Если все выборки совпали - значит дребезг исчез. Этот метод действенен еще когда существует множество датчиков типа "сухой контакт" или "провод-команда" и они существенно удалены от контроллера, он исключает влияние переходных процессов в проводах.


Запуск цикла опроса также может быть запущен дискретно в процедуре прерывания таймера с достаточно высокой частотой (инкремент/сброс счетчика времени нажатия), тем самым без ущерба остальным процессам.
Go to the top of the page
 
+Quote Post
defunct
сообщение Dec 26 2006, 16:54
Сообщение #9


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(tag @ Dec 26 2006, 15:48) *
...на самом деле второй способ не всегда применим, потому что приходится останавливать все процессы для проверки на дребезг.

Второй способ можно выполнять в прерывании, например таймера:

Код
void PeriodicIntHandler(void)
{
     static U8 state = 0x00; // последнее устойчивое состояние
     static U8 new_state = 0xA5; // текущее состояние (с дребезгом) устанавливаем в неопределенное положение

     new_state <<= 1;
     new_state |= (значение некоторого пина, к которому подключена кнопка);

     if ((new_state == 0) || (new_state == 0xFF))
     {
         if (state != new_state)
         {
              state = new_state; // состояние изменилось.
         }
     }
}
Go to the top of the page
 
+Quote Post
prottoss
сообщение Dec 26 2006, 17:03
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



НЕ клавиатуру я опрашиваю так:

Код
/*****************************************************************************
Рабочие переменные
******************************************************************************/

/* описатель состояния датчика */
typedef struct
{
BOOL State:  1;  /* текущее состояние линии */
    BOOL Changed: 1;  /* флаг изменения состояния */
    UINT32 Time;    /* время для гашения дребезга контактов */
}
Discrete_Status_t;

Discrete_Status_t Cover; /* состояние датчика крышки прибора */
Discrete_Status_t Ignit; /* состояние линии зажигания */

/*****************************************************************************
Прототипы функций
******************************************************************************/

/* Возвращает состояние на линии */
BOOL DISCRETE_SENS_GetState(UCHAR state, Discrete_Status_t *status, UCHAR delay);

/*****************************************************************************
Инициализация модуля
******************************************************************************/
void DISCRETE_SENS_Init(void)
{
/* Настраиваем порты датчика крышки прибора */
   COVER_SENSOR_DDR &= ~(1 << COVER_SENSOR); /* настраиваем как вход */



#ifdef COVER_SENSOR_PULLUP_INC
    COVER_SENSOR_PORT |= (1 << COVER_SENSOR); /* подключаем pull-up */
#endif /* #ifdef COVER_SENSOR_PULLUP_INC */



    /* Настраиваем порты датчика включения зажигания */
    IGNIT_SENSOR_DDR &= ~(1 << IGNIT_SENSOR); /* настраиваем как вход */

#ifdef IGNIT_SENSOR_PULLUP_INC
    IGNIT_SENSOR_PORT |= (1 << IGNIT_SENSOR); /* подключаем pull-up */
#endif /* #ifdef IGNIT_SENSOR_PULLUP_INC */



    /* инициализируем датчики */
    Cover.State = FALSE;
    Cover.Changed = FALSE;
    Ignit.State = FALSE;
    Ignit.Changed = FALSE;
}

/*****************************************************************************
возвращает состояние на линии
******************************************************************************/
BOOL DISCRETE_SENS_GetState(UCHAR state, Discrete_Status_t *status, UCHAR delay)
{
   /* проверяем, измеряем ли время дребезга */
    if(TRUE == status->Changed) /* да */
    { if(delay < (g_SysTIME_ms - status->Time))
        {
            status->State = state; /* запоминаем новое состояние */
            status->Changed = FALSE; /* снимаем флаг измерения времени */
        }
    }
    else /* нет */
    { /* проверяем, изменилось ли состояние линии */
       if(state != status->State) /* если да, то начинаем цикл задержки */
        {  
           status->Time = g_SysTIME_ms; /* запоминаем время события, для задержки на временя дребезга */
            status->Changed = TRUE; /* фиксируем изменение состояния линии */
        }
    }

    return status->State;
}

/*****************************************************************************
Возвращает состояние на линии датчика крышки прибора
******************************************************************************/
BOOL COVER_SENS_GetState(void)
{
   return DISCRETE_SENS_GetState(
     (COVER_SENSOR_PIN & (1 << COVER_SENSOR))? TRUE: FALSE,
        &Cover,
        COVER_SENSOR_SWITCH_TIME);
}

/*****************************************************************************
возвращает состояние на линии зажигания
******************************************************************************/
BOOL IGNIT_SENS_GetState(void)
{
   return DISCRETE_SENS_GetState(
     (IGNIT_SENSOR_PIN & (1 << IGNIT_SENSOR))? TRUE: FALSE,
        &Ignit,
        IGNIT_SENSOR_SWITCH_TIME);
}




g_SysTIME_ms - системное время в милисекундах

COVER_SENSOR_SWITCH_TIME и IGNIT_SENSOR_PULLUP_INC - промежуток времени, определяющий дребезг контакта



COVER_SENS_GetState и IGNIT_SENS_GetState вызываются в главном цикле программы


--------------------
Go to the top of the page
 
+Quote Post
defunct
сообщение Dec 26 2006, 17:50
Сообщение #11


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



prottoss
Просто организуете задержку, без подтверждения состояни датчика?
Ложных срабатываний из-за помех в вашей системе не бывает?

Оптимизировать лучше те участки, которые выполняются чаще:

....
if (g_SysTIME_ms >= status->Time)
....
status->Time = g_SysTIME_ms + delay;
Go to the top of the page
 
+Quote Post
prottoss
сообщение Dec 26 2006, 18:01
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(defunct @ Dec 26 2006, 21:50) *
prottoss
Просто организуете задержку, без подтверждения состояни датчика?
Ложных срабатываний из-за помех в вашей системе не бывает?
Почему без подтверждения? При входе в DISCRETE_SENS_GetState(...) передается текущее состояние линии, ну а там уже анализ и сравнение с предыдущим состоянием. Как Вы догадались система работает в авто, правда это пока тестовая плата, но вот уже пару недель без сбоев. Почему так уверен, потому что все фиксируется во внешней флэш



Цитата(defunct @ Dec 26 2006, 21:50) *
Оптимизировать лучше те участки, которые выполняются чаще:
....
if (g_SysTIME_ms >= status->Time)
....
status->Time = g_SysTIME_ms + delay;
Возможно, надо попробовать и посмотреть листинг. Но, на этапе разработки, я не занимаюсь вылизыванием программы)))


--------------------
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 26 2006, 20:59
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(tag @ Dec 26 2006, 17:48) *
...на самом деле второй способ не всегда применим, потому что приходится останавливать все процессы для проверки на дребезг. А первый очень даже универсален, я обычно по системному таймеру делаю выборки с периодом меньшим чем время дребезга и сохраняю эти выборки в массиве каждый раз контролируя совпадение выборок. Если все выборки совпали - значит дребезг исчез. Этот метод действенен еще когда существует множество датчиков типа "сухой контакт" или "провод-команда" и они существенно удалены от контроллера, он исключает влияние переходных процессов в проводах.

Я в общем-то тоже использую первый способ. Но в некоторых случаях (например, когда требуется энергосберегающий режим работы устройства) второй способ предпочтительнее. Кстати, на нем же работали обычные ПиСишные клавиатуры. По крайней мере лет 10-12 назад я встречал описание именно такого принципа сканирования в PC-ных клавиатурах.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 09:40
Рейтинг@Mail.ru


Страница сгенерированна за 0.01523 секунд с 7
ELECTRONIX ©2004-2016