Timers
Timers
Pre-information for the readers that this article will be long as I intend it to be. This article could
be made short as well but it will lead you directly into topic without clarification and real life
examples. Earlier on I used to prefer books and articles with less volume. I found their contents to be
memorized and some of them don’t go through my head due to which I stopped reading for several
hours and spent those hours just feeling the pain of my head. If those books and articles were
presented with examples and clear idea of the topics being discussed despite it takes several texts or
pages, those hours of pain would be spent learning in delightful manner. This refrain me being limited
to less volume resources and attract towards dense resources as well. As a consequence of this, I
attempt to present the contents of my article including examples and somehow long explanation
although it results to long article which readers find less attracted too. What I believe through this
article is reader spends more time reading and learning than avoiding after few lines but I could be
wrong as well and if it is I pre-apologize for that.
Pre-Introduction
Since the development of human civilization time has been a matter of concern. In the days
when the present days clocks were not invented, human still are aware of time with the help of the
Sun, the Moon. The shape of shadow during day time helps to keep track to hours. People would wait
for a big full moon to travel out at night. These methods does not provide exact time and are not
applicable when the sky is not clear. Considering this lacking many advancement had taken place and
now we have come to the phase that we can track even micro or nanoseconds. Remember that we
are still in the path of advancement.
Suppose you wake up 6 AM in the morning, study 2 hours, be at school for 6 hours, watch movie
of 2 hours and 11 minutes, sleeps for 8 hours. If you are late to something like waking up then you say
I wake up 45 minutes late today. You tell that seeing the clock. Your body has inbuilt clock due to
which you feel sleepy after 10 pm if you have sleeping habit at 10 pm. Your day to day activity is
synchronized with time.
Don’t think only of human, electronics components work on time basis too. You may have used
the terms like my computer or mobile is slow or faster in comparison to others. To open a image or
display what you typed on your screen, it takes no time but takes a bit of time to turn off or on your
computer. So these are all related with time.
Due to the huge importance for time to human world, AVR manufactures have included inbuilt
hardware for timer so that external hardware is not needed for this.
Like enabling internal pull-up resistor from software, we can use timer with some few lines of code.
This contributes much to make embedded systems like washing machine, AC, etc that operate with
time.
The AVR timer can handle a few microseconds(like the ticks of a processor) to many hours (like
child playing time), accurately to the resolution of microseconds.
Slowly lets enter into the topic. You must have heard of processor speed. If not then atleast
while buying mobile or computer you see processor specification like 2.4GHz. Go to the internet and
find the processor speed of your phone and computer. My laptop has speed of 4 GHz(Giga Hertz).
If I ask you about frequency then you can atleast tell something or write an essay about it.
Simply it is the number of times an event occurs per unit of time. Suppose I want to check how much
words can I type per minute and after checking I found that I can type only 35 words per minute, so I
need to improve my typing skill. You can check yours and can improve by practicing. But for now, see
what I am considering in this case as event. Its “typing words” and “minute” as unit time. So my
frequency of typing words is 35 words per min. In case of computer, we consider instructions that we
provide to computer like clicking mouse, keyboard press, run movie or like that as event. Second is
standard unit time as given by the International System of Units(SI). We used words(event) per
minute as unit of frequency. But Hertz(Hz) is the SI unit, which tells no of times an event occurs per
second.
Again to be familiar with GHz term I want to remind you of GB. You tell I’ve 500 GB(Giga Byte) of
hard disk. Here Giga refers to (1 or sth)*109. 1 GB = 1 billion bytes. Like that 1GHz = 1 billion Hertz.
Finally you should be ready to tell that your mobile processor has specification of 2.4GHz means your
mobile can run 2.4 billions instructions per second. Now you may believe your mobile can detect 2.4
billions pressed at a time, but its not. For each key pressed your mobile processor has to do some
tasks like stop other recent operations, focus on key press, detect which key and much more such
that it can understand what instruction you are giving to your mobile. Its takes 100s of instruction to
display in the screen what you press. So better to tell 2.4 billion machine lBe careful with the case of
the letters, before underscore is the name of the peripheral or interrupt source all in capital letters. If
the source has more than one sub source like timer can produce interrupt for overflow and compare
match then the name of sub source should be include after underscore in capital letters. Finally
‘_vect’ which is in small letters is added at the end which is short form of vector. Simply understand
that vector is added in the parameter name as it gives direction to AVR to perform task whenever
interrupt takes place. For more information see “AVR’s interrupt tutorial ” online.
evel instructions per second. Its fine if you don’t understand, just feel cool up to where you have
learned.
AVR has frequency in the range of MHz(Mega Hertz) which is 1000 times smaller than GHz. It is
because computer and mobile are for multitasking i.e. you need to watch movie, do calculation, use
internet, and many more with the same device. But AVR is mostly used for specific purpose like only
printing in case of printer or control temperature in case of AC.
In your earlier steps of learning AVR, you may have blink LED at an interval of 1 second or like
that. The example code for it is:
int main(void) {
LED_DDR = (1 << LED1);
while(1) {
LED_PORT ^= (1 << LED1); // Toggle LED after each second
// to make it appear blink
_delay_ms(DELAY_TIME);
}
return 0;
}
If the code is clear to you then its fine continue reading. Otherwise see my bit twiddling article to
understand “^”, “|”, “<<” operators and the whole code.
This is an example of time based project. The above code works fine if your task is to only blink a
LED using AVR. But what if I want to blink another LED at an interval of 2 sec.
From above code, “util/delay.h” header file is included and F_CPU is defined to 1MHz
before including the header file. Note that F_CPU should be defined before including the
“util/delay.h” header as the code inside the header file search for the definition of F_CPU in the
lines preceding its inclusion, if defined below shows warning message and considered default
value define inside the code which is normally 1MHz. With this definition we are telling that
frequency of CPU or AVR is 1MHz, 1*106 machine cycle instructions per second. UL at the end
denotes the value is of unsigned long type to the compiler as the value is greater than the range
the integer data type can handle.
In ATmega32 we can select the operating frequency of 1, 2, 4 or 8MHz by changing some
fuse bit(just extra information, I won’t teach you how to do that here as it doesn’t come under
this topic). Or if you want other frequencies than that, you can use external crystal or
resonator.
You have to provide the exact frequency of your AVR in the F_CPU definition. Initially the
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
LED_DDR = (1 << LED1) | (1 << LED2);
while(1) {
LED_PORT ^= (1 << LED1);
_delay_ms(DELAY_TIME1);
LED_PORT ^= (1 << LED2);
_delay_ms(DELAY_TIME2);
}
return 0;
}
Does this work? I believe not. When we enter into the while loop the first LED remains ON for 1
sec because of the delay function. After that next instruction is executed which makes second LED ON
for 2 sec. At this time both LEDs remain ON. After 3 sec only the first LED turns OFF which does not
match our requirement.
Some of you may think of replacing the while part with the below statements:
Introduction
Basically, a timer is a register like PORTx, DDRx, etc. But has special features than other registers.
The value of this register increases/decreases automatically independent of AVR CPU(main processor
of AVR that executes the instruction provided by us) i.e. the increment/decrement in the value of that
register takes place even if the AVR is performing some other task. like timekeeper observing time
while teacher is teaching. For this reason timer gives us accurate result. In AVR, timers are of two
types: 8-bit and 16-bit timers. In an 8-bit timer, the register used is of 8-bit whereas of 16-bit in case
of 16-bit timer. So, the 8-bit timer can count up to 2^8=256 steps from 0 to 255 and 16-bit timer up to
2^16=65536 steps. Due to this it is considered as counter and you will see timer/counter as it can be
used to know time as well as count events like no of men entering a room, no of vehicles over
speeding, no of peas coming out of machine... Suppose it is in auto increment mode. After some time,
the register stores its maximum value. What happens after that? Does the timer stops working from
now on or AVR also stops its operation? Well, no such things take place. It returns to its initial value
i.e. zero. We say that the timer overflows.
Timer Concepts
The timer register store the numbers but we need time like 10 ms(mili seconds) or 5 sec as our
tasks will be like blink LED every 1sec or take data from sensor every 10ms. So how to convert the
number in the register into time?
AVR has a clock inside it which generates clock signal, a signal that oscillates between a high and
a low state.
In the figure there are 6 clock signals. If the AVR frequency is set to 1MHz then 1 million such
clock signals are produced in 1 sec. If so, how much time does it take to produce one clock signal?
Using unitary method you can get it.
Time Period = 1
Frequency
This also gives the same result.
If you have idea of the up counter register, you are well aware of the information that the
register gets incremented at each clock pulse. Else you take a tour of “register” or just keep that in
mind that it takes one clock pulse to go from 0 to 1, another clock pulse to go from 1 to 2 and so on.
In terms of time, the timer register changes from 0 to 1 after one microsecond, 1 to 2 after another
microsecond and so on(consider 1MHz frequency). With this you can convert the register value into
equivalent time. Doesn’t it fell like opposite to you. We know how much delay we want but not the
value of the register. If so how to know the register value according to required delay?
Its lower level mathematics time.
Note
Time period of a clock signal = HIGH time + LOW TIME.
If considered only HIGH time, it is called clock pulse.
The digital circuits like ICs, flip-flops get synchronized with clock pulse. To
understand this statement lets consider a up-counter register. The register value
increases with the clock signal provided to it. So here, clock signal and the register
are operating simultaneously.
The clock signal is of certain time period. During this time period of clock signal,
at what time the up-counter gets incremented? The answer is either at the
rising(leading) edge, falling(trailing) edge or during the pulse width(edge triggered or
level triggered if you have heard of). Among this options only one is used and it may
be already defined or the programmer gets to choose. You will get to choose either
rising edge or falling edge in the timer of AVR later on.
How many counts are possible between 0 and 255? First count when the register changes its
value from 0 to 1, second from 1 to and like that we get 255 counts. In case of 8-bit timer as I
mentioned earlier, when it reaches 255 it again gets back to 0. To change the register value from 255
to 0 it takes one clock cycle. During this one clock cycle another change also takes place within AVR to
indicate the timer count has reached its maximum value. Its in overflow flag which is one of the bit of
a register of AVR. If you are keen to football then referee raises the flag to indicate foul or offside. You
can consider this overflow flag similar to that. If this bit is 1, the overflow flag is raised to indicate the
maximum reach of timer and if 0, no overflow. Will you be confused if I say the 8-bit counter can
count up to 256? Up to 255 you are sure but 1 extra how? Previously included, one extra clock pulse is
required to indicate the AVR, overflow takes place. So 255 counts and this extra clock pulse makes
count of 256. For simplicity, consider 0 as extra count as one extra clock pulse is required to become
value 0 from 255. Similar in the case of 16 bit register considering 2^16(65536) instead of 2^8(256)..
Back to the count and timer relation. 1 count is equal to 1 clock signal which is equal to
reciprocal of frequency(1s for 1MHz frequency). 8-bit counter can count maximum of 256 which
means we can have maximum delay up to 256s. This delay is huge for AV although negligible to
human persistence. Don’t waste you time imagining of having delay more than this. By the end of this
article you will have knowledge more than you are imagining now.
Let me introduce the registers. Focusing ATmega32A it has 3 timers:
Timer0 - 8-bit timer
Timer1 - 16-bit timer
Timer2 - 8-bit timer
To get to know 8-bit timer, I will consider Timer0. Formerly talked register which stores count
from 0 to 255 for Timer0 is TCNT0(Timer/Counter0).
It is a read/write register i.e. value can be written to it as well as its value can be read as shown
below.
Observe that I’ve used “unsigned char” instead of int. It’s because our requirement is to store
the TCNT0 value which is of 8 bits or 1 byte. Int occupies 2 bytes memory while unsigned char
occupies 1 byte memory. As AVR has very less memory, programmers should be concerned of
minimizing as much memory use as possible. But for 16-bit timer unsigned int type variable is
required.
In AVR there is a register, TIFR(TImer/Counter Interrupt Flag Register) and it has a bit named
TOV0 which is generally 0 but becomes 1 when overflow takes place in Timer0. Through this bit, AVR
gets to know whether overflow occured or not.
Always consider the point that whenever overflow takes place we have to do something like
blinking led or increment a variable to count some event or like that. Following the above conditions, I
mean to say 1 MHz frequency, if we need to have 256 s then we set TCNT0 to 0 although it is
initially 0 just for our confirmation or as an example that we can provide any initial value to TCNT0
register. The register then starts to increment from that initial values every clock pulse. To have delay
of 256 s we need 256 time count or clock pulse and this much time count is obtained when the
register value increments from 0 and overflows or changes from 255 to 0. So we need to check the
TOV0 flag to know this and this is done through the code shown below:
You surely will understand the condition for if statement if you are familiar to bit
twiddling/manipulation otherwise learn it first from here. The statement below if, “LED_PORT... “ is
also clear to you which toggles the LED state each time overflow tales place. But why the statements
below them are necessary? “TCNT0 = 0;” is not necessary in this case but still I’ve included it. The
reason for this will be cleared to you in the next example. Remember that “TIFR |= ...” statement is
necessary.
Whenever overflow takes place in Timer0, TOV0 bit becomes 1, TCNT0 becomes 0 and then 1, 2,
3, ......, 255 after each clock pulse. After 255, overflow takes place and sets TOV0 flag but TOV0 flag is
already set. To know whether the overflow has occurred for second time or not, we have to clear the
TOV0 bit after performing the required task which in this case is to blink LED. Actually clearing the
overflow flag is one of the task to be done whenever overflow took place. To clear the bit we have to
set that bit, which is guided by the data sheet. This seem confusing to you and may even think this
one as mistake and should be “TIFR &= ~(1 << TOV0); but the previous one is 100% correct. From now
on, be sure that when I say to clear any flag bit, you should write the code to set that bit manually
which results 0 to that bit. If this bit was not cleared, the condition for if will be true forever after the
first overflow. So LED toggles at around 2 s delay.(To check how much delay has been provided, you
need oscilloscope or you can check virtually using simulation software like proteus.)
Try to write the code for 50 s delay.
Using this formula we obtain TCNT0 initial value as 206 and the code is;
TCNT0 = 206;
if (TIFR & (1 << TOV0)) {
LED_PORT ^= (1 << LED_PIN); .
TCNT0 = 206;
TIFR |= (1 << T0V0); // Clear TOV0 bit
}
Here if TCNT0 is not set to 206 then the count starts from 0 which is not what we required.
As you see, in this method we are checking manually whether overflow occurred or not. It’s kike
you have kept your mobile phone in silent mode and you are manually checking time to time whether
someone has called you or not. Maximum time you see no call, if you see call also it may be missed
and there is rare chance that you attain the call. You are wasting your valuable time for checking your
phone and you must not like it. This method is called polling and is not effective. You know why from
the phone example. Like this if you observe the delay time using oscilloscope or simulation software
in the AVR, you will get somehow more delay than required. As a solution to phone checking problem,
must of keep our phone in ringing or atleast in vibration mode due to which phone itself notify us
whether or not someone is calling us and there is less chance of missing call. If your are playing game
in your phone and someone calls you, the phone will interrupt your game and notify you about the
phone call. You can use any function of your phone but your operation is interrupted whenever you
have a phone call. So such method is called interrupt and is available in AVR too.
To keep your phone in ringing mode you have to do some task to enable interrupt method.
Likewise there is some job for you to be done to enable interrupt in AVR. After that you have to group
the tasks your would like AVR to do whenever overflow takes place inside a special function called
Interrupt Service Routine(ISR) as the AVR looks inside thid function to know what to do whenever
overflow takes place.
To know how to enable interrupt we need to know about another register called
TIMSK(Timer/Counter Interrupt Mask Register).
In the above register you will find TOIE0(Timer/Counter Overflow Interrupt Enable 0) bit and
you need to set this bit . Just don’t care if you don’t understand other bits but you can see and guess
what other bits does.
The function which is executed whenever interrupt takes place look like this:
ISR(TIMER0_OVF_vect) {
LED_PORT ^= (1 << LED_PIN);
TCNT0 = 206;
}
Like DDRx, PORTx etc being defined under <avr/io.h> file, ISR, TIMER0_OVF_vect are defined
under <avr/interrupt.h> file, so need to be included for using it in program.
Just like your phone interrupt you by notifying you for call, message, facebook notification etc,
AVR also has to handle different types of interrupt sources, ATmega32 has 3 timer and each timer has
two interrupt sources: one is overflow and another compare match. Other peripherals present inside
AVR like UART, EEPROM, ADC etc also have interrupt sources. You have to perform one task
whenever timer0 overflows and another task whenever timer2 overflows. How do you provide the
separate task? ISR() takes an parameter, like TIMER0_OVF_vect in above code which specifies what
task to perform for what interrupt source. The above code does not run whenever timer2 overflows
as it is specified for timer0. To perform the same task for timer2 as well we have to write another
ISR() function with TIMER2_OVF_vect as an parameter.
Be careful with the case of the letters, before underscore is the name of the peripheral or
interrupt source all in capital letters. If the source has more than one sub source like timer can
produce interrupt for overflow and compare match then the name of sub source should be include
after underscore in capital letters. Finally ‘_vect’ which is in small letters is added at the end which is
short form of vector. Simply understand that vector is added in the parameter name as it gives
direction to AVR to perform task whenever interrupt takes place. For more information see “AVR’s
interrupt tutorial ” online.
In the code you must have noted that I have not clear the overflow flag manually as it is done by
the ISR() function implicitly.
There is one more thing I need to tell you in the interrupt. Like our house’s electrical wiring
system contains a main switch which can turn off all the lights in our house despite the switch to
control that light is on, AVR also has a main switch which should be enabled before using interrupt
otherwise just enabling the individual interrupt enable(e.g. TOIE0 bit for timer0 overflow) bit won’t
work. To enable the AVR’s interrupt main switch we need to write sei() in our code and to disable it,
cei().
You have shown patience till now, there is one more topic to introduce you and then you are
capable to some fun thing with timer of AVR.
The Prescaler
I’ve made you capable of introducing delay up to 256us, not more than that. The formula for
maximum delay we can have using 8-bit timer is:
This is not new formula. If you replace count with 256, required delay with max delay and
rearrange the formula, we obtain this formula. This formula shows the inverse relation of max delay
with frequency. If we are able to reduce the frequency we can increase the delay time. Instead of
1MHz if we use 0.5MHZ , the maximum delay time increases to 512us. There is a range of frequency
in which AVR can operate on. Moreover if we decrease the AVR frequency the AVR becomes less
responsive and takes longer time to execute instructions which we don’t want.
AVR provides a feature to decrease the frequency of clock provided to timer keeping the
operating frequency of AVR or actual F_CPU as it is. This technique of frequency division is called
prescaling. We can do this by setting some bits of TCCR0(Timer/Counter Control Register).
The bits highlighted by yellow color, CS00(Clock Select 00), CS01 and CS02 are used to set clock
frequency for timer0.
Leave last two options foe now in the table below.
Doing nothing with this register bits means we are providing 0 to CS00, CS01 and CS02 by
default. This will disable the timer0 as shown by the above table. To enable the timer and providing it
with frequency equal to F_CPU/ clkI/o we have to set CS00 bit and clear other two bits. Similarly 1 to
all 3 bits will enable timer 0 with frequency equal to F_CPU/1024(if F_CPU = 1MHz, timer frequency =
976.5625Hz and max delay = 262ms ). You may be clear from the table that you cannot divide F_CPU
value by any random numbers. You should choose one of the prescale from the available one and no
more than that.
You see the advantage of prescaling. You should be aware that prescaling decreases resolution.
Here resolution is the minimum time that can be measured. Using 1MHz frequency you can have
minimum delay of 1us but with prescale of 1024 reduces 1MHz frequency to around 977Hz and
minimum delay possible is around 1 ms which is its resolution. If you wish to have delay of 3us, it is
not possible using 1024 prescale.
/*-- Description : Toggle LED at 184ms delay using timer0 with prescale 1024.
* F_CPU frequency is 1MHz which makes timer frequency equals 976.5625
* For the delay of 184ms timer count equals req delay*time period
* i.e. .184*976.5625 = 179.69 ~ 180 counts
* After 180 counts the timer should overflow for which TCNT0 value should be
* equal to 256 - 180 = 76
* WITHOUT INTERRUPT
* Date : 29th May 2020
*--*/
The output is shown using Proteus simulation software. In actual the output may not be as
accurate as shown here. To get the accurate result you should use external crystals or resonators.
Later I will show how to use it but for now continue using internal RC oscillator or take help of
internet.
2. Interrupt method(184ms delay)
/*-- Description : Toggle LED at 184ms delay using timer0 with prescale 1024.
* F_CPU frequency is 1MHz which makes timer frequency equals 976.5625
* For the delay of 184ms timer count equals req delay*time period
* i.e. .184*976.5625 = 179.69 ~ 180 counts
* After 180 counts the timer should overflow for which TCNT0 value should be
* equal to 256 - 180 = 76
* USE OF INTERRUPT
* Date : 30th May 2020
*--*/
void timer0_init_with_interrupt() {
TCCR0 = (1 << CS02) | (1 << CS00); // Prescale of 1024
TCNT0 = 76; // As calculated in Descrition
TIMSK |= (1 << TOIE0); // Enable the interrupt for timer0 overflow
}
ISR(TIMER0_OVF_vect) {
PORTB ^= (1 << PB0); // Toggle PB0
TCNT0 = 76; // Again start the connt from 76 rather than 0
// TIFR |= (1 << TOV0); Clear the overflow flag statement is commented as
// this is done automatically by ISR function
}
int main(void) {
DDRB = (1 << PB0);// Set PBO to OUTPUT
timer0_init_with_interrupt();
PORTB |= (1 << PB0);
sei(); // Enable global interrupt. This is like turning ON the
// meter box of our home electricity system. Not including this
// function is similar to keeping meter box off and we cannot turn
// on the light with individual switch.
return 0;
}
For output see the video shown in the link
In the oscilloscope you can see square wave as we are toggling the output state of PB0 pin at an
interval of 184ms. Can you tell me the frequency of square wave being generated? I will help you if
you can’t or it will be revision for you if you can. The time period of the square wave equals 184 + 184
= 368ms as it is the sum of high and low time. Frequency being inverse of time period give the
frequency of the square wave equals 1/(368*10^(-3)) = 2.72Hz.
1 second delay or more using 8-bit timer
Even the maximum prescale which is 1024 can give us some mili seconds of delay. What to do if
1 second delay is require? Lets slowly step forward.
Consider I am using AVR in 1MHz frequency. In case of timer0 I am using this frequency with
prescale of 64 which means timer0 operating frequency is 1000000/64 = 15.635KHz i.e. in 1S 15635
clock pulse are generated and as 1 clock pulse equals 1 count, 15635 counts are required. But
maximum of 256 count is possible in 8-bit timer. After that overflow occurs and starts to count from 0
again to overflow. This process continues as long as the AVR is on if our program does not contain
code to stop it. For the second overflow to take place 512 clock pulses or counts are required
considering from the beginning. Likewise additional 256 clock pulse are required for the third
overflow which makes total of 768 counts. This gives us idea that the overflow count helps to acquire
longer delays.
How may overflows are needed for our required delay is to be calculated and it is possible by
dividing the required count by 256, considering only the integer part and neglecting the decimal
part.
15635/256 = 61.07421875, considering only integer part give us 61 overflows are required for 1
sec delay.
The time delay for 61 overflows equals to 61*256*1/15635(61*256 is the count no and 1/15635
is the time period) = 0.998784778 seconds delay. This is not equal to 1 sec delay because in 61
overflows we are counting only 61*256 = 15616 counts which is (15635 - 15616) = 19 count less. To
include this 19 count also we require TCNT0 register value equal to 19 after 61 overflows. This will be
clear in the programming section.
To keep record of the number of overflows we require a variable. The variable should of global
type as this variable is to be used inside ISR() function and may be inside while loop as well. This is not
enough. The variable should be of volatile type. volatile keyword prevents compiler for modifying or
simply don’t allow to be smart. As this variable is controlled by ISR() function, the compiler believes
the modification is mistakenly done and don’t allow the modification without this keyword which will
be undesired result in our case. volatile keyword is especially used in embedded C. You make internet
your friend for more information.
/*-- Description : Toggle LED at 1s delay using timer0 with prescale 1024.
* F_CPU frequency is 1MHz which makes timer frequency equals 15625
* For the delay of 1s timer count equals req delay*time period
* i.e. 1*15625 = 15625 counts
* After 256 counts the timer overflows for the first time and second
* overflow takes place at (256 + 256) 512 counts. Counting the no of
* overflows we can have greater delays.
* No of overflows required = 15625/256 = 61.07421875.
* But no of overflows can be interger value only so 61 is the required
* no of overflows.
* After 61 overflows time count = 256* 61 = 15616.
* Remaining counts = 15625 - 15616 = 19
* Date : 31th May 2020
*--*/
#include <avr/io.h>
#include <avr/interrupt.h>
ISR(TIMER0_OVF_vect) {
overflows_count ++;
if(overflows_count == 61) {
while (1)
;
return 0;
}
You can use the statement to increment the overflow_count variable inside the ISR() function
and the remaining polling part inside the while loop. Inside while loop you don’t need to wait until
TCNT0 becomes 19. You can replace the while loop with the if. But to do this the condition should be
like if(TCNT0 >= 19). Although we require exactly the count of 19 but we need to use “greater than or
equal” symbol. This is because the timer and the code execution are run independently. When the
timer counts 19 the execution of code may be at somewhere other than this if statement. When the
code execution reaches the if statement the timer count value will be other than 19 which makes if
statement false and brings error. This brings some inaccuracy in delay which we should consider.
If have seen other tutorials you may find the code at the beginning of timer like
while (1) {
if(TCNT0 >= 180) {
PORTB ^= (1 << PB0);
TCNT0 = 0;
}
TCNT0 value always starts with 0 and the required count is kept inside the if statement to
compare with the current TCNT0 value. This brings inaccuracy for small delays like in micro or
miliseconds which avoids me to teach you this method at the beginning and use the overflow concept
by changing TCNT0 value rather than starting it with 0.
See we have used both polling and interrupt method. Polling method is less accurate than
interrupt by some microseconds but for greater delays microseconds inaccuracy does not affect
much.
CTC mode
So far we were talking about normal mode. Its time to move another step forward in timer by
knowing about CTC mode.
The AVR hardware knows when the timer count value overflows or reaches its maximum value
(255 in case of 8-bit and 65535 in case of 16-bit). But for some middle value like 180, we were
checking manually i.e. using software which is not so accurate. To increase accuracy, AVR timer
provides a way by which the AVR hardware knows by itself when the timer count value reaches 180 or
any other possible values the timer can count. The CTC(Clear Timer on Compare) mode is for this.
With this, we no longer have to worry about comparing the timer count value we required. We are
given a register OCR0 (for timer0) where we can provide the required time count value like 180.
When the TCNT0(in case of timer0) value reaches the required time count value, the TCNT0 value
clears to 0 in the next clock pulse, the flag OCF0 in the register TIFR is set as in case of overflow
condition. The name CTC for this mode is because of the reason, the hardware itself compares the
value
What happen is known but how to make it happen or how to use timer in CTC mode? This will be
the topic for further discussion.
You may have started worrying about the registers and its bits as the course increases. I will list
all the registers used for timer0 so that you know how much registers are to be known and don’t
need to fear of how many new registers to come:
1. TCNT0
2. OCR0
3. TIFR
4. TCCR0
5. TIMSK
The first two registers are for count purpose so its individual bits does not worry us. We are to
be aware of individual bits of the remaining three register, each register is of 8 bits which make us to
know about 24 bits. Also the registers whose name ends with ‘0’ are only for timer0 and the
remaining registers are common to all the three timers available in ATmega32.
To enable CTC mode we have to deal with TCCR0 register as it is control register for timer0. We
are familiar with three of its bits, clocks select bits and its time to know additional two bits WGM00
(Wave Generation Mode) and WGM01.
Don’t thing Mode as bit rather consider it as SN. I won’t make you clear about the last three
columns for now. We are now focused to CTC mode only so setting the WGM01 bit fulfill our job. You
may also be clear that doing nothing to these bits sets our timer in Normal mode.
For this also we need to calculate the required time count and the formula is similar but not
same as above.
Required Delay
Time Count = ------------------------ - 1
Clock Time Period
Time Count = Required Delay*Frequency - 1
(Frequency is inverse of time period)
8 500000 9999
64 62500 1250
256 15325 312.5
1024 3906.25 78.125
To have exact time delay you should choose prescale such that time count value is purely
integer. . So we can either choose 8 or 64 as prescale but timer0 can’t count up to that value. This is
the case where you required timer1 which can count up to 65535. Note that if time count is less than
256 then its best to use timer0 than timer1 as timer0 provides less load to the AVR since our AVR
being 8-bit can process only 8-bit at a time. To process 16-bit data like timer1 count value the AVR
splits it into two 8-bit value and process one by one. We are forced to choose prescale of 1024
despite of its inaccuracy as we are dealing with timer0. Time count in this case is 78, considering
integer part only.
I’ve missed one thing to inform you i.e. like TOV0 flag in the TIFR register when set indicates
overflow, OCF0(Output Compare Flag 0) in the same register when set indicates compare match took
place. And the parameter to be passed inside the ISR() function for this case is
“TIMER0_COMP_vect”. With this information you are ready to program yourself. You can either
check the flag manually or use interrupt method. I will choose interrupt method to demonstrate you.
/*-- Description: Toggle the state of PB0 at each 20ms time using CTC
* mode of timer0
* Date: 3rd June 2020
* --*/
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 4000000UL // If you can change the fuse bits set the
// AVR frequency to 4MHz otherwise do calculate for 1MHz and operate
// like this
#include <util/delay.h>
ISR(TIMER0_COMP_vect) {
LED_PORT ^= (1 << LED_PIN);
}+
void timer0_setup() {
TCCR0 = ((1 << CS02) | (1 << CS00) | (1 << WGM01));
TCNT0 = 0;
OCR0 = 78;
TIMSK = (1 << OCIE0);
sei();
}
int main() {
LED_DDR = (1 << LED_PIN);
DDRB = (1 << PB1);
timer0_setup();
while(1) { // The code inside while loop is just to show that timer runs
// independent of AVR cpu and can perform any task as required
// while the timer is doing its job. For now I’m blinking LED at PB1.
PORTB ^= (1 << PB1);
_delay_ms(1000);
}
return 0;
}
If you see the video demo for this code then you must notice that LED remains off all the time. This is
because of a mistake in the code. The mistake is at the second statement inside main. I should have
writ “DDRB |= (1 << PB1). The missing of ‘|” has made everything wrong. This is related to bit
twiddling. The missing of this “|” made PB0 or LED_PIN as input. It was done by me unknowingly
which took me a lot of time to debug. Then instead of correcting it myself I believe it best to show you
the incorrect result, tell its consequences and made you to correct yourself so that you don’t need to
spend time in debugging such problem in future.
These bits control the Output Compare pin(OC0) behaviour. OC0 pin, can you find this pin? If
not you surely will find the PB3 pin in ATmega32, this is OC0 pin. This pin can perform multiple
function. It can be used as PB3 or OC0 or even AIN0 but we won’t talk about this. Consider this like
multimeter which can be used as voltmeter, ammeter, ohmmeter or more depending on its
configuration done by us. How to choose between PB0 and OC0. COM00(Compare Match Output
Mode) and COM01 bits play the role for it.
Initially these bits are 0 due to which this pin functions as PB0. Any changes to this bit will enable
the pin as OC0.( Notice one thing that to use as OC0, you must set it to OUTPUT mode in DDRB
register.) Here compare match indicates TCNT0 value equals to the value provided by us in OCR0
register. The above table is true for not only CTC mode but works for normal mode as well. But they
have some differences which will be shown below.
The time vs TCNT0 graph for CTC mode is as shown below:
You can clearly see that TCNT0 value is cleared when reaches OCR0 value and can’t go above
that despite the timer has capacity up to 255 count. So the top value, which is the value up to which
TCNT0 can count in this case is equal to OCR0 where as maximum value of TCNT0 is 255. But in
normal mode, top value equals the normal mode as timer continues to count up until it reaches the
maximum value.
The difference between normal mode and CTC mode exits at the toggle OC0 case i.e. set COM00
bit. At each compare match the logic state (HIGH and LOW or 0 and 1 or 0V and 5V)of OC0 pin is
changed. This generates square wave. Note AVR being digital, can generate square wave only. When
we talk about wave it has certain frequency.
The TCNT0 value vs time graph and the equivalent square waveform generated for the two
modes is observed like below.
It should not be necessary to tell you which one is normal mode and CTC mode.
Can you calculate the frequency of the square wave in normal mode? You may can but first I’ve
to provide some information about frequency of the timer which I considered to be 16MHz. This
should be enough. Try on your own or follow me if you are confused.
The frequency of the wave generated by CTC mode can be controlled by changing the OCR0
value but the frequency remains same as long as the timer frequency is constant in case of normal
mode.
`
Demonstration of square wave generation using CTC mode (Coding without ISR())
/*-- Description: Toggle the state of OC0 at each 20ms time using CTC
* mode of timer0 completely by hardware itself i.e. disabling the
* GPIO pin PB3 and enabling OC0 which is another functionality of that
* pin.
* The frequency of the square wave so generated is equal to 1/(20+20)
* = 25Hz
* Here no interrupt is necessary. The timer is performing its job and
* the AVR cpu other jobs independently or say parallelly.
* Date: 3rd June 2020
* --*/
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 4000000UL
#include <util/delay.h>
void timer0_setup() {
TCCR0 = ((1 << CS02) | (1 << CS00) | (1 << WGM01) | (1 << COM00));
// prescale of 1024, CTC mode and toggle OC0 on compare match
TCNT0 = 0;
OCR0 = 78; // For 20ms delay.
}
int main() {
LED_DDR =(1 << LED_PIN);
DDRB |= (1 << PB1);
timer0_setup();
while(1) { // The code inside while loop is just to show that timer runs
// independent of AVR cpu and can perform any task as required
// while the timer is doing its job. For now I m blinking LED at PB1.
return 0;
}
The task for you is to do the same for normal mode by configuring the WGM00 and WGM01 to 0.
This will change the frequency of square wave. Include the frequency of the wave so generated in the
description.
/*-- Description: Changing the duty cycle by changing the OCR0 value with in the
* program.
* F_CPU frequency = 1MHz = Timer frequency
* Time period of one count = 1us
* Time period of square wave = ON + OFF time = 70*1us + 100*1us = 170us
* This ON time (70us) is achieved by providing OCR0 value equal to 69 (70-1) and
* setting TCCR0 value such that it operates in CTC mode, set on compare match
* and no prescale.
* For OFF time OCR0 value equals 99, TCNT0 is configured in CTC mode, clear on
* compare match, no prescale.
* Frequency of square wave = 1/170us = 5.88KHz
* Duty cycle = (70/170)*100% = 41.18%
* Date: 5th June 2020
*--*/
#include <avr/io.h>
#define F_CPU 1000000UL
int main(void) {
DDRB = (1 << PB3); // Set PB3(OC0) as output
while(1) {
OCR0 = 69;
TCCR0 = (1 << CS00) | (1 << WGM01) | (1 << COM01) | (1 << COM00);
// No prescale, CTC mode, set on match
while (!(TIFR & (1 << OCF0))); // Wait until OCF0
// flag is set
TIFR = (1 << OCF0); // Clear OCF0 flag
OCR0 = 99;
TCCR0 = (1 << CS00) | (1 << WGM01) | (1 << COM01);
while (!(TIFR & (1 << OCF0))); // Wait until OCF0
// flag is set
TIFR = (1 << OCF0); // Clear OCF0 flag
}
return 0;
}
Do you have any confusion that using timer such way is fully independent of AVR CPU but we are
controlling it through while loop? Its still true that the operation is independent of AVR CPU. The
output of the OC0 pin is becoming HIGH and LOW but you can’t see any code like “PORTB = (1 <<
PB3);”, we are just configuring the hardware and remaining job is done by hardware itself. So
understand like this, the timer setup can be changed any time from the program and the timer
performs the task according to the setup itself without aid of CPU.