Как выйти из прерывания таймера (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
Как видите, программа не выполняется полностью. У кого-нибудь есть идеи, как я могу это исправить, или, во всяком случае, я могу улучшить свой код? Спасибо.
@Dema Govalla, 👍1
Обсуждение2 ответа
Как было предложено в некоторых комментариях, я бы либо избавился от 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;
Используйте cli();
чтобы полностью отключить прерывание. Затем используйте sei();
чтобы повторно включить прерывание, если оно вам понадобится позже.
- Использование millis() и micros() внутри процедуры прерывания
- Почему необходимо использовать ключевое слово volatile для глобальных переменных при обработке прерываний в ардуино?
- Arduino непрерывно считывает значение АЦП с помощью прерывания
- Использование TIMER0_COMPB_vect
- Серийное прерывание
- Влияет ли `millis()` на длинные ISR?
- Как прервать функцию цикла и перезапустить ее?
- 4-битный счетчик вверх и вниз
возьмите весь код в 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