I'm trying to check the frequency of Timer3 using a counter. The value of the counter, declared as volatile, is incremented in the ISR and every second the sum is shown in the main loop and the value reset to zero.
The timer has been set up correctly. (If I choose a 3Hz timer I can see the led blinking)
The problem
The counter isn't incremented. Here is the output:
Setup Completed
tick: 1
tick: 0
tick: 0
tick: 0
CODE
volatile int cont = 0;
void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);
// Initialize Timer
cli(); // disable global interrupts
TCCR3A = 0; // set entire TCCR3A register to 0
TCCR3B = 0; // same for TCCR3B
// set compare match register to desired timer count: 800 Hz
OCR3B = 20; // 800Hz 5; // 3 Hz
// turn on CTC mode:
TCCR3B |= (1 << WGM12);
// Set CS10 and CS12 bits for 1024 prescaler:
TCCR3B |= (1 << CS30) | (1 << CS32);
// enable timer compare interrupt:
TIMSK3 |= (1 << OCIE3B);
// enable global interrupts:
sei();
Serial.println("Setup completed");
}
void loop()
{
if (millis() % 1000 == 0)
{
Serial.print(" tick: ");
Serial.println(cont);
cont = 0;
}
}
ISR(TIMER3_COMPB_vect)
{
//digitalWrite(13, digitalRead(13) ^ 1);
cont++;
}
EDIT This timer is used to read an anlog value from an accelerometer and store it in an array of float. But at the moment I'm stuck on this update issue.
SOLUTION 1 Thanks to Gerben
volatile int cont = 0;
void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);
// Initialize Timer
cli(); // disable global interrupts
TCCR3A = 0; // set entire TCCR3A register to 0
TCCR3B = 0; // same for TCCR3B
// set compare match register to desired timer count: 800 Hz
OCR3A = 20; // 20; //800Hz 5; // 3 Hz
// turn on CTC mode:
TCCR3B |= (1 << WGM32);
// Set CS10 and CS12 bits for 1024 prescaler:
TCCR3B |= (1 << CS30) | (1 << CS32);
// enable timer compare interrupt:
TIMSK3 |= (1 << OCIE3B);
// enable global interrupts:
sei();
Serial.println("Setup completed");
}
void loop()
{
delay(1000);
Serial.println(cont);
cont = 0;
}
ISR(TIMER3_COMPB_vect)
{
cont++;
}
SOLUTION 2 Thanks to BrettM
volatile int cont = 0;
void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);
// Initialize Timer
cli(); // disable global interrupts
TCCR3A = 0; // set entire TCCR3A register to 0
TCCR3B = 0; // same for TCCR3B
// set compare match register to desired timer count: 800 Hz
OCR3B = 20; //800Hz 5; // 3 Hz
// turn on CTC mode:
//TCCR3B |= (1 << WGM32);
// Set CS10 and CS12 bits for 1024 prescaler:
TCCR3B |= (1 << CS30) | (1 << CS32);
// enable timer compare interrupt:
TIMSK3 |= (1 << OCIE3B);
// enable global interrupts:
sei();
Serial.println("Setup completed");
}
void loop()
{
Serial.println(cont);
cont = 0;
delay(1000);
}
ISR(TIMER3_COMPB_vect)
{
TCNT3 = 0;
cont++;
}
2 Answers 2
In CTC mode the top is OCR3A
, not OCR3B
!
After that TIMSK3 |= (1 << OCIE3B);
should also be changed to TIMSK3 |= (1 << OCIE3A);
, and ISR(TIMER3_COMPB_vect)
to ISR(TIMER3_COMPA_vect)
For 3Hz, OCR3A
should be 5208, not 20.
Technically TCCR3B |= (1 << WGM12);
should be TCCR3B |= (1 << WGM32);
-
With your configuration the counter is not updated and every second the "Setup completed" sentence, (written in the setup() function!) is shown. Really weird behaviour.UserK– UserK2014年12月11日 21:37:35 +00:00Commented Dec 11, 2014 at 21:37
-
Solved using
TIMSK3 |= (1 << OCIE3B);
. Thank you Gerben! Please modify your answer and I'll accept it as solution.UserK– UserK2014年12月11日 21:41:58 +00:00Commented Dec 11, 2014 at 21:41 -
1I forgot the mention you also need the change the ISR vector.
ISR(TIMER3_COMPB_vect)
should beISR(TIMER3_COMPA_vect)
. If an ISR isn't defined, the AVR will reset itself, like you were experiencing. Glad you got it working.Gerben– Gerben2014年12月12日 14:04:13 +00:00Commented Dec 12, 2014 at 14:04
It seems my answer to this question was previously incomplete, thanks for pointing out that CTC mode only works with OCR3A Gerben. I apologize for not testing an answer before I post it.
Given the information only in this question Gerben's answer is complete, but since your other question implies that you cannot use OCR3A due to the Servo library I'll add a bit. (I've also edited that answer)
you can emulate the behavior of CTC mode by setting TCNT3 to 0 in your interrupt routine. Remember to remove the line that turns on CTC mode in your code.
I've tested your code with this ISR:
ISR(TIMER3_COMPB_vect)
{
TCNT3 = 0;
cont++;
}
and this configuration of the timer registers
OCR3B = 5208; // 800Hz 5; // 3 Hz
// Set CS10 and CS12 bits for 1024 prescaler:
TCCR3B |= (1 << CS30) | (1 << CS32);
// enable timer compare interrupt:
TIMSK3 |= (1 << OCIE3B);
This might be a bit less accurate at high frequencies than CTC, I'm not sure, but at 3Hz it worked perfectly. Notice that 5208 was the correct OCR value, not 20 (again thanks to Gerben).
-
I've tried your code but the counter isn't incremented. I've added the
TCNT3=0;
in the ISR() and removed//TCCR3B |= (1 << WGM32);
in the setup() as you said. I've also tried commenting out thecont=0;
line but nothing changedUserK– UserK2014年12月11日 21:56:29 +00:00Commented Dec 11, 2014 at 21:56 -
1Make sure the code matches what is posted in the question in every other way. Try changing your loop to just
println(cont); delay(1000);
. Also you are still including the bits with cli() and TCCR3A etc correct?BrettFolkins– BrettFolkins2014年12月11日 22:06:46 +00:00Commented Dec 11, 2014 at 22:06
Explore related questions
See similar questions with these tags.
digitalWrite
line you see the LED blink about once per second (every 0.66s)?digitalWrite
and setOCR3B = 5;
the led blinks at approximately that frequency.cont = 0;
inside the loop? What happens then?