Как заставить прерывание перезапустить основной цикл вместо возобновления? (вопрос времени!)

За последние два дня я написал программу, которая в общих чертах генерирует довольно точный настраиваемый пользователем импульсный сигнал (как по частоте, так и по рабочему циклу). Он в основном использует функцию micros() для отслеживания времени, чтобы вывести 4 или 4 канала цифрового выхода.

Эти 4 канала всегда должны иметь разность фаз 90 градусов (например, 4-цилиндровый двигатель). Чтобы пользователь мог изменить настройки, реализован ISR, который возвращает флаг в основной цикл для повторной инициализации программы. Этот флаг определен как логическое значение 'set4'. Когда оно ложно, оператор while в основном цикле будет запускать выходы. Когда оно истинно, оператор if выполнит необходимые пересчеты и сбросит флаг, чтобы оператор while возобновился.

Программа отлично работает с начальными значениями. Этап идеален. Однако, когда ISR вызывается и возвращается к основному циклу, насколько я понимаю, он возобновляет программу в операторе 'while' с того места, где он был первоначально прерван, до тех пор, пока не завершится и не проверит флаг 'set4', чтобы увидеть его Теперь верно, и это должно прекратиться. Затем, даже несмотря на то, что оператор "if" впоследствии сбрасывает и пересчитывает все необходимые переменные, фаза между этими 4 выходными каналами теряется. Проверено вручную, я вижу, в зависимости от того, в какое время вызывается ISR, это даст разные результаты, обычно синхронизируя все 4 выходных канала! Это происходит, даже если я не могу изменить никакие значения (таким образом, подпрограмма if сбрасывает переменные до тех же самых значений, когда вы впервые включаете arduino!). Однако, если я закомментирую эту процедуру и просто оставлю строку, которая сбрасывает флаг 'set4', программа продолжит работу как обычно, ничего не произошло!

Я почти уверен, что это как-то вызвано таймером micros(), потому что цикл будет возобновлен с того места, где был вызван ISR. Я пытался сделать это по-другому, проверяя и отключая прерывания с помощью cli() и sei(), но я не смог заставить его работать, потому что он просто зависнет, когда аргументы для cli() верны. Единственное решение, о котором я могу подумать (я перепробовал все, потратил целый день на поиски и испытания), - заставить ISR возобновить работу с начала цикла, чтобы программа могла правильно инициализироваться. Еще одно решение, которое приходит на ум, - это, может быть, каким-то образом сбросить таймер micros(), но, по-моему, это испортит ISR.

Чтобы помочь вам визуализировать то, что происходит, вот фрагмент моего кода (пожалуйста, не обращайте внимания на имя 'Millis' в переменных micros и любые пропущенные фигурные скобки, так как это не просто copy-paste:p):

    void loop()
    {
        while(!set4)
        {
        currentMillis = micros();
        currentMillis2 = micros();
        currentMillis3 = micros();
        currentMillis4 = micros();

          if(currentMillis - previousMillis >= interval) {
            // save the last time you blinked the LED 
            previousMillis = currentMillis;   

            // if the LED is off turn it on and vice-versa:
            if (ledState == LOW)
            {
              interval = ONTIME;
              ledState = HIGH;
            }
            else
            {
             interval = OFFTIME; 
             ledState = LOW;
            }

            // set the LED with the ledState of the variable:
            digitalWrite(ledPin, ledState);
            }
    .
    .
    //similar code for the other 3 output channels
    .
    .
    }
    if (set4){
    //recalculation routine - exactly the same as when declaring the variables initially  
      currentMillis = 0;
      currentMillis2 = 0;
      currentMillis3 = 0;
      currentMillis4 = 0;

      //Output states of the output channels, forced low seperately when the ISR is called (without messing with the 'ledState' variables)
      ledState = LOW;
      ledState2 = LOW;
      ledState3 = LOW;
      ledState4 = LOW;

      previousMillis = 0;
      previousMillis2 = 0;
      previousMillis3 = 0;
      previousMillis4 = 0;

     //ONTIME is the HIGH time interval of the pulse wave (i.e. dwell time), OFFTIME is the LOW time interval
     //Note the calculated phase/timing offset at each channel

      interval = ONTIME+OFFTIME;
      interval2 = interval+interval/4;
      interval3 = interval+interval/2;
      interval4 = interval+interval*3/4;

      set4=false;

    }
}

Есть идеи, что не так? С уважением, Кен

1 ответ

Решение

Проблема здесь:

  previousMillis = 0;
  previousMillis2 = 0;
  previousMillis3 = 0;
  previousMillis4 = 0;

Все, если утверждение будет верно в следующем цикле.

Попробуйте с:

  previousMillis = micros();
  previousMillis2 = micros();
  previousMillis3 = micros();
  previousMillis4 = micros();
Другие вопросы по тегам