Страница 1 из 3
Енкодер + антидребезг + микроконтролер = "работаю как хочу"
Добавлено: Чт июл 26, 2012 19:29:08
pierro
Прошу помощи или подскажите в какую сторону копать
Есть енкодер, подключенный к микроконтроллеру(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;
}
}
}
}
есть подозрения что это дребезг контактов на енкодере, но как от него избавится?
Спасибо!
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Чт июл 26, 2012 19:44:40
hybroid
Картинка маленькая, ничего не видно.
Пробуйте избавляться программно, статей валом, ищите поиском.
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Чт июл 26, 2012 19:54:38
pierro
hybroid писал(а):Картинка маленькая
за картинку - извините - исправил
Программным - это ставит задержки? (а-ля delay_ms(5))
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Чт июл 26, 2012 22:00:17
hybroid
Хотя бы задержки. Алгоритм прост. Словили нажатие, подождали, проверили ещё раз, если осталось - значит окей. Сколько обычно длится дребезг контактов механических энкодеров подскажет ещё кто-то.. Ну или сами поищите, я не помню. Не сильно долго, 5мс это жирно, имхо.
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Пт июл 27, 2012 07:05:58
oleg110592
Использовал года 2 назад код ув. Леонида Ивановича с обсуждения на сахаре, вроде этот:
http://caxapa.ru/207402.htmlвсе работало
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Пт июл 27, 2012 09:04:38
Goldsmith
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 ... диск фактически стоит на месте, а программа неуклонно шагает вверх. Поправьте меня, пожалуйста, если я ошибаюсь.
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Пт июл 27, 2012 09:12:26
s_black
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Пт июл 27, 2012 09:33:16
GP1
pierro писал(а):hybroid писал(а):Картинка маленькая
за картинку - извините - исправил
Программным - это ставит задержки? (а-ля delay_ms(5))
5 мс мало, они звенят 60-120 мс
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Пт июл 27, 2012 09:38:43
oleg110592
По коду Леонида Ивановича тут еще обсуждалось:
http://www.530.ru/wwwboards/mcontrol/21 ... 0755.shtmlЛень искать на внешнем винчестере проект, но устройство с энкодером работает без нареканий со стороны заказчика.
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Пт июл 27, 2012 09:45:22
Goldsmith
s_black писал(а):Здесь посмотрите
Спасибо, посмотрел. Этот вариант понравился гораздо больше - аккуратная автоматная реализация, явно не боящаяся дребезга и дрожания диска.
(Разве что я бы еще добавил флаг ошибки при запрещенных переходах, например, из state_0 в state_3: полезно знать о том, что лезут помехи или контроллер не угоняется за скоростью диска; но это уже детали).
Вопрос не в том, что в принципе невозможно корректно работать с энкодером (чай не бином Ньютона), а в корректности конкретной реализации, которая предложена как рабочая.
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Пт июл 27, 2012 10:27:53
Леонид Иванович
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; //сохранение предыдущего состояния
}
}
//----------
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Пт июл 27, 2012 11:19:38
Goldsmith
Леонид Иванович писал(а):Ничего подобного происходить не будет. Для этой ситуации есть проверка EncCur != EncPrevPrev.
Точно, прошу прощения. Слишком быстро просматривал текст.
Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Вс июл 29, 2012 13:03:29
pierro
Спасибо всем. Исправил код - вроде работаєш хорошо.

Re: Енкодер + антидребезг + микроконтролер = "работаю как х
Добавлено: Вс июл 29, 2012 17:53:27
makser
В STM32 есть аппаратная поддержка энкодера, по этому программно не пройдет защита от дребезга.
Проанализировав промсхемы сделал так:
В схеме топикстартера последовательно с выходами энкодера поставил резисторы номиналом 15-25% от подтягивающего.
Дребез полностью пропал.
Дребезг контактов и МК
Добавлено: Ср янв 15, 2014 02:03:42
Dr. Alex
Ну и как-же, всё-таки, бороться с преславутым дребезгом? Делать задержки, ставить тригерные защёлки.... А каков на самом деле самый изящный метод, применимый и к микроконтроллерам?
Re: Дребезг контактов
Добавлено: Ср янв 15, 2014 07:38:45
pyzhman
Тот же самый, что и при приеме бита по уарту. Три раза прочитали вход, за значение принимаем тот уровень, который встречается два или три раза.
Я делаю так:
Код: Выделить всё
// каждые 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; // удерживается нажатой
Re: Дребезг контактов
Добавлено: Ср янв 15, 2014 08:05:44
blackx
Задержки в самой программе - наиболее распространенный и универсальный вариант. Три раза ловить нажатие не нужно, достаточно одного. Суть в том, чтобы после первого сигнала о нажатии заблокировать кнопку на короткое время, чтобы пропустить дребезг. Может быть есть какие-нибудь библиотеки для организации задержки на разных кнопках, для тех же AVR. Думаю, правильная организация защиты от дребезга в программе и будет наиболее изящным решением. Но я таких правильных универсальных решений не знаю, всегда приходится делать по разному под конкретную программу.
Re: Дребезг контактов
Добавлено: Ср янв 15, 2014 08:11:57
КРАМ
pyzhman писал(а):Я делаю так:
А кто будет ресетить флаги состояния?
else не хватает...
blackx писал(а):Суть в том, чтобы после первого сигнала о нажатии заблокировать кнопку на короткое время
Это если кнопку.
А если произвольный механический контакт, энкодер, например?
Там ловля срабатывания по любому фронту чревата "странной" логикой работы...
Лучше все таки фильтровать фронт срабатывания буфером на 2...3 бита.
Re: Дребезг контактов
Добавлено: Ср янв 15, 2014 08:35:41
SmarTrunk
Таких тем был миллион, и это не считая тем по дребезгу энкодеров (а это отдельная история):
viewtopic.php?f=57&t=5931&start=1680viewtopic.php?f=20&t=42986viewtopic.php?f=20&t=50083viewtopic.php?f=20&t=32&start=6800viewtopic.php?f=20&t=79801viewtopic.php?f=59&t=67578&start=820viewtopic.php?f=20&t=5560&start=2820 (на эту ссылку браузер ругается)
...
и т.д., Гугл поможет.
Единого рецепта нет, есть разные способы, как программные, так и аппаратные.
К слову сказать, есть свежий цикл статей в журнале "Everyday Practical Electronics", называются "Mastering Rotary Encoders", 2013 год, номера 10-12. К сожалению, именно про удаление дребезга энкодера там нет ничего полезного, но просто по удалению дребезга интересно почитать, особенно про раритетные аппаратные способы. Язык - английский.
Re: Дребезг контактов
Добавлено: Ср янв 15, 2014 08:41:06
КРАМ
SmarTrunk писал(а):...не считая тем по дребезгу энкодеров (а это отдельная история)
Делать ее "отдельной историей" не очень удобно...
Учитывая общий тик для анализа всей "механики" устройства...