|
|
  |
Дребезг контактов, Как избежать? |
|
|
|
Jul 10 2006, 15:19
|

Участник

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

|
Внесу свою реплику в дискуссию... Код #define _fDreb 5 //защита от дребезга (0.05 сек.) #define _fRepite 39 //время первого автоповтора (0.4 сек.) #define _nRepite 10 //время второго и последующего автоповтора (0.1 сек.)
//уровни напряжений для кнопок (_minKey1 > _minKey2 > _minKey3 > _minKey4) #define _minKey1 ... //минимальный уровень напряжения для кнопки 1 #define _minKey2 ... //минимальный уровень напряжения для кнопки 2 #define _minKey3 ... //минимальный уровень напряжения для кнопки 3 #define _minKey4 ... //минимальный уровень напряжения для кнопки 4 unsigned int ADCresult; unsigned char newHKey, oldHKey, drebCount; unsigned char _key;
ADCresult = ...; //данные с АЦП //... вызывается с частотой ~100 Гц newHKey = 0; if(ADCresult>=_minKey1) { newHKey = 0x01; //key1 } else if(ADCresult>=_minKey2) { newHKey = 0x02; //key2 } else if(ADCresult>=_minKey3) { newHKey = 0x04; //key3 } else { newHKey = 0x08; //key4 }; if((oldHKey!=newHKey)||(newHKey==0x0)) { _key = false; drebCount = _fDreb; } else { if((--drebCount)==0) { //расшифровываем нажатие на кнопки if(newHKey&0x01)key1=true; if(newHKey&0x02)key2=true; if(newHKey&0x04)key3=true; if(newHKey&0x08)key4=true; drebCount = _fRepite; //предполагаем повторное нажатие if(_key==false)drebCount = _nRepite; //устанавливаем ожидание 1-го нажатия _key = true; }; }; oldHKey = newHKey;
--------------------
В голове слышался грохот: рушились грандиозные планы...
|
|
|
|
|
Jul 19 2006, 17:58
|

Участник

Группа: Новичок
Сообщений: 40
Регистрация: 4-06-06
Пользователь №: 17 766

|
Понимаю что вопрос тупой, но всё таки ... Упростил пример до невозможного, а он опять не работает Цитата int main( void ) { byte t1,t2; DDRB=0x0F; // b0-b3 : outputs b4-b7 : inputs DDRD=0xFF; // d0-d7 output
PORTB=0x01;; for(;;) { __delay_cycles(160000); // Пихните куда надо t1=PORTB; t2=0x10; t1=t1 & t2;
if (t1==t2) PORTD=0xFF; else PORTD=0x00; } } Хочу чтоб загорелся диод на PORTD после нажатия клав. "1" на 4x4 клавиатуре. Помогите плииииис !!! п.с. Не ругайте снльно.
|
|
|
|
|
Feb 11 2010, 09:23
|
Знающий
   
Группа: Свой
Сообщений: 922
Регистрация: 3-06-05
Из: Москва
Пользователь №: 5 709

|
Как-то уже приводил здесь этот код. Код 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); }
|
|
|
|
|
Feb 11 2010, 13:49
|

Частый гость
 
Группа: Участник
Сообщений: 148
Регистрация: 23-02-07
Пользователь №: 25 618

|
Цитата(smk @ Feb 10 2010, 19:48)  Как выяснилось в моем случае, полезно обеспечивать не только устранение дребезга, но и время нечувствительности к повторному нажатию. Иначе сканировать и отрабатывать будет успевать быстрее чем поймет оператор что он нанажимал. Или следить, когда кнопку отпустили. Для схемы с одной кнопкой делал типа : Код #define Knopka PIND.3 // Knopka podl na PD 3 , vtoraja noga na zemlu // v portu vklucit podtiagivajushchij rezistor, ili postavit vneshnij k +5 V // jesli knopka nazata, to "Knopka " budet ravna 0
unsigned char ButtonDownTime(void) // return TimeLong if long, and TimeShort if short time { unsigned char i; while ( Knopka == 1); for(i=0;i<7;i++) { delay_ms(50); // zadierzka od drebiezga kontaktow if (Knopka == 1) // odpuscili knopku { return TimeShort;//short goto MEnd; // vyhod s cikla } } return TimeLong;//long MEnd: }
void WaitButtonUp(void) { while (Knopka == 0); delay_ms(50); }
// vyzyvat primerno tak if (Knopka == 0) //Pervoje nazatije, vhod v menu { WaitButtonUp(); // zhdem otpuskanija knopki if (ButtonDownTime() == TimeShort) { //naprimer uvelichit peremennuju HD++; WaitButtonUp(); } else //if (ButtonDownTime() == TimeShort) { // perehod na sledushchij punkt menu } }
|
|
|
|
|
Feb 11 2010, 21:31
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Oleg_IT @ Feb 12 2010, 00:27)  Товарищ смешивает две задачи, устранения дребезга и частота автоповтора. Может это я не совсем понимаю или неправильно понимаю суть написанного smk?  Поясняю для самого общего случая. Процедура устранения дребезга требуется для ликвидации недостатков аппаратуры. Единичное нажатие клавиши пользователем аппаратура должна четко определить именно как единичное, а не как 2 или 52 или 152 нажатия. Все! Никаких ограничений на частоту нажатий эта процедура оказывать не должна. Ограничения возникают чисто физиологические. Человек физически не способен нажимать клавиши чаще чем, скажем, 100 раз в секунду. И осмысленно с такой скоростью нажимать их, тем более не способен. - Я способна набирать 1200 символов в минуту! - Ну и как, получается? - Вы знаете, если честно, такая фигня выходит. (из анекдота)  В реальности процедура устранения дребезга конечно тоже налагает ограничение на темп нажатий сверху. Типовое время дребезга механических контактов кнопок составляет порядка 10мс. Если устранение дебезга построено на периодическом опросе, то сверху ограничение в те же 100 нажатий в секунду выходит. Но если клавиатура способна 100 нажатий/с обеспечить, то она обязана их обеспечивать без каких-либо других ограничений. Теперь про автоповтор. Автоповтор это "фича" клавиатуры, дополнительное удобство т.с. Автоповтор имитирует многократное нажатие пользователем одной и той же клавиши. Но раз он только имитирует действия пользователя (а пользователи-то все разные), то следовательно автоповтор должен иметь настраиваемые или даже (само)адаптируемые параметры. Пример самоадаптируемого изменения скорости автоповтора можно привести на базе паяльной станции с цифровой регулировкой температуры. Одиночные нажатия изменяют регулировку температуры на 1°C. Автоповтор вначале имитирует такую же ступень изменения (на 1°C). Но если удерживать клавишу дольше и изменение произойдет более чем на 10°C, то шаг приращения температуры автоматически увеличивается до 10°C. Впрочем это я немного отвлекся. Суть-то в том, что автоповтор это имитация действий пользователя. Для его (пользователя) удобства. А ведь пользователи все разные, кто-то реально по 20 раз/с способен нажимать кнопки, а кто-то "с ограниченными возможностями" нажимает кнопки локтем (калека) или физически не способен на быстрые движения (старик или с отклонениями в психическом развитии). Соответственно для каждого из них нужны разные задержки для включения функции автоповтора и разный темп имитации нажатий. Если у функции автоповтора есть возможности подстройки этих параметров, то я не представляю ситуации, когда Цитата("smk") Оператор хочет увеличить на 1, а пока нажал-отпустил насчитало 10.  Вот где мое недоумение/непонимание возникло.
|
|
|
|
|
Feb 11 2010, 23:02
|

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

|
Цитата(Stas633 @ Jul 10 2006, 09:45)  Интересно, каким же алгоритмом пользуются производители автомагнитол? Не знаю как производители магнитол, а я пользуюсь алгоритмом откладывания события: Код const PROGMEM U8 transTab[] = { 200, 167, 125, 99, 83, 71, 61, 55, 49, 44, 40, 37, 35, 32, 30, 28 };
// это задачка, которая запускается с периодом 5ms // сканирует АЦП канал, и преобразует показания АЦП в индекс от 0x0 до 0xF, // индекс представляет собой код, где каждый бит соответствует одной нажатой кнопке. void kbr_ScanTask(void) { U8 val = kbr_AdcChanRead( kbrContext.AdcChan ); U8 i; U8 NewStatus = 0;
for(i = 0; i < sizeof(transTab); i++) { if (val > pgm_read_byte_near( transTab + i )) { NewStatus = i; break; } }
if (NewStatus != kbrContext.status) { kbrContext.status = NewStatus; if (NULL != kbrContext.StatusChange_CB) { // register keyboard status change handler to be executed after 50 ms (to filter out all false events) Kernel_SetTask( kbrContext.StatusChange_CB, 50, TASK_RUN_ONCE ); } } } И при изменении статуса клавиатуры (в данном случае 4 кнопки на 1 канал АЦП), сканирующая задачка ставит в очередь на исполнение через __50ms__ "Keyboard Status Change event". За эти 50ms задача сканирует канал АЦП еще 10 раз (т.к. она выполяется раз в 5ms) и если статус будет изменяться (дребезг), то запуск event'a будет откладываться. Когда состояние АЦП установится - т.е. на протяжении 10 следующих подряд сканирований состояние не изменится, event таки отработает. Это есть, одна из возможных, реализация "Интервального" алгоритма, упомянутого resident'ом
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|