Будет ли простой RC-фильтр работать с механическим поворотным энкодером или понадобится триггер Шмитта?
Я купил в Интернете несколько инкрементальных поворотных энкодеров https://www.bourns.com/docs/Product- Таблицы данных/PEC12R.pdf
В их технических характеристиках указана схема фильтра для выходов кодера, которая выглядит следующим образом:
Добавление этого фильтра уменьшает, но не устраняет паразитные сигналы от кодировщика. Я хотел избежать добавления триггеров Шмитта или других полупроводниковых компонентов, поскольку на моей прототипной плате осталось мало места для микросхемы, но я начинаю думать, что мне придется добавить что-то с гистерезисом, поскольку любой фильтр, который уменьшает джиттер, также замедляет время нарастания/спада на выходе кодера и слишком долго удерживает его в «серой зоне» между НИЗКИМ и ВЫСОКИМ уровнем для цифрового сигнала.
Есть ли способ подключить эти кодеры и/или программное обеспечение, позволяющее считывать данные с помощью простой пассивной фильтрации и/или программного обеспечения, а не добавлять что-то вроде защелки или триггера Шмитта для устранения дребезга?
@Duncan C, 👍0
Обсуждение3 ответа
Похоже, что нет. Я добавил 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
Прежде всего, я бы поставил под сомнение целесообразность устранения ротационного
кодер. Я ожидаю, что контакт отскочит только тогда, когда контакт
переход от HIGH
к LOW
или наоборот. При этом переходе
точки зрения, показания HIGH
и LOW
в некотором смысле верны. А
показания без дребезга должны затем отображать угол поворота, который на короткое время
переключается вперед и назад между двумя последовательными позициями, без
накопительная ошибка.
Я бы посоветовал вам забыть об устранении дребезга и просто посмотреть на состояние изменения. Если вы считаете, что устранение дребезга действительно необходимо, решите его ниже по течению, периодически запрашивать «сырой» ракурс и обновлять «устраненный дребезг» угол:
если необработанный угол отличается от угла устранения дребезга более чем на одну единицу, верните эту разницу к одной единице.
если необработанный угол не изменился с момента фиксированного количества миллисекунд, затем сделайте угол устранения дребезга равным необработанному углу.
Второй момент: вы смотрите не на спадающий фронт входа A, вы
смотрят на восходящие края. Это потому, что pinAState
использует отрицательную логику: это true
, когда вывод имеет значение LOW
. Это не должно
имеют большое значение с точки зрения логики кода.
Третий момент: в вашей логике подсчета есть некоторая ошибка. я не буду пытаться
проанализировать его подробно, как и вся используемая вами концепция устранения дребезжания.
для меня это не имеет смысла, а лишь приводит пример того, как это может потерпеть неудачу.
Предположим, что кодер находится в положении, когда оба входа имеют значение LOW
,
и вы немного покачиваете его, чтобы каждый ввод, в свою очередь, выдавал
позитивный импульс, вот так:
_ _ _ _ _ _
input A __/ \_____/ \_____/ \_____/ \_____/ \_____/ \_____
_ _ _ _ _ _
input B ______/ \_____/ \_____/ \_____/ \_____/ \_____/ \_
rotaryValue 0 | 1 | 2 | 3 | 4 | 5
Здесь rotaryValue
увеличивается по каждому нарастающему фронту входа A, сохраните
для самого первого. В этом случае ожидаемое поведение для этого
чтобы переменная оставалась, скажем, в пределах [−1, +1].
Я только что преследовал проблему с использованием программного обеспечения для устранения дребезга в течение нескольких дней, и я добавлю, что для энкодеров, которые я использовал (зеленые безымянные китайские), если вы подаете 10 мА через контакты, то сигнал намного лучше. Поэтому измените 10 кОм на 470 Ом.
Или при использовании 3,3 В используйте сопротивление 330 Ом. Решил все мои проблемы.
- Кодировщик + Библиотека Bounce2
- Чтение поворотного энкодера с использованием цифровых контактов Mega 2560 напрямую с помощью регистров порта?
- Устранение дребезга кнопки с помощью прерывания
- Хорошая кнопка debouncing/Библиотека StateChange
- Считывание нескольких поворотных энкодеров
- Использование поворотных энкодеров с прерываниями смены контактов
- Выводы прерываний Arduino Mega 2560 и отображение портов с помощью поворотного энкодера
- Управление несколькими светодиодами с помощью нескольких кнопок
Как быстро вы поворачиваете энкодер? Вы измеряете скорость двигателя? Используете его для ввода данных человеком/пользователем?, @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