Pages Menu
TwitterRssFacebook
Categories Menu

Posted by on Jun 28, 2011 in Atmel AVR, Microcontrollers | 139 comments

AVR Timers – TIMER1

AVR Timers – TIMER1

AVR SeriesHello folks! Welcome back! In this tutorial, we will come across TIMER1 of the AVR. I hope that you have read and understood the previous posts:

So basically, in this tutorial, we will do whatever we did in the previous one. In the TIMER0 tutorial, we generated a timer running at the CPU frequency. We then modified the code to include prescalers, and once again modified the code to include interrupts.

Now that you are aware of the concepts, we will deal with TIMER1 in a short and snappy way. Whatever we did in the previous TIMER0 tutorial, we will do the same here. Thus, we will discuss only one problem statement which will include both, prescalers and interrupts.

Once we are done with this, we can proceed to the CTC and PWM modes of operations in subsequent posts.

Problem Statement

Okay, let’s make it loud and clear. We need to flash an LED every 2 seconds, i.e. at a frequency of 0.5 Hz. We have an XTAL of 16 MHz.

Methodology – Using prescaler and interrupt

Okay, so before proceeding further, let me jot down the formula first.Timer CountGiven that we have a CPU Clock Frequency of 16 MHz. At this frequency, and using a 16-bit timer (MAX = 65535), the maximum delay is 4.096 ms. It’s quite low. Upon using a prescaler of 8, the timer frequency reduces to 2 MHz, thus giving a maximum delay of 32.768 ms. Now we need a delay of 2 s. Thus, 2 s ÷ 32.768 ms = 61.035 ≈ 61. This means that the timer should overflow 61 times to give a delay of approximately 2 s.

Now it’s time for you to get introduced to the TIMER1 registers (ATMEGA16/32). We will discuss only those registers and bits which are required as of now. More will be discussed as and when necessary.

TCCR1B Register

The Timer/Counter1 Control Register B– TCCR1B Register is as follows.

TCCR1B Register

TCCR1B Register

Right now, only the highlighted bits concern us. The bit 2:0 – CS12:10 are the Clock Select Bits of TIMER1. Their selection is as follows.

Clock Select Bits Description

Clock Select Bits Description

Since we need a prescaler of 8, we choose the third option (010).

TCNT1 Register

The Timer/Counter1 – TCNT1 Register is as follows. It is 16 bits wide since the TIMER1 is a 16-bit register. TCNT1H represents the HIGH byte whereas TCNT1L represents the LOW byte. The timer/counter value is stored in these bytes.

TCNT1 Register

TCNT1 Register

TIMSK Register

The Timer/Counter Interrupt Mask Register – TIMSK Register is as follows.

TIMSK Register

TIMSK Register

As we have discussed earlier, this is a common register for all the timers. The bits associated with other timers are greyed out. Bits 5:2 correspond to TIMER1. Right now, we are interested in the yellow bit only. Other bits are related to CTC mode which we will discuss later. Bit 2 – TOIE1 – Timer/Counter1 Overflow Interrupt Enable bit enables the overflow interrupt of TIMER1. We enable the overflow interrupt as we are making the timer overflow 61 times (refer to the methodology section above).

TIFR Register

The Timer/Counter Interrupt Flag Register – TIFR is as follows.

TIFR Register

TIFR Register

Once again, just like TIMSK, TIFR is also a register common to all the timers. The greyed out bits correspond to different timers. Only Bits 5:2 are related to TIMER1. Of these, we are interested in Bit 2 – TOV1 – Timer/Counter1 Overflow Flag. This bit is set to ‘1’ whenever the timer overflows. It is cleared (to zero) automatically as soon as the corresponding Interrupt Service Routine (ISR) is executed. Alternatively, if there is no ISR to execute, we can clear it by writing ‘1’ to it.

Code

Now that we are aware of the methodology and the registers, we can proceed to write the code for it. To learn about I/O port operations in AVR, view this. To know about bit manipulations, view this. To learn how to use AVR Studio 5, view this. To learn how this code is structured, view the previous TIMER0 post.

#include <avr/io.h>
#include <avr/interrupt.h>
 
// global variable to count the number of overflows
volatile uint8_t tot_overflow;
 
// initialize timer, interrupt and variable
void timer1_init()
{
    // set up timer with prescaler = 8
    TCCR1B |= (1 << CS11);
 
    // initialize counter
    TCNT1 = 0;
 
    // enable overflow interrupt
    TIMSK |= (1 << TOIE1);
 
    // enable global interrupts
    sei();
 
    // initialize overflow counter variable
    tot_overflow = 0;
}
 
// TIMER1 overflow interrupt service routine
// called whenever TCNT1 overflows
ISR(TIMER1_OVF_vect)
{
    // keep a track of number of overflows
    tot_overflow++;
 
    // check for number of overflows here itself
    // 61 overflows = 2 seconds delay (approx.)
    if (tot_overflow >= 61) // NOTE: '>=' used instead of '=='
    {
        PORTC ^= (1 << 0);  // toggles the led
        // no timer reset required here as the timer
        // is reset every time it overflows
 
        tot_overflow = 0;   // reset overflow counter
    }
}
 
int main(void)
{
    // connect led to pin PC0
    DDRC |= (1 << 0);
 
    // initialize timer
    timer1_init();
 
    // loop forever
    while(1)
    {
        // do nothing
        // comparison is done in the ISR itself
    }
}

So folks, this is how to apply the basic timer concepts for TIMER1. Please note that if you learn the basics, everything will be easy. If you find yourself struggling with the code, then please visit the TIMER0 tutorial, clear your concepts and give it a try again. If still you don’t get it, I will be glad to help you! :)

In my next post, we will learn how to apply the same concepts to TIMER2. It is, once again, an 8-bit timer. Thus all the TIMER2 registers are similar to TIMER0. After that, we move towards the interesting part, the Clear Timer on Compare (CTC) mode!

Till then, grab the RSS Feeds or subscribe to my blog to stay updated! Also, post your responses below. I am awaiting for them! :)

139 Comments

  1. The previous article about TIMER0 is missing

  2. Amazing tutorial … it’s just i can’t open the Timer0 tab … would you please repost it

  3. In equation for timer count, why – 1 is required?

    Can’t understood, kindly explain

    • Think of a situation. You have to count till 99. If you keep counting ahead of 99, it will roll back to 0. Which number should you start at so that the counter rolls back to 0 in 10 steps?
      Answer: 99 – 10 + 1 = 90. If you start counting from 90, it will roll back to 0 in exactly 10 steps. The reason why you’re doing +1 is the same reason why you’re doing -1 in the equation. You just need to wrap your head around it. It’s just how humans count. :)

  4. What is difference between OCIE0 and TOIE0

    • OCIE0 is the Output Compare Match Interrupt Enable for Timer0. This is used when you want to be notified if the timer value matches the compare value (CTC mode).
      TOIE0 is the Timer Overflow Interrupt Enable for Timer0. This is used when you want to be notified whenever the timer overflows.

  5. hai max, it’s me again. I don’t understand about uint8_t. Can you explain more about it. and why are u sing the same ‘uint8_t’ in timer0 and timer1.

    • uint8_t means that it is unsigned integer which has a size of 8 bits (1 byte). The _t in the end simply means that it is a typedef.

      For instance, if you write
      int var1 = 10;
      This means that the size of var1 could be 16 bits or 32 bits – you don’t know exactly since it is compiler dependent. The AVR compiler takes the size of 16 bits, but a compiler on your local computer will convert it to 32 bits.

      However if you write
      int16_t var2 = 10;
      This means that the size of var2 is guaranteed to be 16 bits no matter what compiler you use. Making it uint16_t simply makes it unsigned. Same goes with uint8_t. I think this reddit thread explains it well enough.

  6. how can we generate 2 min delay using timer1 by interrupt method in atmega8.

    • You know everything to generate a 2 min delay. Don’t expect me to write code for you.

  7. if(ovf>=61)
    {
    PORTB^=1<<0;
    ovf=0;

    }
    this code also works inside main function while loop otherthan isr ().

    • Yes, but if it is inside the main loop, then it is wasting processor time. The only reason it is inside ISR is because you don’t want it to execute every single time. You want it to execute ONLY when an overflow occurs. It is useless otherwise.

    • The code is written for ATMega16/32 where there is only one TIMSK register with the name TIMSK. You’re probably using a different microcontroller.

  8. Can I initialize the TCNT1 16 bit register value as 20? If yes, will it start to count from 20 to Max for the entire iteration or after first iteration will it starts to count from 0 to max? Please clarify me on this

    • 20, 21, 22, …, 65534, 65535, 0, 1, 2, …, 65534, 65535, 0, 1, 2, …
      Cool? If you want it to count from 20 every time it overflows, you need to reload TCNT1 with 20 every time it overflows.

  9. hi Max
    really you are the best in all this thank you very much for you work i appreciate it so much thank you again
    now i have some questions for you
    first why we should write logical 1 in the TOV1 bit if there is no ISR in the code i think we need to clear it so we should write logical 0 am so confused now may you explain that for me ?
    second question is about the 16-bit timer counter register
    i saw it in the data sheet for atmega32 that these 16-bit register the CPU reach it and write on it by using another register called TEMP register and there are no any explanation about how that happen and when
    do you have any idea about that ?
    and thank you a lot again

    • If you read the datasheet properly, it says that you should write 1 to clear TOV1 bit. I don’t know why, but apparently that’s how the hardware is designed.

      TEMP is a hardware register and not software-writable. Which means that it is not present in the memory map and hence the compiler cannot access it. Only the hardware can write to it and it is designed to work that way. You don’t need to worry about it as a software developer. In a 16-bit timer, when you try to write the entire register to the 8-bit bus, only the lower bits get copied. That’s why you need a TEMP register to hold the contents of the upper byte before it can be read/written to/from the 8-bit bus. Great question.

    • Thanks. Updated the link.

  10. hello Mr max,thank you very much for this tuto,it is explained by the simplest way ever
    i have just one question :in the timer1 code you didn’t reset the timer whereas in the timer0 you did ,is there any particularity for the timer 1?or just an improved code
    thank you

    • I don’t need to reset timer in this example. It depends on your application.

  11. is there any example on how to use timer in case of external clock source is used?

    • What’s the difference anyways? You just need to change a few bits. If you understand how this works, then you should be able to write it yourself.

  12. Please if it possible , could you explain the ADC peripheral of avr atmega 32 because i am bit confused of dealing with and how to control the mtor speed

Leave a Reply

%d bloggers like this: