Будет ли простой RC-фильтр работать с механическим поворотным энкодером или понадобится триггер Шмитта?

Я купил в Интернете несколько инкрементальных поворотных энкодеров https://www.bourns.com/docs/Product- Таблицы данных/PEC12R.pdf

В их технических характеристиках указана схема фильтра для выходов кодера, которая выглядит следующим образом:

Добавление этого фильтра уменьшает, но не устраняет паразитные сигналы от кодировщика. Я хотел избежать добавления триггеров Шмитта или других полупроводниковых компонентов, поскольку на моей прототипной плате осталось мало места для микросхемы, но я начинаю думать, что мне придется добавить что-то с гистерезисом, поскольку любой фильтр, который уменьшает джиттер, также замедляет время нарастания/спада на выходе кодера и слишком долго удерживает его в «серой зоне» между НИЗКИМ и ВЫСОКИМ уровнем для цифрового сигнала.

Есть ли способ подключить эти кодеры и/или программное обеспечение, позволяющее считывать данные с помощью простой пассивной фильтрации и/или программного обеспечения, а не добавлять что-то вроде защелки или триггера Шмитта для устранения дребезга?

, 👍0

Обсуждение

Как быстро вы поворачиваете энкодер? Вы измеряете скорость двигателя? Используете его для ввода данных человеком/пользователем?, @jose can u c

Посмотрите даташит. Это энкодеры, повернутые вручную., @CrossRoads

Дубликат вопроса здесь https://electronics.stackexchange.com/questions/423688/how-do-you-pick-comComponent-values-for-a-debouncing-filter/423695?noredirect=1#comment1052330_423695, @CrossRoads

@CrossRoads, это плохой тон задавать похожие вопросы на разных сайтах Stack Exchange? Мой вопрос на сайте SE по электронике начался с вопроса о выборе номиналов компонентов, а затем перерос в более общий вопрос об устранении дребезга. Эта тема специально посвящена тому, как устранить дребезг моего ротационного кодирования для использования с Arduino., @Duncan C

Пробовали ли вы эту библиотеку https://github.com/buxtronix/arduino/tree/master/libraries/Rotary с прерыванием.ino https://github.com/buxtronix/arduino/blob/master/libraries/Rotary/examples /interrupt/interrupt.ino эскиз?, @VE7JRO

Я видел схемы, в которых добавляли диод, поэтому конденсатор заряжается/разряжается мгновенно, но в других направлениях подвергается RC-фильтрации. В вашем случае ваши прерывания срабатывают по спаду, поэтому вы подключаете диод через переключатель к земле, и подтягивающий резистор «медленно» заряжает конденсатор обратно, когда переключатель разомкнут. Не уверен, что это действительно «лучше»., @Gerben

Какая у вас проблема: слишком быстро (дрожание) или слишком медленно (отсутствуют щелчки)? GPIO обычно не меняют ни копейки, и при необходимости вы можете настроить значения rc, чтобы отрегулировать время фронта., @dandavis

«Какая у вас проблема: слишком быстро (дрожание) или слишком медленно (отсутствуют щелчки)». Кажется, что это дрожание, но это немного сложно сказать. Джиттер произойдет, даже если сигнал устранен, если наклон переходов высокий/низкий и низкий/высокий слишком плавный и слишком много времени находится в «запретной зоне» промежуточных напряжений. (Я думаю, именно это и происходит.), @Duncan C

Я только что добавил в свою схему триггер Шмитта в дополнение к RC-фильтру, показанному в моем вопросе (MC14584BCP). Кажется, это устраняет дрожание, но иногда кажется, что он по-прежнему занижается или завышается. (Используя ISR, который считывает контакты с помощью регистров порта, поэтому он должен быть достаточно быстрым.), @Duncan C

Смотрите мой ответ и редактирование к нему. Должно быть возможно выполнить устранение дребезга в программном обеспечении, и код очень близок, но не совсем там., @Duncan C


3 ответа


2

Похоже, что нет. Я добавил RC-фильтр, предложенный производителем, и результаты по-прежнему скачут (иногда значения увеличиваются на несколько шагов сразу или уменьшаются даже при повороте декодера по часовой стрелке).

Я добавил триггер Шмитта КМОП, и это решило проблему.

Я действительно не понимаю, почему это так, поскольку, очевидно, цифровые входы Arduino имеют встроенные триггеры Шмитта. В этой теме на форуме Arduino это подробно обсуждается:

http://forum.arduino.cc/index.php?topic=452599.15

Единственное, о чем я могу думать, это то, что полоса гистерезиса встроенных триггеров Шмитта слишком узкая (2,08–2,63 В при VCC 5 В и типичных рабочих условиях), и отфильтрованное напряжение все еще колеблется между этими значениями.< /п>

Я использую триггер Шмитта MC14584B, который у меня лежал, и похоже, что его полоса гистерезиса составляет от ≈2,1 В до 2,7 В (типично при 25 ° C), что немного шире r и немного превышает гистерезис. диапазон самого Arduino.

Однако различия кажутся довольно небольшими, поэтому я не понимаю, почему триггер Шмитта устраняет «качание»; ценностей, которые я вижу.

Я мог бы добавить код устранения дребезга на основе задержки в свою программу Arduino, но обработчик декодера написан как ISR, и он должен быть максимально быстрым, а функция millis() должна быть довольно медленной, поэтому сложно.

РЕДАКТИРОВАТЬ:

Я задал похожий вопрос относительно значений компонентов фильтра при обмене стеком EE, и кто-то там заметил, что я должен видеть только «отскок»; по одному выводу за раз, и что я смогу отклонять ложные изменения исключительно с помощью программного обеспечения. Я пытаюсь сделать это сейчас.

Мой новый код выглядит так:

bool rotaryValueChanged = false;

bool pinAHasChanged = false;
bool pinBHasChanged = false;

enum ChangeTypes {
  fallingA, 
  changingA, 
  changingAOrB
  };
ChangeTypes changesToDetect = fallingA;


void encode() {
  pinAHasChanged = true;
  //Прочитайте PinA & PinB (цифровые контакты 2 и 3) с использованием регистра порта PINE, 4-й и 5-й бит.
  //Быстрый эквивалент pinAState = digitalRead(rotaryPinA) == LOW
  bool pinAState = (PINE & (1 << 4)) == 0;
  bool pinBState = (PINE & (1 << 5)) == 0;
  //Игнорировать изменения состояния контакта A, если только контакт B не изменился с момента последнего изменения.
  //Также обращайте внимание, только если это спадающий фронт
  //или мы отслеживаем изменения как нарастающего, так и падающего фронта
  if (pinBHasChanged && (pinAState == false || changesToDetect != fallingA)) {
    rotaryValue +=  (pinAState == pinBState) ? -1 : 1;
    rotaryValueChanged = true;
    pinBHasChanged = false;
  } 
}

void encodePinB() {
  pinBHasChanged = true;

  //Если мы не считаем 48 тактов/вращение, не учитывайте изменения PinB.
  if (changesToDetect != changingAOrB) { 
    return; 
  }
  //Прочитайте PinA & PinB (цифровые контакты 2 и 3) с использованием регистра порта PINE, 4-й и 5-й бит.
  bool pinAState = (PINE & (1 << 4)) == 0;
  bool pinBState = (PINE & (1 << 5)) == 0;

  //Игнорируем изменения состояния контакта B, если только контакт A не изменился с момента последнего изменения
  if (pinAHasChanged) {
    rotaryValue +=  (pinAState != pinBState) ? -1 : 1;
    rotaryValueChanged = true;
  } 
}

void setup() {
  attachInterrupt(digitalPinToInterrupt(rotaryPinA), encode, CHANGE);//ПАДЕНИЕ
  attachInterrupt(digitalPinToInterrupt(rotaryPinB), encodePinB, CHANGE);
  //Больше кода настройки здесь...
}

Этот код написан для обработки трех возможных вариантов:

  • Изменяется только состояние заднего фронта на выводе A (12 шагов/поворот)
  • Изменение возрастания или понижения контакта A (24 шага/поворот)
  • Изменение состояния подъема или спада на любом выводе (48 шагов/поворот).

Ключевая часть этого — наличие прерываний на обоих выводах. Когда один вывод изменяется, его обработчик прерывания устанавливает сообщение «этот вывод изменен». bool к истине. В ISR (программе обслуживания прерываний) для другого вывода он обращает внимание на изменение состояния только в том случае, если изменился другой вывод. Таким образом, когда контакт A меняет состояние, если он отскакивает, другой контакт не должен отскакивать в то же время, и поэтому, если контакт B не изменился, я могу просто игнорировать дополнительные изменения в контакте A и обрабатывать свое устранение дребезга в программном обеспечении, и без необходимости для выполнения временных задержек, которые слишком медленны для ISR.

Однако приведенный выше код не совсем работает. Иногда я получаю ложные показания обратного вращения. Если я вращаю энкодер по часовой стрелке, значения, которые я получаю, увеличиваются одно за другим, как и ожидалось, но иногда уменьшаются на 1, а затем возвращаются к увеличению.

Что я делаю не так?

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

р>

Мой тестовый пример подсчитывает только переходы по заднему фронту для контакта A моего энкодера, поэтому обнаружение ложных показаний вращения против часовой стрелки позволяет предположить, что иногда контакт B меняет состояние одновременно с контактом B. Этого не должно происходить, поэтому Я в замешательстве.

,

Взгляните на аппаратный дебаунсер [MC14490](https://www.onsemi.com/pub/Col Lateral/MC14490-D.PDF)., @Alexander


1

Прежде всего, я бы поставил под сомнение целесообразность устранения ротационного кодер. Я ожидаю, что контакт отскочит только тогда, когда контакт переход от HIGH к LOW или наоборот. При этом переходе точки зрения, показания HIGH и LOW в некотором смысле верны. А показания без дребезга должны затем отображать угол поворота, который на короткое время переключается вперед и назад между двумя последовательными позициями, без накопительная ошибка.

Я бы посоветовал вам забыть об устранении дребезга и просто посмотреть на состояние изменения. Если вы считаете, что устранение дребезга действительно необходимо, решите его ниже по течению, периодически запрашивать «сырой» ракурс и обновлять «устраненный дребезг» угол:

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

  • если необработанный угол не изменился с момента фиксированного количества миллисекунд, затем сделайте угол устранения дребезга равным необработанному углу.

Второй момент: вы смотрите не на спадающий фронт входа A, вы смотрят на восходящие края. Это потому, что pinAState использует отрицательную логику: это true, когда вывод имеет значение LOW. Это не должно имеют большое значение с точки зрения логики кода.

Третий момент: в вашей логике подсчета есть некоторая ошибка. я не буду пытаться проанализировать его подробно, как и вся используемая вами концепция устранения дребезжания. для меня это не имеет смысла, а лишь приводит пример того, как это может потерпеть неудачу. Предположим, что кодер находится в положении, когда оба входа имеют значение LOW, и вы немного покачиваете его, чтобы каждый ввод, в свою очередь, выдавал позитивный импульс, вот так:

                _       _       _       _       _       _
input A      __/ \_____/ \_____/ \_____/ \_____/ \_____/ \_____
                    _       _       _       _       _       _
input B      ______/ \_____/ \_____/ \_____/ \_____/ \_____/ \_

rotaryValue      0     |   1   |   2   |   3   |   4   |   5

Здесь rotaryValue увеличивается по каждому нарастающему фронту входа A, сохраните для самого первого. В этом случае ожидаемое поведение для этого чтобы переменная оставалась, скажем, в пределах [−1, +1].

,

3

Я только что преследовал проблему с использованием программного обеспечения для устранения дребезга в течение нескольких дней, и я добавлю, что для энкодеров, которые я использовал (зеленые безымянные китайские), если вы подаете 10 мА через контакты, то сигнал намного лучше. Поэтому измените 10 кОм на 470 Ом.

Или при использовании 3,3 В используйте сопротивление 330 Ом. Решил все мои проблемы.

,