| Форум РадиоКот https://radiokot.ru/forum/ |
|
| Енкодер + антидребезг + микроконтролер = "работаю как хочу" https://radiokot.ru/forum/viewtopic.php?f=62&t=76027 |
Страница 1 из 3 |
| Автор: | pierro [ Чт июл 26, 2012 19:29:08 ] |
| Заголовок сообщения: | Енкодер + антидребезг + микроконтролер = "работаю как хочу" |
Прошу помощи или подскажите в какую сторону копать Есть енкодер, подключенный к микроконтроллеру(atmega8) к ножкам PINB.2, PINB.1. схема подключения - стандартная с1,с2 = 0,1 мкф, r1,r2 = 10 ком ![]() Но вот проблема в том, что иногда при бистром повороте в одном направление, "программа" может подсчитать 10 положительных импульсов и 3 отрицательных, хотя должно быть 13 положительных. И наоборот. Вот такой программный код Код: #define DECODER_BUTTON_PLUS_IN PINB.2 #define DECODER_BUTTON_MINUS_IN PINB.1 #define DEC_0 0 #define DEC_STEP 1 #define DEC_FIN 2 PrintLineText, PrintLineNumber - вивод текста на екраy типа wh1602 char ShowDialogInt(const char* sCaption, int* iRes, int iMin, int iMax) { int i = 0, iStep = 0; char iCurDec = DEC_0; PrintLineText(0, sCaption); PrintLineNumber(1, *iRes); while(1) { if(0 == DECODER_BUTTON_PLUS_IN && 0 == DECODER_BUTTON_MINUS_IN) { if(DEC_FIN == iCurDec) { (*iRes) = (*iRes) + (int)iStep; if((*iRes) < iMin) (*iRes) = iMin; if((*iRes) > iMax) (*iRes) = iMax; PrintLineNumber(1, *iRes); iCurDec = DEC_0; } } else if(1 == DECODER_BUTTON_PLUS_IN && 0 == DECODER_BUTTON_MINUS_IN) { if(DEC_0 == iCurDec) { iCurDec = DEC_STEP; iStep = -1; } } else if(0 == DECODER_BUTTON_PLUS_IN && 1 == DECODER_BUTTON_MINUS_IN) { if(DEC_0 == iCurDec) { iCurDec = DEC_STEP; iStep = 1; } } else { if(DEC_STEP == iCurDec) { iCurDec = DEC_FIN; } } } } есть подозрения что это дребезг контактов на енкодере, но как от него избавится? Спасибо! |
|
| Автор: | hybroid [ Чт июл 26, 2012 19:44:40 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
Картинка маленькая, ничего не видно. Пробуйте избавляться программно, статей валом, ищите поиском. |
|
| Автор: | pierro [ Чт июл 26, 2012 19:54:38 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
hybroid писал(а): Картинка маленькая за картинку - извините - исправил Программным - это ставит задержки? (а-ля delay_ms(5)) |
|
| Автор: | hybroid [ Чт июл 26, 2012 22:00:17 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
Хотя бы задержки. Алгоритм прост. Словили нажатие, подождали, проверили ещё раз, если осталось - значит окей. Сколько обычно длится дребезг контактов механических энкодеров подскажет ещё кто-то.. Ну или сами поищите, я не помню. Не сильно долго, 5мс это жирно, имхо. |
|
| Автор: | oleg110592 [ Пт июл 27, 2012 07:05:58 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
Использовал года 2 назад код ув. Леонида Ивановича с обсуждения на сахаре, вроде этот: http://caxapa.ru/207402.html все работало |
|
| Автор: | Goldsmith [ Пт июл 27, 2012 09:04:38 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
oleg110592 писал(а): Использовал года 2 назад код ув. Леонида Ивановича с обсуждения на сахаре, вроде этот: http://caxapa.ru/207402.html Действительно работает? Я бегло просмотрел, показалось, что тут не все гладко:все работало Код: //---------- Обработка энкодера: ---------- void Encoder_Exe(void) { char EncCur = 0; if(!Pin_ENC_F1) EncCur = StateA; //опрос фазы 1 энкодера if(!Pin_ENC_F2) EncCur |= StateB; //опрос фазы 2 энкодера if(EncCur != EncPrev) //если состояние изменилось, { if(EncPrev == StateAB && //если предыдущее состояние StateAB EncCur != EncPrevPrev ) //и текущее и пред-предыдущее не равны, { if(EncCur == StateB) //если текущее состояние StateB, Msg = ENC_UP; //шаг вверх else //иначе Msg = ENC_DN; //шаг вниз } EncPrevPrev = EncPrev; //сохранение пред-предыдущего состояния EncPrev = EncCur; //сохранение предыдущего состояния } } Насколько могу судить, при смене состояний AB -> B -> AB -> B ... диск фактически стоит на месте, а программа неуклонно шагает вверх. Поправьте меня, пожалуйста, если я ошибаюсь. |
|
| Автор: | s_black [ Пт июл 27, 2012 09:12:26 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
Здесь посмотрите |
|
| Автор: | GP1 [ Пт июл 27, 2012 09:33:16 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
pierro писал(а): hybroid писал(а): Картинка маленькая за картинку - извините - исправил Программным - это ставит задержки? (а-ля delay_ms(5)) 5 мс мало, они звенят 60-120 мс |
|
| Автор: | oleg110592 [ Пт июл 27, 2012 09:38:43 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
По коду Леонида Ивановича тут еще обсуждалось: http://www.530.ru/wwwboards/mcontrol/21 ... 0755.shtml Лень искать на внешнем винчестере проект, но устройство с энкодером работает без нареканий со стороны заказчика. |
|
| Автор: | Goldsmith [ Пт июл 27, 2012 09:45:22 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
s_black писал(а): Здесь посмотрите Спасибо, посмотрел. Этот вариант понравился гораздо больше - аккуратная автоматная реализация, явно не боящаяся дребезга и дрожания диска.(Разве что я бы еще добавил флаг ошибки при запрещенных переходах, например, из state_0 в state_3: полезно знать о том, что лезут помехи или контроллер не угоняется за скоростью диска; но это уже детали). Вопрос не в том, что в принципе невозможно корректно работать с энкодером (чай не бином Ньютона), а в корректности конкретной реализации, которая предложена как рабочая. |
|
| Автор: | Леонид Иванович [ Пт июл 27, 2012 10:27:53 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
Goldsmith писал(а): Насколько могу судить, при смене состояний AB -> B -> AB -> B ... диск фактически стоит на месте, а программа неуклонно шагает вверх. Поправьте меня, пожалуйста, если я ошибаюсь. Ничего подобного происходить не будет. Для этой ситуации есть проверка EncCur != EncPrevPrev. Наоборот, в этой реализации имеется механический гистерезис. Чтобы произошел инкремент или декремент, должны последовательно пройти 3 состояния энкодера. При дрожании ручки энкодера между двумя соседними состояниями никакого изменения редактируемой величины происходить не будет. Чем, кстати, страдают многие варианты функций обработки энкодера. К тому же, это позволяет отказаться от обычного подавления дребезга, основанного на повторном считывании состояния с задержкой. Такое подавление вызывает пропуски шагов при большой скорости вращения. Данную реализацию обработки сигналов энкодера тестировал на предмет соответствия тактильных ощущений и реакции на поворот энкодера. Ведь для момента переключения можно выбрать разные условия. Остановился именно на таком варианте. Теперь использую его во всех проектах, никаких нареканий нет. Вот полный текст модуля: Код: //----------
//Модуль поддержки энкодера //Энкодер подключается к портам ENC_F1 (фаза 1) и ENC_F2 (фаза 2). //Для подавления дребезга используется анализ двух последовательных //состояний. Это позволяет обойтись без временных задержек. //Функция Encoder_Init() должна вызываться один раз в начале программы. //Функция Encoder_Exe() должна вызываться в основном цикле. //При повороте энкодера на шаг вправо или влево вызываются функции //To_Do_Step_Up() и To_Do_Step_Dn() соответственно. //---------- #include "Main.h" #include "Encoder.h" //---------- Константы: ---------- #define ENC_F1 (1 << PC0) //фаза энкодера F2 #define ENC_F2 (1 << PC1) //фаза энкодера F1 #define Pin_ENC_F1 (PINC & ENC_F1) #define Pin_ENC_F2 (PINC & ENC_F2) enum { State0, StateA, StateB, StateAB }; //состояния энкодера //---------- Переменные: ---------- static char EncPrev; //предыдущее состояние энкодера static char EncPrevPrev; //пред-предыдущее состояние энкодера //---------- Инициализация энкодера: ---------- void Encoder_Init(void) { DDRC &= ~(ENC_F1 | ENC_F2); //настройка портов на ввод PORTC |= ENC_F1 | ENC_F2; //включение подтягивающих резисторов EncPrev = State0; //инициализация предыдущего состояния EncPrevPrev = State0; //инициализация пред-предыдущего состояния } //---------- Обработка энкодера: ---------- void Encoder_Exe(void) { char EncCur = 0; if(!Pin_ENC_F1) EncCur = StateA; //опрос фазы 1 энкодера if(!Pin_ENC_F2) EncCur |= StateB; //опрос фазы 2 энкодера if(EncCur != EncPrev) //если состояние изменилось, { if(EncPrev == StateAB && //если предыдущее состояние StateAB EncCur != EncPrevPrev ) //и текущее и пред-предыдущее не равны, { if(EncCur == StateB) //если текущее состояние StateB, To_Do_Step_Up(); //шаг вверх else //иначе To_Do_Step_Dn(); //шаг вниз } EncPrevPrev = EncPrev; //сохранение пред-предыдущего состояния EncPrev = EncCur; //сохранение предыдущего состояния } } //---------- |
|
| Автор: | Goldsmith [ Пт июл 27, 2012 11:19:38 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
Леонид Иванович писал(а): Ничего подобного происходить не будет. Для этой ситуации есть проверка EncCur != EncPrevPrev. Точно, прошу прощения. Слишком быстро просматривал текст.
|
|
| Автор: | pierro [ Вс июл 29, 2012 13:03:29 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
Спасибо всем. Исправил код - вроде работаєш хорошо.
|
|
| Автор: | makser [ Вс июл 29, 2012 17:53:27 ] |
| Заголовок сообщения: | Re: Енкодер + антидребезг + микроконтролер = "работаю как х |
В STM32 есть аппаратная поддержка энкодера, по этому программно не пройдет защита от дребезга. Проанализировав промсхемы сделал так: В схеме топикстартера последовательно с выходами энкодера поставил резисторы номиналом 15-25% от подтягивающего. Дребез полностью пропал. |
|
| Автор: | Dr. Alex [ Ср янв 15, 2014 02:03:42 ] |
| Заголовок сообщения: | Дребезг контактов и МК |
Ну и как-же, всё-таки, бороться с преславутым дребезгом? Делать задержки, ставить тригерные защёлки.... А каков на самом деле самый изящный метод, применимый и к микроконтроллерам? |
|
| Автор: | pyzhman [ Ср янв 15, 2014 07:38:45 ] |
| Заголовок сообщения: | Re: Дребезг контактов |
Тот же самый, что и при приеме бита по уарту. Три раза прочитали вход, за значение принимаем тот уровень, который встречается два или три раза. Я делаю так: Код: // каждые 20..30 мсек
old_key= key; key= PINX.Y; if(old_key && !key) push= 1; // момент нажатия if(!old_key && key) pop= 1; // момент отпускания if(old_key && key) NotPressed= 1; // не нажата if(!old_key && !key) Pressed= 1; // удерживается нажатой |
|
| Автор: | blackx [ Ср янв 15, 2014 08:05:44 ] |
| Заголовок сообщения: | Re: Дребезг контактов |
Задержки в самой программе - наиболее распространенный и универсальный вариант. Три раза ловить нажатие не нужно, достаточно одного. Суть в том, чтобы после первого сигнала о нажатии заблокировать кнопку на короткое время, чтобы пропустить дребезг. Может быть есть какие-нибудь библиотеки для организации задержки на разных кнопках, для тех же AVR. Думаю, правильная организация защиты от дребезга в программе и будет наиболее изящным решением. Но я таких правильных универсальных решений не знаю, всегда приходится делать по разному под конкретную программу. |
|
| Автор: | КРАМ [ Ср янв 15, 2014 08:11:57 ] |
| Заголовок сообщения: | Re: Дребезг контактов |
pyzhman писал(а): Я делаю так: А кто будет ресетить флаги состояния? else не хватает... blackx писал(а): Суть в том, чтобы после первого сигнала о нажатии заблокировать кнопку на короткое время Это если кнопку. А если произвольный механический контакт, энкодер, например? Там ловля срабатывания по любому фронту чревата "странной" логикой работы... Лучше все таки фильтровать фронт срабатывания буфером на 2...3 бита. |
|
| Автор: | SmarTrunk [ Ср янв 15, 2014 08:35:41 ] |
| Заголовок сообщения: | Re: Дребезг контактов |
Таких тем был миллион, и это не считая тем по дребезгу энкодеров (а это отдельная история): viewtopic.php?f=57&t=5931&start=1680 viewtopic.php?f=20&t=42986 viewtopic.php?f=20&t=50083 viewtopic.php?f=20&t=32&start=6800 viewtopic.php?f=20&t=79801 viewtopic.php?f=59&t=67578&start=820 viewtopic.php?f=20&t=5560&start=2820 (на эту ссылку браузер ругается) ... и т.д., Гугл поможет. Единого рецепта нет, есть разные способы, как программные, так и аппаратные. К слову сказать, есть свежий цикл статей в журнале "Everyday Practical Electronics", называются "Mastering Rotary Encoders", 2013 год, номера 10-12. К сожалению, именно про удаление дребезга энкодера там нет ничего полезного, но просто по удалению дребезга интересно почитать, особенно про раритетные аппаратные способы. Язык - английский. |
|
| Автор: | КРАМ [ Ср янв 15, 2014 08:41:06 ] |
| Заголовок сообщения: | Re: Дребезг контактов |
SmarTrunk писал(а): ...не считая тем по дребезгу энкодеров (а это отдельная история) Делать ее "отдельной историей" не очень удобно... Учитывая общий тик для анализа всей "механики" устройства... |
|
| Страница 1 из 3 | Часовой пояс: UTC + 3 часа |
| Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |
|



