Чтение поворотного энкодера с использованием цифровых контактов 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, не дает надежных результатов при нормальной скорости включения элемента управления.
@Duncan C, 👍-1
Обсуждение2 ответа
Похоже, что цифровые контакты 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;
}
Похоже, этот код работает, но значение, которое я получаю от поворотного энкодера, дрейфует.
Вы пробовали какие-нибудь устройства защиты от аппаратных средств, такие как MC14490?
Используя прерывания, вы можете обнаружить все четыре фазы каждого шага кодировщика.
- Выводы прерываний Arduino Mega 2560 и отображение портов с помощью поворотного энкодера
- Будет ли простой RC-фильтр работать с механическим поворотным энкодером или понадобится триггер Шмитта?
- Кодировщик + Библиотека Bounce2
- Регистры ввода-вывода SAM3X8E (Arduino Due)
- Устранение дребезга кнопки с помощью прерывания
- Хорошая кнопка debouncing/Библиотека StateChange
- Считывание нескольких поворотных энкодеров
- Использование поворотных энкодеров с прерываниями смены контактов
Вы ищете полный список? 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