Timer interrupt not working?

I don't have much hair left!!! Please put me out of my misery. Why won't this interrupt timer work?

// Define Global Variables
volatile byte ExecutionFlag = 0;
//*****************************************************
void setup() {
// Conf an interrupt on Timer 1 to fire an ISR every second
TCCR1B |= (1 << WGM12); // Configure for CTC mode
TCCR1B |= ((1 << CS10) | (1 << CS12)); // Prescaler @ 1024
TIMSK1 |= (1 << OCIE1A); // Enable interrupt
OCR1A = 15624; // compare value = 1 sec (16MHz AVR)
sei(); // Enable global interrupts

Serial.begin(9600);
}
//*****************************************************
void loop() {
if (ExecutionFlag){ // Every second ...
digitalWrite(13, !(digitalRead(13))); // toggle LED on Pin 13
ExecutionFlag = 0;
}
}
//**********************************************
ISR(TIMER1_COMPA_vect) {
ExecutionFlag = 1;
}

Thanks!!!

1 Like

I think you're setting up A then enabling B's interrupt.


Rob

Tried that. It is my understanding that there is only one timer 1 with two compare values/registers (please correct me if I am wrong).
When I put a Serial.println(TCNT1) in the loop, the timer does not appear to be incrementing ...
I'm stumped.

bryanb334:
...hair...

Yeah, we all have bad hair days from to time. (Well, most of us...)

Here's the deal: You need to be taking over Timer 1. Totally. See Footnote.

Try the following, to make sure that that the Timer 1 registers don't have anything left over from the Arduino initialization stuff:

void setup()
{
  pinMode(13, OUTPUT);
      
  cli();                   //Disable interrupts while setting registers       
  TCCR1A = 0;              // Make sure it is zero
  TCCR1B = (1 << WGM12);   // Configure for CTC mode (Set it; don't OR stuff into it)
  TCCR1B |= ((1 << CS10) | (1 << CS12)); // Prescaler @ 1024
  TIMSK1 = (1 << OCIE1A);  // Enable interrupt
  OCR1A = 15624;           // compare value = 1 sec (16MHz AVR)
  sei();                   // Enable global interrupts
  
  Serial.begin(9600);
}

Regards,

Dave

Footnote:
The Arduino init() function is always called before your setup() function. That's the way that Arduino builds the application around your sketch.

The Arduino init() function initializes Timer 1 to be ready for PWM output operation as follows:

Sets bit WGM10 in TCCR1A


- ```
[color=blue]Sets bits CS11 and CS10 in TCCR1B[/color]

Bottom line: You are taking over the timer. You need to initialize the registers for your mode of operation. By leaving those Timer 1 register bits set and ORing your bits into TCCR1B, the timer is definitely not operating the way you want it to.

I'm kind of a nub and want to set up a timer0 interrupt every 1ms, what needs setting?

or rather, where can I read about what bits and bobs to set?

thanks :]

If you are willing to use timer2 instead, there is already a well developed general purpose timer library avalible. I've used it to generate 2 millsec interrupts in a 5x5x5 led cube I built. Recall the arduino core functions already utilize timer0 for predefined functions like millis(), etc.

Either way you should be able to read the source code for MsTimer2 to see how they built it.

http://www.arduino.cc/playground/Main/MsTimer2

Lefty

Thankyou Davekw7x!!! You have saved what few hairs I have left.
I had to clear the cs11 bit as well but then all works great!

Does this mean that I cannot do any PWM now? Or does this timer only control PWM on some pins?

bryanb334:
...Or does this timer only control PWM on some pins?

For PWM output using Arduino analogWrite() function calls, Timer 1 is used to control ATmega pins OC1A and OC1B. For Arduino Duemilanove, Uno, and other Arduino non-Mega boards, these are Arduino Pins 10 and 11. Of course, you can still use Pins 10 and 11 for other things; you just can't expect to call *analogWrite()*s for those pins if you modify Timer 1 to operate in CTC mode. (The other analogWrite() pins are not affected by Timer 1 settings.)

Regards,

Dave

Thanks again Dave!
To clarify my understanding of the timer ... timer1 is just one timer but has two compare registers/values (A & B). Can these compare registers/values each have a different value and be used to trigger their own separate ISR in the way I have just done?

Bryan

bryanb334:
...timer1 is just one timer but has two compare registers/values (A & B)

Yes.

Here are the interrupt vectors for Timer 1:

  • TIMER1_CAPT_vect /* Timer/Counter1 Capture Event */
  • TIMER1_COMPA_vect /* Timer/Counter1 Compare Match A */
  • TIMER1_COMPB_vect /* Timer/Counter1 Compare Match B */
  • TIMER1_OVF_vect /* Timer/Counter1 Overflow */

bryanb334:
in the way I have just done?

The complete reference can be found here: http://www.atmel.com/dyn/resources/prod_documents/doc8271.pdf Chapters 15 and 16 contain EYAWTKAT1 (Everything You Always Wanted To Know About Timer 1).

Regards,

Dave

I've been fiddling around with TIMER1 , and I can't get interrupt A AND B to work at the same time.

I'm in CTC mode, timer resets when it gets to OCR1A so i set OCR1B lower of course, but still it seems to be either or. Also tried using ICR1 (input capture) and OCR1B to no avail.

It doesn't affect me since I don't want both interrupts, I just use interrupt A and in my loop check for the OCF1B flag.

Just thought i'd mention it :]

Yes, I have been having the same problem. Can only get one interrupt to work at a time. My thoughts are that it is in CTC (Clear on Timer Compare) mode. So which one does the clearing? It would seem that the lowest compare value would clear the timer so the higher value would never be reached, but it doesn't appear to be doing that.
Can anybody set me straight?
Thanks!

it's the OCR1A that does the clearing, not B.

there IS another CTC mode that uses ICR1 as the max, but I tried that too and couldn't get two interrupts on one timer.

bryanb334:
My thoughts are that it is in CTC (Clear on Timer Compare) mode.

Are you using the code in the first post? Or something similar?

If "yes", then you will need to change your code to set the values of bit WGM13 and bit CS11.

Here's a way to use ICR1 to determine the count period and use OCR1A and OCR1B interrupts for times somewhere within each count cycle.

//
// Illustration of use of OCR1A and OCR1B interrupts
// with Timer 1.
// A "real" application might do something more meaningful
// than simply recording the times that the interrupts
// occur, but, this can form a framework for bigger and
// better things.
//
// Maybe.
//
// davekw7x
//
#include <avr/io.h>
#include <avr/interrupt.h>


const int LEDPIN = 13;

// I want the count period to be 1 second.  This is how long
// (in seconds) it takes the counter to reset.
const float countinterval = 1.0;

// For Arduino Uno and Duemilanove and Mega boards F_CPU = 16 MHz
const unsigned long CPU = F_CPU;

// I'll pick a large prescale divisor to allow long intervals
const unsigned long prescale = 1024;

// Round the floating point value to an integer
const unsigned count1 = (CPU * countinterval / prescale) + 0.5 - 1;

//
// For countinterval = 1 sec, the LED goes high for one second
// and low for a second.
//
// For countinterval equal to 1.0 and F_CPU equal to 16000000,
// we will get count1 = 15624
//
// That is, the result fits in a 16-bit unsigned int, as it must.
// With this scheme you can get count intervals of slightly over
// four seconds.
//
// If you want a shorter interval you can decrease,
// the prescale value to get better granularity,
// but you must always keep the size so that count1
// fits into a 16-bit integer. A more sophisticated program
// might select the optimum prescale factor based on the value
// of countinterval.
//

void setup()
{
    pinMode(LEDPIN, OUTPUT);
    digitalWrite(LEDPIN, HIGH);

    // Disable interrupts while setting registers  
    cli();

    // Make sure all is normal in TCCR1A
    TCCR1A = 0;

    // Configure timer 1 for CTC mode with TOP = ICR1A, prescale = 1024
    // For finer granularity with shorter intervals, you could use a lower
    // prescale factor
    //
    // Top is ICR1
    TCCR1B = (1<< WGM13) | (1 << WGM12) | (1<< CS12) | (1 << CS10);


    // This determines output frequency: Timer will reset when it hits this value
    ICR1   = count1;
    
    OCR1A = count1 / 3; // Make it about 1/3 of the way through the count cycle
    
    // Arithmetic can overflow an int, so do the calculation
    // with long ints and truncate the result to an int
    OCR1B = 2L*count1 / 3; // Make it about 2/3 of the way through the count cycle
    
    // Enable CTC Interrupts for count match on comparator A
    // and also for comparator B
    TIMSK1 = (1 << OCIE1B) | (1 << OCIE1A);
    // Enable global interrupts
    sei();
    
    // As a sanity check, show the register values that were obtained by
    // calculations
    Serial.begin(9600);
    Serial.print("count1 = ");Serial.println(count1);
    Serial.print("OCR1A  = ");Serial.println(OCR1A);
    Serial.print("OCR1B  = ");Serial.println(OCR1B);
}

void loop()
{
    static unsigned long oldtime;
    unsigned long newtime = get_compb1time();
    if (newtime != oldtime) {
        oldtime = newtime;
        //Serial.print(millis());
        //Serial.print(":  ");
        Serial.print(get_compa1time(), DEC);
        Serial.print("  ");
        Serial.println(newtime, DEC);
    }
}

unsigned long compa1time, compb1time; // Millisecond values for OCR matches

// Fetching a 16-bit quantity is not atomic.  If it just
// happens that a timer0 (or other) interrupt occurs when
// trying to get compa1time, it just might return
// low byte from one count and high byte from the next
// count.  This can lead to occasional gross errors in
// the count value.
// To avoid this, don't try to read compa1time from the application,
// use this function:
unsigned long get_compa1time()
{
    unsigned long t;
    byte oldSREG = SREG;

    cli();
    t = compa1time;
    SREG = oldSREG;
    return t;
}
    
// See comment preceding get_compa1time()
unsigned long get_compb1time()
{
    unsigned long t;
    byte oldSREG = SREG;

    cli();
    t = compb1time;
    SREG = oldSREG;
    return t;
}
    
ISR(TIMER1_COMPA_vect)
{
    compa1time = millis(); 
  
    // Two methods for writing to the LED pin.
    // Comment out one of them and uncomment the other  
    
    // Direct manipulation of Arduino Pin 13 ia
    // faster than digitalWrite
    //PINB = (1 << 5); // Toggle the LED
    
    // On the other hand, digitalWrite makes it
    // easy to use a different LEDPIN without having
    // to look up the port and bit number.
    // Local variable keeps from having to read the LED pin each time
    static byte compa1;
    digitalWrite(LEDPIN, (++compa1)&1);

}  

ISR(TIMER1_COMPB_vect)
{
    compb1time = millis();
}

Output:


[color=blue]count1 = 15624
OCR1A  = 5208
OCR1B  = 10416
332  665
1332  1666
2332  2665
3332  3665
4332  4666
5332  5665
6332  6666
7332  7665
8332  8666
9332  9665
10332  10665
11332  11665
12333  12665
13332  13666
14332  14665
15332  15666
16332  16665
17332  17666
18332  18665
19332  19665
20332  20666
21332  21665
.
.
.
[/color]

Regards,

Dave

Still digesting .... this is awesome. Thanks so much for your help!!!

Bryan