Чтение поворотного энкодера с использованием цифровых контактов Mega 2560 напрямую с помощью регистров порта?

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

Затем мне нужно посмотреть на значение на выводе 3 и посмотреть, является ли оно высоким или низким, чтобы определить, в каком направлении поворачивается энкодер. Я построил простую схему подавления дребезга, используя пару резисторов и конденсатор 0,01 мкФ на линию от энкодера, так что теперь эти сигналы чистые.

Исходя из того, что я сделал, лучше считывать состояния выводов напрямую, а не использовать digitalRead в ISR, поскольку функция digitalRead() довольно медленная.

Мне трудно найти и выяснить сопоставления портов для регистров портов для чтения контактов.

Я считаю, что мне следует использовать

(PIND & (1 << 3) != 0 для чтения цифрового контакта 3, так как я думаю, что контакты 2-9 находятся в регистре PIND?

Я нашел эту диаграмму https://www.arduino.cc/en/Hacking/PinMapping2560, в которой перечислены сопоставление контактов для Mega 2560, но я не уверен, как его прочитать.

Если я использую bool pinBState = digitalRead(rotaryPinB) == LOW в своем ISR, он работает, но иногда он пропускает изменения состояния.

Если вместо этого я использую код `bool pinBState = (PIND & (1 << 3)) == 0;

Значение pinBState никогда не меняется.

Может ли кто-нибудь сказать мне, что я делаю неправильно?

См. ответ ниже. Кажется, что цифровые контакты 0–7 считываются из PINE, а не из PIND.

Однако теперь у меня новая проблема:

С кодом, показанным в моем ответе, я получаю показания, которые увеличиваются при вращении по часовой стрелке и уменьшаются при вращении против часовой стрелки, как и ожидалось:

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

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

https://www.bourns.com/docs/Product-Datasheets/PEC11R.pdf

Схема выглядит так:

Разве эта схема не должна работать? Я подключил его на макетной плате, и у меня довольно длинные провода, и я не обрезал провода на резисторах или конденсаторах, так как это все еще тестовая схема. Я бы не подумал, что это будет чувствительно к радиочастотному шуму. Единственное, что у меня есть в проекте, это ЖК-дисплей I2C. Я трижды проверил свою проводку и не думаю, что сделал какие-либо ошибки.

Я не понимаю, почему управляемый прерываниями поворотный энкодер с рекомендованной схемой подавления дребезга, который считывает регистры порта для считывания данных с PIN-кода B, не дает надежных результатов при нормальной скорости включения элемента управления.

, 👍-1

Обсуждение

Вы ищете полный список? https://forum.arduino.cc/index.php?topic=52534.0, @VE7JRO

Нет, я видел эту страницу, но ничего не понял. Мне нужно знать, какой код использовать для считывания значения цифрового вывода 2 на моем Mega 2560. Некоторое обучение тому, как читать эти таблицы, было бы хорошим плюсом, но сейчас моя цель очень узкая: заставить это единственное считывание работать. ., @Duncan C

Цифровой контакт 2 - это PE4 ... это 5-й бит порта E., @jsotola

Чем это отличается от того, что вы здесь спросили? https://electronics.stackexchange.com/questions/423688/how-do-you-pick-component-values-for-a-debouncing-filter/423695?noredirect=1#comment1052330_423695, @CrossRoads

Цифровые контакты 2 и 4 имеют аппаратные прерывания. Почему бы не использовать оба прерывания? Это как бы перебор, но у меги они есть, так почему бы их не использовать. Что касается вашей текущей проблемы; Вы пропустили шаги, поэтому либо ваш код слишком медленный, либо фильтр подавления дребезга слишком силен. Последнее можно легко проверить, используя конденсаторы меньшего размера. Если rotaryValue и int? Определяется ли он как «изменчивый»?, @Gerben

Почему голосование против?, @Duncan C

Гербен, мою программу можно настроить так, чтобы она считывала только задний фронт 1 вывода (12 шагов), задний фронт обоих выводов (24 шага) или нарастающий и спадающий фронт обоих выводов (48 шагов). Для 12-шагового декодирования я помещаю прерывание только на один контакт и считываю состояние другого контакта, чтобы определить направление вращения. В других случаях я устанавливаю прерывания на оба контакта., @Duncan C


2 ответа


1

Похоже, что цифровые контакты 0–7 считываются из регистра PINE (это PIN E), а не из PIND.

Я настраиваю свои контакты в качестве входных данных, используя обычный код Arduino:

#define rotaryPinA 2
#define rotaryPinB 3

void setup() {
  attachInterrupt(digitalPinToInterrupt(rotaryPinA), encode, FALLING);

  pinMode(rotaryPinA, INPUT);
  pinMode(rotaryPinB, INPUT);
  // Остальная часть функции настройки
}

И затем мой метод кодирования:

void encode() {
  rotaryValueChanged = true;
  //Чтение моего PinB (цифровой контакт 3) с помощью регистра порта PINE, 5-й бит
  bool pinBState = (PINE & (1 << 5)) == 0;
  //Вот эквивалентный код с использованием digitalRead:
  // bool pinBState = digitalRead(rotaryPinB) == LOW;
  rotaryValue +=  pinBState ? -1 : 1;
}

Похоже, этот код работает, но значение, которое я получаю от поворотного энкодера, дрейфует.

,

0

Вы пробовали какие-нибудь устройства защиты от аппаратных средств, такие как MC14490?
Используя прерывания, вы можете обнаружить все четыре фазы каждого шага кодировщика.

,