timer/counter

Note: im using Atmega328 for this post with 8 bit timer:
datasheet

before i start, this post shows simple blink program .. i will try to describe how timer/counter
believe me, if you really want to understand it .. the best is to read full datasheet and watch some avr geeks’ tutorial …

for me, i dont know all the features in timers, i will describe simple blink program .. not pwm or somthing just an ISR function (inturrept service routine) ..

what is ISR

to make it simple, and ISR function, is a function that interrupt your code and goes to some function that is predifined.. in microcontroller that has no OS (operating system) .. an ISR function is predefined in the processer through somthing called NVIC (Nested Vectored Interrupt Controller)

but what is NVIC

if you are so intrested to know all these details, i would suggest you to read more about C, assembly, well and this video describe NVIC pretty good https://www.youtube.com/watch?v=uFBNf7F3l60&t=833s

OK, lets start

What is the Prescaler:

The prescaler is electronics counting circuit that reduces high frequency to lower one by integer division. the prescaler is just a clock divider When you set Prescaler to 8 and you have 8MHz clock. You will get output 1MHz from the prescaler

timer/counter [TCNT]:

This register that holds the count value from timer ticks (after applying prescaler)

ok, this is getting boring, lets see the code then we will continue ..


#define F_CPU 16000000UL

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

volatile static uint8_t x = 1;


ISR( TIMER0_COMPA_vect)
{
    x++;
    if (x == 100) // 100* 10ms = 1000 ms
    {
        PORTB ^= 0B00100000;
        x=0;
    }
}

int main(void)
{

    //Set Direction port B to output pin 13 in arduino
    DDRB = DDRB | 0B00100000 ;
    //Timer/counter control register A
    TCCR0A = 0;
    TCCR0A |= 1<< WGM01; // CTC mode - clear counter when reaches to OCR0A
   
    //Timer/counter control register B ->  clk select bits:
    TCCR0B = (1 << CS00 ) | (1 << CS02 );  //1024 prescaler = 15625 ticks / sec @ 16MHz
   
    //output compare A
    OCR0A = 156;  //  156 * (1/15625) = 9.984ms
    // interrupt mask register
    //TIMSK0 |= 1 << TOIE0 ; // [TOIE0] interrupt enable bit = 1
    TIMSK0 |= 1<< OCIE0A; // [output compare A interrupt enable 0]
   
    sei();

    while (1)
    {
     // you can do anything here.. the mcu will blink 1 sec ...
       
    }
}

lets start with the code in the main function:

Input output programming:


Timer Stuff:

  • TCCR0A this is called Timer/counter Control Register i set the WGM bit to CTC mode .. WGM in CTC mode, you can set a value and when the timer reach to it.. it will reset the timer .. this give you better control .. CTC: Clear timer on compare match

  • TCCR0B this is still timer/counter control register .. but this is the second register im setting up CS bits (clock select):
    timer clock select

1024 prescaler = 15625 ticks / sec @ 16MHz: the microcontroller is running with 16 MHz system clock which means
there are 16,000,000 ticks in a second ..
setting the timer prescaler to 1024 means the timer will have
16,000,000 / 1024 = 15625 ticks/sec - OCR0A output compare register when the counter reaches to the value in this register, it will trigger the compare interrupt ISR and will reset the counter..

  • TIMSK0 timer mask i just set the on compare enable interrupt bit here..
    which means that when the timer counter register [TCNT] reaches to the Compare A register [OCR0A] it will trigger special ISR function ..

result:

although the code was and first implementation was done on arduino uno “atmega328”, you can see the datasheet discreption and screenshots are on atmega328 however, the same timer exist in attiny44, here is a good link for avr-libc “inturrept ISRs”: Avr-libc: <avr/interuupt.h> the change in code is the ISR function name:

  • Code:


#define F_CPU 20000000UL

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

volatile static uint8_t x = 1;


ISR( TIM0_COMPA_vect )
{
    x++;
    if (x == 100) // 100* 10ms = 1000 ms
    {
        PORTB ^= 1<<2; //led on io board
        x=0;
    }
}

int main(void)
{
    // CLOCK prescaler to /1 
     CLKPR = (1 << CLKPCE);
     CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
    //Set Direction port B to output pin 13 in arduino
    DDRB = DDRB | 1<<2 ; //led on IO board
    //Timer/counter control register A
    TCCR0A = 0;
    TCCR0A |= 1<< WGM01; // CTC mode - clear counter when reaches to OCR0A
   
    //Timer/counter control register B ->  clk select bits:
    TCCR0B = (1 << CS00 ) | (1 << CS02 );  //1024 prescaler = 15625 ticks / sec @ 16MHz
    //19531.25 ticks / sec @ 20MHz
   
    //output compare A
    //OCR0A = 156;  //  156 * (1/15625) = 9.984ms //for atmega328 16mhz
    OCR0A = 195; //195 / 19531 = 9.984ms //for attiny44 20mhz
    // interrupt mask register
    TIMSK0 |= 1<< OCIE0A; // [output compare A interrupt enable 0]
   
    sei();

    while (1)
    {
     // you can do anything here.. the mcu will blink 1 sec ...
       
    }
}

  • Compile:

    
    avr-gcc -Wall -g -Os -mmcu=attiny44 -o x.bin x.c
    avr-objcopy -O ihex x.bin main.hex
    
    

  • Flash:

    
    avrdude -F -p t44 -P usb -c avrisp2 -U flash:w:main.hex
    avrdude -F -p t44 -P usb -c avrisp2 -U lfuse:w:0x5E:m
    
    


So, what all this is about

this is just demostration of how 8-bit timer/counter in a microcontroller works,
how to schudule a function with time control ..
if you get intreseted, i would suggest to read the datasheet it teaches a lot of things ..

datasheet


good tutorials:

i didnt read them, but went through them very fast i think they really explain better than this post: