Отмена состояния кода перед прерыванием

В настоящее время в моем коде Arduino есть два цикла.

В некоторых случаях я перехожу от цикла 1 к циклу 2

У меня также есть ISR

Когда мое условие ISR выполняется, код выполняется, и часть кода ISR должна перейти в цикл 1. Что он и делает, но...

Затем я соответствующим образом закрываю ISR, но процедура обслуживания возвращается к циклу 2.

Есть идеи, почему?

Я сижу в Интернете последние пару часов и не поймал ни одной волны..

Спасибо всем.

//Физические переменные
int eStop = 3;         // номер входного контакта
int eStopLED = 9;       // номер выходного контакта

int dispenseButton = 6;         // номер входного контакта
int dispenseLED = 8;       // номер выходного контакта

// иметь 789 для цветов и 3456 только для ввода 3 ND 6 НЕОБХОДИМО ИСПОЛЬЗОВАТЬ

int eStopZone = HIGH;      // текущая eStopZone выходного вывода
int eStopScan;           // текущий eStopScan с входного вывода
int eStopPrior = LOW;    // eStopPrior eStopScan с входного контакта

int dispenseZone = HIGH;      // текущая eStopZone выходного вывода
int dispenseScan;           // текущий eStopScan с входного вывода
int dispensePrior = LOW;    // eStopPrior eStopScan с входного контакта


//Другие переменные
volatile int vControl = 0;
int eVar;
int i; //Нормальное числовое значение


// быстро станет большим числом, чем может быть сохранено в int.
long time = 0;         // последний раз, когда выходной пин был переключен
long debounce = 200;   // время устранения дребезга, увеличиваем, если вывод мерцает

void control(void);
void emergency(void);
//еще один coid для char ring


void setup()
{
  pinMode(eStop, INPUT);
  pinMode(eStopLED, OUTPUT);

  pinMode(dispenseButton, INPUT);
  pinMode(dispenseLED, OUTPUT);
  eVar = 0;
  Serial.begin(9600);  //Начать сериал
  attachInterrupt(digitalPinToInterrupt(eStop), emergency, CHANGE);
}


void loop()
{
  eStopScan = digitalRead(eStop);
  dispenseScan = digitalRead(dispenseButton);
  //Serial.println(eStopScan);
  /*if (eStopScan == HIGH && eStopPrior == LOW && millis() - time > debounce) { //Условия управления eStop
    switch (eVar) {
      case 0:
        vControl = 0;
        control();
        break;

      case 1:
        vControl = 1;
        control();
        break;
    }
    time = millis();
    }
  */

  if (dispenseScan == HIGH && dispensePrior == LOW && millis() - time > debounce) { //условия контроля выдачи
    Serial.println("in this loop");
    switch (eVar) {
      case 0:
        vControl = 2;
        control();
        break;

      case 1:
        vControl = 3;
        control();
        break;
    }
    time = millis();
  }


  eStopPrior = eStopScan;
  dispensePrior = dispenseScan;
}

void control () {

  switch (vControl) {
    case 0: // случай estop помещается в другую переменную для отображения последнего состояния estop
      eStopZone = HIGH;
      dispenseZone = LOW;
      digitalWrite(dispenseLED, dispenseZone);
      digitalWrite(eStopLED, eStopZone);
      eStopScan = LOW;
      dispenseScan = LOW;
      Serial.println("Case 0");
      //eVar = 1;
      break;

    case 1:
      for (int i = 0; i <= 2; i++) {
        eStopZone = LOW;
        digitalWrite(eStopLED, eStopZone);
        delay(345);
        eStopZone = HIGH;
        digitalWrite(eStopLED, eStopZone);
        delay(345);
        Serial.println("Case 1");
        //Серийный.println(i);
      }
      break;

    case 2:
      dispenseZone = HIGH;
      eStopZone = HIGH;
      digitalWrite(eStopLED, eStopZone);
      digitalWrite(dispenseLED, dispenseZone);
      Serial.println("here 1");
      delay(1000);
      Serial.println("here?");
      eStopZone = LOW;
      digitalWrite(eStopLED, eStopZone);
      Serial.println("Case 2");
      break;

    case 3:
      dispenseZone = HIGH;
      eStopZone = LOW;
      digitalWrite(eStopLED, eStopZone);
      digitalWrite(dispenseLED, dispenseZone);
      eVar = 0;
      Serial.println("Case 3");
      // делаем светодиод зеленым
      break;
  }
  time = millis();
  loop();
}

void emergency () {
  Serial.println("interrupt");
  vControl = 0;
  control();
}

Окно Com из отладки

in this loop
here 1
here?
Case 2
in this loop
here 1
here?
Case 2
in this loop
here 1
interrupt
interrupt
interrupt
here?
Case 2

, 👍0

Обсуждение

Пожалуйста, покажите нам скетч, который вы используете., @VE7JRO

пожалуйста, объясните, что вы понимаете о прерывании и о ISR, @jsotola

Трудно понять, что вы на самом деле имеете в виду. Пожалуйста, включите свой код и подробное описание того, что вы ожидали от кода и что он делает на самом деле., @chrisl

Насколько я понимаю, ISR завершится, а затем вернется в состояние, в котором он был остановлен. Однако я подумал, что, поскольку я говорю вернуться в цикл, где моя переменная теперь изменена, это аннулирует предыдущий случай., @96jeremy


2 ответа


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

1

Ваше объяснение того, что вы ожидаете, не очень понятно, но я попытаюсь ответить на ваш вопрос.

Во-первых, подпрограммы обслуживания прерываний (ISR) должны быть короткими (время выполнения, не обязательно длина кода). Сделайте минимум, необходимый для сохранения любого статуса или данных, вызвавших прерывание и выход. Предоставьте фону (вашему основному скетчу) дальнейшую обработку в результате прерывания.

Это означает, что ISR должен оставить какое-то указание — логический флаг, f/ex — что он что-то сделал, и ваш фон должен часто проверять это, реагировать на это, когда оно изменяется, и сбрасывать его для следующего прерывания.

Похоже, что ваш ISR вызывает ваш фоновый код, который фактически становится частью ISR, работает на уровне прерывания, предотвращает дальнейшие прерывания при этом и (возможно) возвращается к вашему фоновому коду в месте или в состоянии, которое к тому времени уже не актуально.

Подумайте об организации кода таким образом, чтобы фон выполнял все текущие рутинные задачи, которые вам нужны, но часто проверял, не произошло ли еще прерывание. Когда это произойдет, сделайте все необходимое, чтобы справиться с этим, сбросьте флаг «произошло прерывание» и вернитесь к своим фоновым задачам.

,

1

Я не вижу, что на самом деле идет не так, но вы слишком много звоните в свой ISR. Вы изменяете энергонезависимые переменные с помощью вызова control() в ISR, что приводит к неопределенному поведению: вы не знаете, когда вызывается ISR, особенно независимо от того, вызвана ли она до или после того, как энергонезависимые переменные были переданы из памяти в регистры или обратно в подпрограмме, запущенной из loop(). Также: никогда не выводите ничего из ISR или из кода, который вы вызываете из этого ISR. Последовательная связь очень медленная (по сравнению с тем, что процессор мог бы делать в это время).

Я бы сказал: единственное, что должен сделать ваш ISR, — это добавить 1 к изменчивой переменной, а затем закончить. В вашем loop() проверьте, больше ли эта изменчивая переменная 0, затем сбросьте изменчивую переменную обратно на 0 и запустите то, что у вас есть в текущем ISR. Чтобы своевременно реагировать на прерывание, это также означает, что вы не должны использовать delay() где-либо в своем коде. По крайней мере, это вернет ваш код к определенному поведению.

,