I am running an ATMega328P, set to use internal 8MHz clock, with timer2 asynchronously clocked via an external 32.786kHz crystal (with 18pF caps). With the following code, I am aiming to toggle an LED every second. With the clock set to 128Hz and OCR2A set to 127 (zero referenced) this should work. But it only toggles every 2s. In fact, it doesnt matter what I change OCR2A to, it always toggles at 2s. This makes me think it is interrupting on an overflow instead of compare match.
In the ISR, TCNT2 is set to zero, to effectively restart the counter. Could this be related to the issue?
As an alternative, I have tried commenting out TCNT2 = 0; and uncommenting TCCR2A = (1<<WGM21);. This should use CTC mode, which automatically clears the timer on interrupt). But then I get even stranger behavior - the LED is toggling very fast. It actually appears to be always on, but I have discovered that if I change the prescaler to 1024 (to slow the clock down to 32Hz), I can see it flashing maybe 10-15 times per second.
As an aside, it doesnt seem to make any difference if interrupts(); is commented out or not.
Ultimately I am trying to set up a timer to count around 80s, run some code, then go to sleep until another 80s is up. The 80s changes periodically.
Would appreciate any light you can shed!
// Global settings
#define LEDPin 10
// Global variables
volatile bool toggleLED = false;
// Interrupt triggered on timer2 compare match
ISR(TIMER2_COMPA_vect) { // Flashes LED approx (interrup triggers at 125Hz)
TCNT2 = 0;
// Set the flat to toggle the LED
toggleLED = true;
}
void setup() {
// Set up timer2
ASSR = (1<<AS2); // Make Timer2 asynchronous - When AS2 is written to one, Timer/Counter2 is clocked from a crystal oscillator connected to the timer oscillator 1 (TOSC1) pin
TCCR2A = 0; // Reset entire TCCR0A register
TCCR2B = 0; // Reset entire TCCR0B register
//TCCR2A = (1<<WGM21); // Clear Timer on Compare Match (CTC) Mode
TCCR2B = (1<<CS22)|(1<<CS21)|(0<<CS20); // Prescaler of 1024 = 32.768kHz/256 = 128 Hz
OCR2A = 127; // Set compare register A to this value (128/128 = 1Hz)
TIMSK2 = (1<<OCIE2A); // Enable compare match interrupt
// Initialise variables
pinMode(LEDPin, OUTPUT);
// Enable interrupts
//interrupts();
}
void loop() {
// if flag set to toggle LED
if (toggleLED == true){
// Reset flag
toggleLED = false;
// Toggle LED
digitalWrite (LEDPin, ! digitalRead (LEDPin));
}
}
Interrupts are enabled when your sketch starts. You don't need to enable them.
You can get 8 seconds between interrupts (32 kHz w/1024 prescale and 256 counts).
It sound like you are just trying to test your interrupt rate to make sure your 128 Hz interrupt is happening at 128 Hz. I would use the overflow interrupt rather than the compare match interrupt. The overflow is after 256 counts so a toggle rate of every two seconds would be expected. That will eliminate any OCR2A issues.
I want to use compare match, not overflow, because my application will require timing of variable periods, so I need to be able to adjust the compare match value. Just using overflow doesn’t actually solve my problem.
Any assistance would be appreciated. My program is going to the interrupt, but after 2 seconds instead of 1. Very confused.
Correct me if I am wrong but the prescaller is set to 256. CS20 is set to 0, not 1.
I’m just toggling and LED as a way to test my timing method. I don’t actually want a timer that toggles the output. I want a timer that runs some code after a certain (~80s) period.
Thanks, however this code uses the overflow method. I need to use the compare match as I want to be able to modify the period occasionally by changing the value of OCR2A.
Just count 80 of those 1 second overflows, or some other number, and take the action. In the meantime, you have the basis for a reasonably accurate RTC, as a freebie.
Here is the rest of it:
//******************************************************************
// Timer2 Interrupt Service
// 32 kKz / 256 = 1 Hz with Timer2 prescaler 128
// provides global tick timer and BCD ASCII Real Time Clock
// no check for illegal values of RTC_buffer upon startup!
ISR (TIMER2_OVF_vect) {
// RTC function
RTC_buf[7]++; // increment second
if (RTC_buf[7] > '9')
{
RTC_buf[7]='0'; // increment ten seconds
RTC_buf[6]++;
if ( RTC_buf[6] > '5')
{
RTC_buf[6]='0';
RTC_buf[4]++; // increment minutes
if (RTC_buf[4] > '9')
{
RTC_buf[4]='0';
RTC_buf[3]++; // increment ten minutes
if (RTC_buf[3] > '5')
{
RTC_buf[3]='0';
RTC_buf[1]++; // increment hours
char b = RTC_buf[0]; // tens of hours, handle rollover at 19 or 23
if ( ((b < '2') && (RTC_buf[1] > '9')) || ((b=='2') && (RTC_buf[1] > '3')) )
{
RTC_buf[1]='0';
RTC_buf[0]++; // increment ten hours and day number, if midnight rollover
if (RTC_buf[0] > '2') {RTC_buf[0]='0'; dayno++;}
}
}
}
}
}
}
I need to count fractions of seconds too, e.g. 83.26 seconds. I know the resolution of a 32Hz timer won’t be great but it’s close enough. A 1Hz interrupt wont be close enough though.
I don't think that your setting of TCNT2 = 0 in the ISR is actually happening.
The data sheet has this to say
When writing to one of the registers TCNT2, OCR2x, or TCCR2x, the value is transferred to a
temporary register, and latched after two positive edges on TOSC1. The user should not write a
new value before the contents of the temporary register have been transferred to its destination.
Each of the five mentioned registers has its individual temporary register, which means that e.g.
writing to TCNT2 does not disturb an OCR2x write in progress. The Asynchronous Status Register
(ASSR) indicates that a transfer to the destination register has taken place.
And this
Bit 4 – TCN2UB: Timer/Counter2 Update Busy
When Timer/Counter2 operates asynchronously and TCNT2 is written, this bit becomes set. When
TCNT2 has been updated from the temporary storage register, this bit is cleared by hardware. A logical
zero in this bit indicates that TCNT2 is ready to be updated with a new value.
Try this in the ISR
ISR(TIMER2_COMPA_vect) { // Flashes LED approx (interrup triggers at 125Hz)
while(TCN2UB != 0); //wait until update flag is cleared by hardware
TCNT2 = 0;
// Set the flat to toggle the LED
toggleLED = true;
}
Sorry. I can't figure out an explanation for either behavior that doesn't involve bad hardware. I don't have an Arduino with a 32768 Hz crystal to test with.
This is my code in CTC mode. With 32.768kHz external clock, prescaler = 1024 and OCR2A = 127, I would expect the LED to toggle every 4s. But it looks like at least 8 times per second (hard to count at that speed).
// Global settings
#define LEDPin 10
// Global variables
volatile bool toggleLED = false;
// Interrupt triggered on timer2 compare match
ISR(TIMER2_COMPA_vect) { // Flashes LED approx (interrup triggers at 125Hz)
// Set the flat to toggle the LED
toggleLED = true;
}
void setup() {
// Set up timer2
ASSR = (1<<AS2); // Make Timer2 asynchronous - When AS2 is written to one, Timer/Counter2 is clocked from a crystal oscillator connected to the timer oscillator 1 (TOSC1) pin
TCCR2A = 0; // Reset entire TCCR0A register
TCCR2B = 0; // Reset entire TCCR0B register
TCCR2A = (1<<WGM21); // Clear Timer on Compare Match (CTC) Mode
TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20); // Prescaler of 1024 = 32.768kHz/1024 = 32 Hz
OCR2A = 127; // Set compare register A to this value (32/128 = 0.25Hz)
TIMSK2 = (1<<OCIE2A); // Enable compare match interrupt
// Initialise variables
pinMode(LEDPin, OUTPUT);
}
void loop() {
// if flag set to toggle LED
if (toggleLED == true){
// Reset flag
toggleLED = false;
// Toggle LED
digitalWrite (LEDPin, ! digitalRead (LEDPin));
}
}