Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить

Енкодер + антидребезг + микроконтролер = "работаю как хочу"

Чт июл 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;           
            }
       
        }                         
    }
}



есть подозрения что это дребезг контактов на енкодере, но как от него избавится?
Спасибо!
Последний раз редактировалось pierro Чт июл 26, 2012 19:50:35, всего редактировалось 1 раз.

Re: Енкодер + антидребезг + микроконтролер = "работаю как х

Чт июл 26, 2012 19:44:40

Картинка маленькая, ничего не видно.
Пробуйте избавляться программно, статей валом, ищите поиском.

Re: Енкодер + антидребезг + микроконтролер = "работаю как х

Чт июл 26, 2012 19:54:38

hybroid писал(а):Картинка маленькая

за картинку - извините - исправил

Программным - это ставит задержки? (а-ля delay_ms(5))

Re: Енкодер + антидребезг + микроконтролер = "работаю как х

Чт июл 26, 2012 22:00:17

Хотя бы задержки. Алгоритм прост. Словили нажатие, подождали, проверили ещё раз, если осталось - значит окей. Сколько обычно длится дребезг контактов механических энкодеров подскажет ещё кто-то.. Ну или сами поищите, я не помню. Не сильно долго, 5мс это жирно, имхо.

Re: Енкодер + антидребезг + микроконтролер = "работаю как х

Пт июл 27, 2012 07:05:58

Использовал года 2 назад код ув. Леонида Ивановича с обсуждения на сахаре, вроде этот: http://caxapa.ru/207402.html
все работало

Re: Енкодер + антидребезг + микроконтролер = "работаю как х

Пт июл 27, 2012 09:04:38

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

Здесь посмотрите

Re: Енкодер + антидребезг + микроконтролер = "работаю как х

Пт июл 27, 2012 09:33:16

pierro писал(а):
hybroid писал(а):Картинка маленькая

за картинку - извините - исправил

Программным - это ставит задержки? (а-ля delay_ms(5))

5 мс мало, они звенят 60-120 мс

Re: Енкодер + антидребезг + микроконтролер = "работаю как х

Пт июл 27, 2012 09:38:43

По коду Леонида Ивановича тут еще обсуждалось: http://www.530.ru/wwwboards/mcontrol/21 ... 0755.shtml
Лень искать на внешнем винчестере проект, но устройство с энкодером работает без нареканий со стороны заказчика.

Re: Енкодер + антидребезг + микроконтролер = "работаю как х

Пт июл 27, 2012 09:45:22

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

Леонид Иванович писал(а):Ничего подобного происходить не будет. Для этой ситуации есть проверка EncCur != EncPrevPrev.
Точно, прошу прощения. Слишком быстро просматривал текст.

Re: Енкодер + антидребезг + микроконтролер = "работаю как х

Вс июл 29, 2012 13:03:29

Спасибо всем. Исправил код - вроде работаєш хорошо. :beer:

Re: Енкодер + антидребезг + микроконтролер = "работаю как х

Вс июл 29, 2012 17:53:27

В STM32 есть аппаратная поддержка энкодера, по этому программно не пройдет защита от дребезга.
Проанализировав промсхемы сделал так:
В схеме топикстартера последовательно с выходами энкодера поставил резисторы номиналом 15-25% от подтягивающего.
Дребез полностью пропал.

Дребезг контактов и МК

Ср янв 15, 2014 02:03:42

Ну и как-же, всё-таки, бороться с преславутым дребезгом? Делать задержки, ставить тригерные защёлки.... А каков на самом деле самый изящный метод, применимый и к микроконтроллерам?

Re: Дребезг контактов

Ср янв 15, 2014 07:38:45

Тот же самый, что и при приеме бита по уарту. Три раза прочитали вход, за значение принимаем тот уровень, который встречается два или три раза.
Я делаю так:
Код:
// каждые 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

Задержки в самой программе - наиболее распространенный и универсальный вариант. Три раза ловить нажатие не нужно, достаточно одного. Суть в том, чтобы после первого сигнала о нажатии заблокировать кнопку на короткое время, чтобы пропустить дребезг. Может быть есть какие-нибудь библиотеки для организации задержки на разных кнопках, для тех же AVR. Думаю, правильная организация защиты от дребезга в программе и будет наиболее изящным решением. Но я таких правильных универсальных решений не знаю, всегда приходится делать по разному под конкретную программу.

Re: Дребезг контактов

Ср янв 15, 2014 08:11:57

pyzhman писал(а):Я делаю так:

А кто будет ресетить флаги состояния?
else не хватает...
blackx писал(а):Суть в том, чтобы после первого сигнала о нажатии заблокировать кнопку на короткое время

Это если кнопку.
А если произвольный механический контакт, энкодер, например?
Там ловля срабатывания по любому фронту чревата "странной" логикой работы...
Лучше все таки фильтровать фронт срабатывания буфером на 2...3 бита.

Re: Дребезг контактов

Ср янв 15, 2014 08:35:41

Таких тем был миллион, и это не считая тем по дребезгу энкодеров (а это отдельная история):

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. К сожалению, именно про удаление дребезга энкодера там нет ничего полезного, но просто по удалению дребезга интересно почитать, особенно про раритетные аппаратные способы. Язык - английский.
Последний раз редактировалось SmarTrunk Ср янв 15, 2014 08:50:43, всего редактировалось 2 раз(а).

Re: Дребезг контактов

Ср янв 15, 2014 08:41:06

SmarTrunk писал(а):...не считая тем по дребезгу энкодеров (а это отдельная история)

Делать ее "отдельной историей" не очень удобно...
Учитывая общий тик для анализа всей "механики" устройства...
Ответить