Почему мой код прерывания не работает?

Фон

Я пытаюсь написать код для чтения сигналов с шестиканального RC-приемника на Arduino Mega 2560. В настоящее время я сохраняю код для чтения только одного канала, чтобы упростить устранение неполадок. Проблема в том, что моя общая переменная не обновляется, что наводит меня на мысль, что моя процедура обработки прерываний не обнаруживает никаких нарастающих фронтов.

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

Я использовал Serial.print(), чтобы проверить, обновляется ли моя переменная volatile channel (то есть, изменяется ли ее значение на значение флага канала 1). Она не обновлялась, поэтому моя ISR должна быть неправильной. Вы можете найти исходный код в сообщении в блоге.

Что случилось? У меня нет идей.

#include <PinChangeInt.h>

//Назначение выводов
#define channel1PIN 10

//Битовые флаги
#define Channel1FLAG 1

//Держатель флага
volatile uint8_t bFLAGUPDATESHARED;

//Общие переменные: Доступ к ним осуществляется процедурой обработки прерываний и чтение в «пустом цикле».
volatile uint16_t unCHANNEL1SHARED;

//Переменные времени начала: они используются для установки времени начала нарастающего фронта
// импульс. Доступ к ним возможен только через ISR, поэтому они являются беззнаковыми целыми числами и
//не летучие вещества.

uint32_t ulCHANNEL1START;

void setup()
{
  Serial.begin(9600);
  Serial.print("RC Channel PWM Read Interrupt Test");

  //Функция библиотеки PinChangInt. Используется для установки прерываний присоединения.
  PCintPort::attachInterrupt(channel1PIN, calcCHANNEL1, CHANGE);
}

void loop()
{
  //Внутрицикловые переменные для хранения локальных копий входов каналов.
  //Это статическое значение, поэтому оно сохраняет значения между циклами вызовов.
  static uint16_t unCHANNEL1IN;

  //Внутрицикловая копия держателя изменчивого флага bSHAREDFLAGUPDATE
  static uint8_t bFLAGUPDATELOCAL;

  //Проверьте, получили ли какие-либо каналы сигналы. Если да, скопируйте
  //общие переменные в локальные переменные цикла.
  if (bFLAGUPDATESHARED)
  {
    //Отключить прерывания при копировании общих переменных в локальные переменные
    noInterrupts();

    bFLAGUPDATELOCAL = bFLAGUPDATESHARED;

    if (bFLAGUPDATELOCAL & Channel1FLAG)
    {
      unCHANNEL1IN = unCHANNEL1SHARED;
    }

    bFLAGUPDATESHARED = 0;
    interrupts();
  }

  Serial.println(unCHANNEL1IN);

  //Очистить локальные флаги обновления, поскольку все значения были скопированы в локальные переменные
  bFLAGUPDATELOCAL = 0;
}

void calcCHANNEL1()
{
  if (digitalRead(channel1PIN) == HIGH)
  {
    //Если вывод становится высоким, запускаем таймер и устанавливаем ulCHANNEL1START на запуск таймера
    ulCHANNEL1START = micros();
  }
  else
  {
    //Если он не растет, значит, он падает, поэтому устанавливаем общий
    //переменная для текущего времени-время начала
    unCHANNEL1SHARED = (uint16_t)(micros() - ulCHANNEL1START);

    // Сообщаем, что канал 1 получил сигнал
    bFLAGUPDATESHARED |= Channel1FLAG;
  }
}

, 👍2

Обсуждение

Попробуйте упростить код. Пусть ISR зажигает светодиод, например. Я не вижу ничего изначально неправильного., @Gerben

Я разобрался. По какой-то причине он работает только на пинах 10,11 и 12. Я не знаю почему. PinchangeInt должен работать на любом цифровом пине, @Ozymandias

Но вы используете пин 10? В любом случае, рад, что у вас все заработало., @Gerben


2 ответа


Лучший ответ:

4

Только некоторые порты на Atmega2560 поддерживают прерывания по изменению состояния контактов, в частности порты B, E (бит 0), J (биты с 0 по 6) и K.

Глядя на референсную схему, можно увидеть, что эти контакты на плате поддерживаются:

     Chip
Name  Pin  Pin on board
-----------------------

Port B

PB0 - 19 - D53 (SS)
PB1 - 20 - D52 (SCK)
PB2 - 21 - D51 (MOSI)
PB3 - 22 - D50 (MISO)
PB4 - 23 - D10 
PB5 - 24 - D11
PB6 - 25 - D12
PB7 - 26 - D13

Port E

PE0 - 2 - D0 (RXD0)

Port J

PJ0 - 63 - D15 (RXD3)
PJ1 - 64 - D14 (TXD3)
PJ2 to PJ6 - not connected on board

Port K

PK0 - PK7 - (89 - 82)  - A8 - A15

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


Серийный номер ПО

Вы можете увидеть подтверждение на странице SoftwareSerial, где говорится:

Не все контакты на Mega и Mega 2560 поддерживают прерывания изменения, поэтому для RX можно использовать только следующие: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69).

Это связано с тем, что SoftwareSerial использует прерывания по смене контактов для обнаружения входящих последовательных данных, поэтому на этой странице есть отказ от ответственности за то, с какими контактами он будет работать.


Распиновка Atmega2560

Распиновка Atmega2560


PinchangeInt должен работать с любым цифровым PIN-кодом

Обратите внимание, что Atmega328P (используемый в Uno) имеет меньше портов, и все они доступны для прерываний по смене контактов на этой плате.

,

2

В ATmega1280/2560 только порты B, J, F и K имеют возможность прерывания смены пина. Они примерно соответствуют выводам 10–15, 50–53 и A6–A15 (хотя часть порта J не сопоставлена с выводами Arduino, поэтому PCINT11–PCINT15 недоступны на Arduino Mega/Mega 2560).

,