Как выйти из прерывания таймера (ISR(TIMER1_COMPA_vect))

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

const signed int numReadings = 21;
volatile int gauge0[numReadings];
volatile int gauge1[numReadings];
volatile int add[numReadings];
volatile int deltaGAUGE;
volatile int slopeADD;
volatile int mean;

const int A0_pin = PC0;
const int A1_pin = PC1;

const uint16_t t1_load = 0;
const uint16_t t1_comp = 62500;

void setup() {
 
  //Set A0 and A1 pins as inputs
  DDRC &= ~(1 << A0_pin);
  DDRC &= ~(1 << A1_pin);

  //Reset Timer1 Control Reg A
  TCCR1A = 0;

  //Set CTC mode
  TCCR1B &= ~(1 << WGM13);
  TCCR1B |= (1 << WGM12);

  //Set to prescaler of 1024
  TCCR1B |= (1 << CS12);
  TCCR1B &= ~(1 << CS11);
  TCCR1B &= ~(1 << CS10);

  //Reset Timer1 and set compare value
  TCNT1 = t1_load;
  OCR1A = t1_comp;

  //Enable Timer1 compare interrupt
  TIMSK1 = (1 << OCIE1A);

  //Enable global interrupt
  sei();
  
       Serial.begin(9600);
       Serial.println(" ");
       Serial.println("START");
        Serial.println(" ");


}


ISR(TIMER1_COMPA_vect){

       Serial.println(" ");
        for (unsigned int i=0; i<numReadings; i++)
            {
                        gauge0[i] = (analogRead(A0_pin))*(100.00/1024.0);
                        gauge1[i] = (analogRead(A1_pin))*(100.00/1024.0);
                        add[i] = ((gauge0[i]+gauge1[i]));
                
                        deltaGAUGE = abs(add[20] - add[0]);
                        slopeADD = abs((add[20]-add[0])/(20-0));
                        mean = (add[1]+add[2]+add[3]+add[4]+add[5]+add[6]+add[7]+add[8]+add[9]+add[10]+
                             
                     add[11]+add[12]+add[13]+add[14]+add[15]+add[16]+add[17]+add[18]+add[19]+add[20])/20;

                        if(i == 20)
                {     
                      Serial.print("This of the delta AVG reading: ");
                      Serial.println(deltaGAUGE);
                      Serial.println(" ");
                      Serial.print("This of the slope reading: ");
                      Serial.println(slopeADD);
                      Serial.println(" ");
                      Serial.print("This of the mean reading: ");
                      Serial.println(mean);
                      Serial.println(" ");
                      Serial.println("END");    
              }
                        
                        delay(50); //wait .05 sec
                                
          }
 

}


void loop()
{

}



Когда я запускаю схему, прерывание продолжает выполняться каждую секунду в течение бесконечного количества времени, в то время как я просто хочу, чтобы оно работало один раз и выходило.

Я попробовал команду exit(0), но получил результат, который выглядит следующим образом

START
 
This of the delta AVG reading: 0
 
This of t

Как видите, программа не выполняется полностью. У кого-нибудь есть идеи, как я могу это исправить, или, во всяком случае, я могу улучшить свой код? Спасибо.

, 👍1

Обсуждение

возьмите весь код в ISR и переместите его в блок if внутри loop() ... установите флаг внутри ISR ... установите блок "если" для выполнения, когда флаг установлен, @jsotola

ИСР очень важны по времени и должны заканчиваться как можно быстрее. Твой слишком долго тянется. Посмотрите очень критически на то, что ДОЛЖНО быть сделано, когда происходит прерывание, и переместите весь остальной код из ISR, особенно все трудоемкие "Serial.print ()" и " delay ()". Пусть основная программа обрабатывает вычисления и вывод. ИСР нужно только провести измерения., @StarCat

Забудьте о прерываниях и читайте [Мигайте без задержки]. (https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay)., @Edgar Bonet

@StarCat это еще хуже. задержка и в некоторой степени " Serial.print` требуют прерываний для работы, но все прерывания отключены во время выполнения вашего кода ISR. Так что код просто повиснет., @Gerben

Почему вы используете аппаратный таймер для длительного интервала, например 1 секунду? Почему бы вам просто не использовать millis() (или micros(), если вам нужно больше точности) для времени измерений? Это было бы намного проще, @chrisl

По крайней мере, часть проблемы заключается в том, что вы никогда не отключаете прерывание, которое вы включили. Конечно, он будет работать снова при следующем переполнении условия/таймера., @RDragonrydr


2 ответа


1

Как было предложено в некоторых комментариях, я бы либо избавился от ISR, либо значительно уменьшил его размер. При использовании ISR рекомендуется сохранять код как можно меньше. Используйте его для установки переменных, например

//эти две переменные являются глобальными
ISR(TIMER1_COMPA_vect){
    someValue = true;
    numberOfValues++;
}

вы также никогда не должны использовать какие-либо последовательные функции внутри ISR, так как они используют сами прерывания, которые могут вызвать всевозможные проблемы

После использования ISR для обновления глобальных переменных можно использовать операторы if() или while() в функции loop() для выполнения функций последовательной печати и т. Д

P.S. на заметку, я бы рекомендовал изменить ваш код, где вы рассчитали среднее из

    mean = (add[1]+add[2]+add[3]+add[4]+add[5]+add[6]+add[7]+add[8]+add[9]+add[10]+         
add[11]+add[12]+add[13]+add[14]+add[15]+add[16]+add[17]+add[18]+add[19]+add[20])/20;

чтобы

for(uint8_t i = 1;i<=20;i++){
    mean += add[i];
}
mean /= 20;
,

1

Используйте cli(); чтобы полностью отключить прерывание. Затем используйте sei(); чтобы повторно включить прерывание, если оно вам понадобится позже.

,