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 (){}
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?
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?
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 (){}
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 (){}
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.