Multiple ISR working together

Hi, in my code I have to ISR's: ISR(TIMER1_COMPA_vect) and ISR(TIMER2_OVF_vect). The COMPA ISR has some code (can be reading a value or something) at a certain rate set using the timers in setup and essentially I am trying to make OVF ISR stop the COMPA part after a certain time period (let's say 5 seconds). Can anyone help? The main part that needs to be adjusted is the heading "Timer Overflow" and the stuff in the ISR_OVF but I can't seem to get it. Any adjustments would be appreciated.

#include <SoftwareSerial.h> 

int i=0;
int r_pin = A0;
int sample_output;
int Sfreq = 1;
const uint16_t Timer_count = (16*10^6) / (Sfreq*1024) - 1;;

void setup (){
  noInterrupts();
  
  Serial.begin (9600);
  ADCSRA |= (1 << ADPS0) |  (1 << ADPS1) | (1 << ADPS2);  // ADC Prescaler of 128

// ------ For Sampling Frequency ------ //
  //set timer1 interrupt at Sfreq Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 1564;// = (16*10^6) / (Sfreq*Timer Prescaler) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS11 and CS10 bits for prescaler <----
  TCCR1B |= (1 << CS12) | (1 << CS10); //-- 1024
//  TCCR1B |= (1 << CS12);               //-- 256
//  TCCR1B |= (1 << CS11) | (1 << CS10); //-- 64
//  TCCR1B |= (1 << CS11);               //-- 8
//  TCCR1B |= (1 << CS10);               //-- 1

  // enable timer COMPARE interrupt
  TIMSK1 |= (1 << OCIE1A);


// ----- Timer Overflow ----- //   
  TCCR2A = 0;
  TCCR2B = 0;
  //These need changing 
  TCNT2 = 250;                                // preload timer (256???-16MHz/256/10Hz)
  OCR2A = 64;
  TCCR1B |= (1 << WGM22);
  TCCR2B |= (1 << CS20) | (1 << CS22);        // 1024 prescaler 
  TIMSK2 |= (1 << TOIE2);                     // enable timer OVERFLOW interrupt

  interrupts();
} 

ISR(TIMER1_COMPA_vect){
 // code that does some stuff. I want this stopped by the OVF
}
ISR(TIMER2_OVF_vect) {
  TIMSK2 |= (1 << TOIE2); // These controls which parts are turned on and off?
  TCNT2 = 250;
  TIMSK2 ^= (1 << OCIE2A);
}

void loop (){}

essentially I am trying to make OVF ISR stop the COMPA part after a certain time period (let's say 5 seconds).

The code in the Timer2 OVF can turn off Timer1 completely by setting all the CS bits of Timer1 to 0.

The code in the Timer2 OVF can also clear the Timer1 output compare interrupt enable.

cattledog:
The code in the Timer2 OVF can turn off Timer1 completely by setting all the CS bits of Timer1 to 0.

The code in the Timer2 OVF can also clear the Timer1 output compare interrupt enable.

Hi, thank you for your response. Do you mean something like this?

#include <SoftwareSerial.h> 

int i=0;
int r_pin = A0;
int sample_output;
int Sfreq = 1;
const uint16_t Timer_count = (16*10^6) / (Sfreq*1024) - 1;;

void setup (){
  noInterrupts();
  
  Serial.begin (9600);
  ADCSRA |= (1 << ADPS0) |  (1 << ADPS1) | (1 << ADPS2);  // ADC Prescaler of 128

// ------ For Sampling Frequency ------ //
  //set timer1 interrupt at Sfreq Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 1564;// = (16*10^6) / (Sfreq*Timer Prescaler) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS11 and CS10 bits for prescaler <----
  TCCR1B |= (1 << CS12) | (1 << CS10); //-- 1024
//  TCCR1B |= (1 << CS12);               //-- 256
//  TCCR1B |= (1 << CS11) | (1 << CS10); //-- 64
//  TCCR1B |= (1 << CS11);               //-- 8
//  TCCR1B |= (1 << CS10);               //-- 1

  // enable timer COMPARE interrupt
  TIMSK1 |= (1 << OCIE1A);


// ----- Timer Overflow ----- //
  TCCR2A = 0;
  TCCR2B = 0;
  
  TCNT2 = 250;                                // preload timer (256???-16MHz/256/10Hz)
  TCCR2B |= (1 << CS20) | (1 << CS22);        // 1024 prescaler 
  TIMSK2 |= (1 << TOIE2);                     // enable timer OVERFLOW interrupt

  interrupts();
} 

ISR(TIMER1_COMPA_vect){
  //code
}
ISR(TIMER2_OVF_vect) {
  TCCR1B ^= (1 << CS12) | (1 << CS10);
  TIMSK1 ^= (1 << OCIE1A);
//  TIMSK2 |= (1 << TOIE2); 
//  TCNT2 = 250;
//  TIMSK2 ^= (1 << OCIE2A);
}

void loop (){}

Do you mean something like this?

Did you try the code? Did it do what you wanted?

ISR(TIMER2_OVF_vect) {
  TCCR1B ^= (1 << CS12) | (1 << CS10);
  TIMSK1 ^= (1 << OCIE1A);}

Yo do not need to do both operations. Either one will stop the Timer 1 interrupt.

The ^= will toggle the state of Timer1. Turn it on and off with each Timer2 overflow. Is that what you want?

I am trying to make OVF ISR stop the COMPA part after a certain time period (let's say 5 seconds).

cattledog:
Did you try the code? Did it do what you wanted?

ISR(TIMER2_OVF_vect) {

TCCR1B ^= (1 << CS12) | (1 << CS10);
 TIMSK1 ^= (1 << OCIE1A);}




Yo do not need to do both operations. Either one will stop the Timer 1 interrupt.

The ^= will toggle the state of Timer1. Turn it on and off with each Timer2 overflow. Is that what you want?

Hi, thank you for your response. Ahh I see. So essentially I have what is below. And kind of, but i want to stop the Timer 1 COMPLETELY after the Timer 2 countdown? Does that make sense? Also, perhaps this is working but I am not observing it, then in that case, for the TCNT value how do I calculate the real time seconds in relation to the number stored there? There is a formula there but I do not understand it. Many thanks!

#include <SoftwareSerial.h> 

int i=0;
int r_pin = A0;
int sample_output;
int Sfreq = 1;
const uint16_t Timer_count = (16*10^6) / (Sfreq*1024) - 1;;

void setup (){
  noInterrupts();
  
  Serial.begin (9600);
  ADCSRA |= (1 << ADPS0) |  (1 << ADPS1) | (1 << ADPS2);  // ADC Prescaler of 128

// ------ For Sampling Frequency ------ //
  //set timer1 interrupt at Sfreq Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 1564;// = (16*10^6) / (Sfreq*Timer Prescaler) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS11 and CS10 bits for prescaler <----
  TCCR1B |= (1 << CS12) | (1 << CS10); //-- 1024
//  TCCR1B |= (1 << CS12);               //-- 256
//  TCCR1B |= (1 << CS11) | (1 << CS10); //-- 64
//  TCCR1B |= (1 << CS11);               //-- 8
//  TCCR1B |= (1 << CS10);               //-- 1

  // enable timer COMPARE interrupt
  TIMSK1 |= (1 << OCIE1A);


// ----- Timer Overflow ----- //
  TCCR2A = 0;
  TCCR2B = 0;
  
  TCNT2 = 250;                                // preload timer (65536-16MHz/256/10Hz) <<- what is this equation?
  TCCR2B |= (1 << CS20) | (1 << CS22);        // 1024 prescaler 
  TIMSK2 |= (1 << TOIE2);                     // enable timer OVERFLOW interrupt

  interrupts();
} 

ISR(TIMER1_COMPA_vect){
//code
}
ISR(TIMER2_OVF_vect) {
  TCCR1B ^= (1 << CS12) | (1 << CS10);
}

void loop (){}

Actually I have realised that since for timer 2 my max count value can be 255 and since even with a prescaler of 1 (1024 I can't really use because the frequency would be too high to observe UNLESS the code does what I originally wanted to do which is completely stop after the OVF count) I am unable to reach a desired count of anything less than 10 seconds. Does anyone know how else I can get around this?

UPDATE: I have realised that this is most likely working, but it is just turning on and off at a frequency of 100Hz. It is faster than without this second timer. Does anyone know how to stop it after 1 iteration?

i want to stop the Timer 1 COMPLETELY after the Timer 2 countdown?

To clear the CS bits:

ISR(TIMER2_OVF_vect) {
  TCCR1B &= ~(1 << CS12) ;
  TCCR1B &= ~(1 << CS10);
}

Thank you for all your help now. So I have manages to get the OVF working, but I still need help with stopping the program of the code in the COMPA ISR completely after one OVF. I simply put in a print statement to monitor and the value print at the correct time intervals, ie on and off. But I just want to turn it off completely after one OVF. Any ideas?

#include <SoftwareSerial.h> 

int i=0;
int r_pin = A0;
int sample_output;
int Sfreq = 1;
const uint16_t Timer_count = (16*10^6) / (Sfreq*1024) - 1;;

void setup (){
  noInterrupts();
  
  Serial.begin (9600);
  ADCSRA |= (1 << ADPS0) |  (1 << ADPS1) | (1 << ADPS2);  // ADC Prescaler of 128

// ------ For Sampling Frequency ------ //
  //set timer1 interrupt at Sfreq Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 1562;// = (16*10^6) / (Sfreq*Timer Prescaler) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS11 and CS10 bits for prescaler <----
  TCCR1B |= (1 << CS12) | (1 << CS10); //-- 1024
//  TCCR1B |= (1 << CS12);               //-- 256
//  TCCR1B |= (1 << CS11) | (1 << CS10); //-- 64
//  TCCR1B |= (1 << CS11);               //-- 8
//  TCCR1B |= (1 << CS10);               //-- 1

  // enable timer COMPARE interrupt
  TIMSK1 |= (1 << OCIE1A);


// ----- Timer Overflow ----- //
  TCCR2A = 0;
  TCCR2B = 0;
  
  TCNT2 = 156;                     //here 100Hz                  // preload timer (65536>16MHz/prescaler/freq)
  TCCR2B |= (1 << CS20) | (1 << CS21) | (1 << CS22);             // 1024 prescaler 
  TIMSK2 |= (1 << TOIE2);                                        // enable timer OVERFLOW interrupt- DISABLING THIS STOPS OVF

  interrupts();
} 

ISR(TIMER1_COMPA_vect){
//print statement
}
ISR(TIMER2_OVF_vect) {
  TCCR1B ^= (1 << CS12) | (1 << CS10);
}

void loop (){}

I still need help with stopping the program of the code in the COMPA ISR completely after one OVF.

Did you not read the previous postings?

They discuss the use of ^= in the Timer2 OVF vector and provided a reference on how to clear bits. I feel like I am wasting my time.

You continue to use

ISR(TIMER2_OVF_vect) {
  TCCR1B ^= (1 << CS12) | (1 << CS10);
}

I suggested

ISR(TIMER2_OVF_vect) {
  TCCR1B &= ~(1 << CS12) ;
  TCCR1B &= ~(1 << CS10);
}

cattledog:
Did you not read the previous postings?

They discuss the use of ^= in the Timer2 OVF vector and provided a reference on how to clear bits. I feel like I am wasting my time.

You continue to use

ISR(TIMER2_OVF_vect) {

TCCR1B ^= (1 << CS12) | (1 << CS10);
}




I suggested


ISR(TIMER2_OVF_vect) {
 TCCR1B &= ~(1 << CS12) ;
 TCCR1B &= ~(1 << CS10);
}

I tried it before and it didn't work with that combination. Hence, I didn't use it. Thank you.

After you make the change, print out the value of the TCCR1B register and confirm that the CS bits are all at 0.

Serial.print(TCCR1B,BIN);

If the three CS bits are all 0, the Timer will be stopped according to the data sheet.

CS12 CS11 CS10 Description
0 0 0 No clock source (Timer/Counter stopped).

Since you are not wanting to use the timer, you can also set TCCR1B = 0 and make sure you reset the WGM bit if you start again.

Hi, thank you for your reply. I have been trying and testing with different timer counts. And I have checked with the print to see if the CS bits are turned off and they are off. I again put in what you suggested. Now the thing the Timer1 counter in the code below is at a rate of 1000Hz and the Timer2 counter is at a rate of 100Hz. So in the Serial Monitor I technically should be able to see the printed value in ISR Timer 1 for a few milliseconds before it turns off, but that is not the case. Any reason why?

#include <SoftwareSerial.h> 

int i=0;
int r_pin = A0;
int sample_output;
int Sfreq = 1;
const uint16_t Timer_count = (16*10^6) / (Sfreq*1024) - 1;;

void setup (){
  noInterrupts();
  
  Serial.begin (9600);
  ADCSRA |= (1 << ADPS0) |  (1 << ADPS1) | (1 << ADPS2);  // ADC Prescaler of 128

// ------ For Sampling Frequency ------ //
  //set timer1 interrupt at Sfreq Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15;// = (16*10^6) / (Sfreq*Timer Prescaler) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS11 and CS10 bits for prescaler <----
  TCCR1B |= (1 << CS12) | (1 << CS10); //-- 1024
//  TCCR1B |= (1 << CS12);               //-- 256
//  TCCR1B |= (1 << CS11) | (1 << CS10); //-- 64
//  TCCR1B |= (1 << CS11);               //-- 8
//  TCCR1B |= (1 << CS10);               //-- 1

  // enable timer COMPARE interrupt
  TIMSK1 |= (1 << OCIE1A);


// ----- Timer Overflow ----- //
  TCCR2A = 0;
  TCCR2B = 0;
  
  TCNT2 = 156;                     //here 100Hz                  // preload timer (65536>16MHz/prescaler/freq)
  TCCR2B |= (1 << CS20) | (1 << CS21) | (1 << CS22);             // 1024 prescaler 
  TIMSK2 |= (1 << TOIE2);                                        // enable timer OVERFLOW interrupt- DISABLING THIS STOPS OVF

  interrupts();
} 

ISR(TIMER1_COMPA_vect){
  sample_output = analogRead (r_pin);
  Serial.println(sample_output);  
  i++;
}
ISR(TIMER2_OVF_vect) {
  TCCR1B &= ~(1 << CS12) ;
  TCCR1B &= ~(1 << CS10);
//  TCCR1B = 0

//  Serial.println(TCCR1B,BIN); //Commented out when the above print statement is in use
}

void loop (){}

The "^" symbol below is EXCLUSIVE OR

const uint16_t Timer_count = (16*10^6) / (Sfreq*1024) - 1;;

Instead use

const uint16_t Timer_count = (16000000UL) / (Sfreq*1024UL) - 1;

So in the Serial Monitor I technically should be able to see the printed value in ISR Timer 1 for a few milliseconds before it turns off, but that is not the case. Any reason why?

You should start both timers together at the end of setup(). The noInterrupts() and interrupts() brackets are not needed in this case as well. I'm not certain I understand, but when you do use those commands, the interrupts need to be enabled before the timers are started.

You really should not be printing from within an ISR. Indeed, all the prints within the ISR are queued and only printed when you exit the ISR. You can easily overflow a print buffer that way.

#include <SoftwareSerial.h>

int i=0;
int r_pin = A0;
int sample_output;
int Sfreq = 1;
const uint16_t Timer_count = (16*10^6) / (Sfreq*1024) - 1;;

void setup (){
  noInterrupts();
  Serial.begin (9600);
  ADCSRA |= (1 << ADPS0) |  (1 << ADPS1) | (1 << ADPS2);  // ADC Prescaler of 128

// ------ For Sampling Frequency ------ //
  //set timer1 interrupt at Sfreq Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15;// = (16*10^6) / (Sfreq*Timer Prescaler) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS11 and CS10 bits for prescaler <----
  //TCCR1B |= (1 << CS12) | (1 << CS10); //-- 1024
//  TCCR1B |= (1 << CS12);               //-- 256
//  TCCR1B |= (1 << CS11) | (1 << CS10); //-- 64
//  TCCR1B |= (1 << CS11);               //-- 8
//  TCCR1B |= (1 << CS10);               //-- 1

  // enable timer COMPARE interrupt
  TIMSK1 |= (1 << OCIE1A);


// ----- Timer Overflow ----- //
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = 156;                     //here 100Hz                  // preload timer (65536>16MHz/prescaler/freq)           
  TIMSK2 |= (1 << TOIE2);                                        // enable timer OVERFLOW interrupt- DISABLING THIS STOPS OVF
  interrupts();
  TCCR2B |= (1 << CS20) | (1 << CS21) | (1 << CS22);// 1024 prescaler  
  TCCR1B |= (1 << CS12) | (1 << CS10); //-- 1024
  //interrupts();
}

ISR(TIMER1_COMPA_vect){
  sample_output = analogRead (r_pin);
  Serial.println(sample_output); 
  i++;
}
ISR(TIMER2_OVF_vect) {
  TCCR1B &= ~(1 << CS12) ;
  TCCR1B &= ~(1 << CS10);
//  TCCR1B = 0

//  Serial.println(TCCR1B,BIN); //Commented out when the above print statement is in use
}

void loop (){}

With A0 jumpered to 3.3v I see

11:12:07.078 -> 674
11:12:07.078 -> 674
11:12:07.078 -> 674
11:12:07.078 -> 674
11:12:07.078 -> 674
11:12:07.078 -> 674

jremington:
The "^" symbol below is EXCLUSIVE OR

const uint16_t Timer_count = (16*10^6) / (Sfreq*1024) - 1;;

Instead use

const uint16_t Timer_count = (16000000UL) / (Sfreq*1024UL) - 1;

Thank you! I will take that into consideration and include it.

Thank you very much! This now works exactly as I needed to. I really appreciate your help and sorry for the hassle! All the best.

cattledog:
You should start both timers together at the end of setup(). The noInterrupts() and interrupts() brackets are not needed in this case as well. I'm not certain I understand, but when you do use those commands, the interrupts need to be enabled before the timers are started.

You really should not be printing from within an ISR. Indeed, all the prints within the ISR are queued and only printed when you exit the ISR. You can easily overflow a print buffer that way.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.