Выводы прерываний Arduino Mega 2560 и отображение портов с помощью поворотного энкодера

Я пытаюсь использовать манипуляции с портами в прерываниях для чтения поворотного энкодера. Я нашел код для Uno, поэтому вызов порта для контактов 2 и 3 различен. Я думаю, что на Меге это PORTH3 и PORTH4 соответственно. Мой код не работает. У меня неправильные порты? Я пробовал читать об этом, но не до конца понимаю часть Bxxxxxxxx. Я думаю, что это может быть неправильно. Вот часть моего кода с одним из прерываний.

static int pinA = 2;
// Наш первый вывод аппаратного прерывания — цифровой вывод 2
static int pinB = 3;
// Наш второй вывод аппаратного прерывания — цифровой вывод 3
volatile byte aFlag = 0;
// сообщаем нам, когда мы ожидаем, что нарастающий фронт на выводе pinA будет сигнализировать о том, что энкодер достиг фиксации
volatile byte bFlag = 0;
// сообщаем нам, когда мы ожидаем, что нарастающий фронт на выводе B будет сигнализировать о том, что энкодер достиг фиксации (направление, противоположное тому, когда установлен aFlag)
volatile byte encoderPos = 0;
//эта переменная хранит наше текущее значение позиции энкодера. Измените значение на int или uin16_t вместо byte, если вы хотите записать больший диапазон, чем 0–255.
volatile byte oldEncPos = 0;
//сохраняет последнее значение позиции энкодера, чтобы мы могли сравнить его с текущим показанием и посмотреть, изменилось ли оно (чтобы мы знали, когда печатать на последовательный монитор)
volatile byte reading = 0;

void setup () {
  pinMode(pinA, INPUT);
  // устанавливаем контакт A в качестве входа, вытягиваем ВЫСОКИЙ уровень логического напряжения (5 В или 3,3 В в большинстве случаев)
  pinMode(pinB, INPUT);
  attachInterrupt(0, PinA, RISING);
  // устанавливаем прерывание на PinA,
  // ищем нарастающий фронт сигнала и выполняем процедуру обслуживания прерываний «PinA» (ниже)
  attachInterrupt(1, PinB, RISING);
  // устанавливаем прерывание на PinB,
  // ищем нарастающий фронт сигнала и выполняем процедуру обслуживания прерываний «PinB» (ниже)
}

void PinA() {
  //CCW
  cli();
  //прекращаем прерывания до того, как мы прочитаем значения контактов
  reading = PORTH & 0xC;
  // считываем значения всех восьми контактов, затем удаляем все значения, кроме значений pinA и pinB
  if (reading == B00001100 && aFlag) {
    //проверяем, что оба контакта зафиксированы (ВЫСОКИЙ) и что мы ожидаем фиксации на нарастающем фронте этого контакта
    encoderPos --; //уменьшаем счетчик позиций кодировщика
    bFlag = 0; //сбрасываем флаги для следующего хода
    aFlag = 0; //сбрасываем флаги для следующего хода
  } else if (reading == B00000100) bFlag = 1;
  //сигнал того, что мы ожидаем, что вывод pinB сигнализирует о переходе в фиксацию из свободного вращения
  sei(); //перезапускаем прерывания
}

, 👍2

Обсуждение

У вас когда-нибудь это работало? Я тоже хотел использовать Arduino Mega для отслеживания углового положения энкодера Omron с тремя прерываниями. Одно из прерываний для сброса индекса в 0 каждый раз, когда он совершает один оборот. Я хочу использовать его для отслеживания вращающейся мачты для определения направления. Есть куски кода, но ничего полного. Ваш полный? [email protected], @Bkukuk62


2 ответа


1

Что касается контактов 2 и 3, они разные. Я думаю, что на Mega это PORTH3 и PORTH4 соответственно», это правда, что цифровые контакты Arduino 2 и 3 относятся к разным портам на платах Uno и Mega2560.

У Mega2560 шесть контактов INTx, а у Uno их два. В Mega INT0...INT3 — это PD0…PD3, а INT4,INT5 — это PE4,PE5. В Uno INT0,INT1 — это PD2,PD3. Обратите внимание: в ответе на Могут ли внешние прерывания объединяться по ИЛИ на '328 (Uno)? я показываю пару подпрограмм, которые будут отображать соответствующие маски. для контактов на разных ардуино. См. разделы «Использование других контактов для PCI» и «Скетч, генерирующий ISR-фреймворк».


Вот несколько проблем с кодом, показанным в вопросе:

  1. aFlag инициализируется нулевым значением и никогда не устанавливается ненулевым в показанном коде. Таким образом, первое условие if в PinA() никогда не выполняется.

  2. PinA() — это обработчик прерываний, подключенный к прерываниям с помощью вызовов attachInterrupt(). Поскольку аппаратное обеспечение отключает прерывания до того, как они попадут в обработчик прерываний, обработчику прерываний нет необходимости отключать прерывания. То есть удалите cli() в PinA(). Аналогичным образом удалите sei() в конце PinA(), поскольку аппаратное обеспечение восстанавливает статус прерывания при выполнении инструкции RETI.

  3. Программная среда Arduino определяет константы типа B00001100 с двоичными значениями, соответствующими имени. То есть в программной среде Arduino константа B00001100 имеет значение 0B00001100. На мой взгляд, это глупая и ненужная функция; Я предлагаю использовать в вашем коде стандартную нотацию C, например 0B00001100, если вы хотите использовать значения двоичных констант.

  4. Я считаю извращением написание encoderPos -- вместо encoderPos-- и предлагаю удалить это ненужное пространство.

  5. Поскольку вы не показали обработчик прерываний PinB(), я не знаю, как вы собираетесь обрабатывать случай encoderPos++. Судя по показанному коду, вы используете метод, который неправильно обрабатывает отказы и периодические ошибки. Я предлагаю использовать прерывания по смене контактов и метод конечного автомата, как показано в ответах на:
    Чтение с поворотного энкодера KY-040 с помощью Digispark
    Как считать RPS для быстрого вращения с помощью метода изменения статуса в Arduino?
    Чтение каналов приемника RC с использованием прерывания вместо PulseIn
    Могут ли внешние прерывания объединяться по логическому ИЛИ в '328 (Uno)?

,

0

На мега-памяти можно было читать с помощью PINE.

Итак, ваш код в PinA изменится на:

reading = PINE & 0b00110000;

  if(reading == 0b00110000 && aFlag) 

  {  encoderPos --;
    bFlag = 0;
    aFlag = 0;
  }
  else if (reading == 0b00010000) bFlag = 1;

Здесь я нашел отличное обсуждение необходимой маскировки: https://forum.arduino.cc/index .php?topic=561741.0

,