Monday, 16 July 2018

Timers on the AVR Microcontroller (Atmega-8)

Aim:

Timers are widely used in industrial and domestic application for automating tasks. Microcontroller scan be used to design versatile and accurate timers with ease. Here I present a simple timer that can be used to turn on/off a load after user specified time.

Description:


What is a timer ?

A timer in simplest term is a register. Timers generally have a resolution of 8 or 16 Bits. So a 8 bit timer is 8Bits wide so capable of holding value withing 0-255. But this register has a magical property ! Its value increases/decreases automatically at a predefined rate (supplied by user). This is the timer clock. And this operation does not need CPU’s intervention.
Since Timer works independently of CPU it can be used to measure time accurately. Timer upon certain conditions take some action automatically or inform CPU. One of the basic condition is the situation when timer OVERFLOWS i.e. its counted upto its maximum value (255 for 8 BIT timers) and rolled back to 0. In this situation timer can issue an interrupt and you must write an Interrupt Service Routine (ISR) to handle the event.
The ATmega8 and ATmega32 has three different timers of which the simplest is TIMER0. Its resolution is 8 BIT i.e. it can count from 0 to 255. Note: Please read the “Internal Peripherals of AVRs” to have the basic knowledge of techniques used for using the OnChip peripherals(Like timer !) The Prescaler The Prescaler is a mechanism for generating clock for timer by the CPU clock. As you know that CPU has a clock source such as a external crystal of internal oscillator. Normally these have the frequency like 1 MHz,8 MHz, 12 MHz or 16MHz(MAX). The Prescaler is used to divide this clock frequency and produce a clock for TIMER. The Prescaler can be used to get the following clock for timer. No Clock (Timer Stop). No Prescaling (Clock = FCPU) FCPU/8 FCPU/64 FCPU/256 FCPU/1024 Timer can also be externally clocked but I am leaving it for now for simplicity.Using The 8 BIT Timer (TIMER0)

AVR Timers – TIMER0

Hello friends! Welcome back to the second part of the AVR Timers Series. In the previous post, we have discussed the basic concepts of AVR Timers. Let me summarize it:
  • We have seen how timers are made up of registers, whose value automatically increases/decreases. Thus, the terms timer/counter are used interchangeably.
  • In AVR, there are three types of timers – TIMER0, TIMER1 and TIMER2. Of these, TIMER1 is a 16-bit timer whereas others are 8-bit timers.
  • We have seen how prescalers are used to trade duration with resolution.
  • We have also discussed how to choose an appropriate value of a prescaler.
  • And then, to finish off, we learnt about interrupts.
So, I will move towards its implementation directly. I have assumed that you have understood the concepts discussed above.
In this tutorial, we will learn to use TIMER0. Since timer is a peripheral, it can be activated by setting some bits in some registers. Instead of discussing all the registers at once, we will be discussing them as and when necessary. For those who are new to the term ‘register’, they can read about it from this page. To have an idea about AVR Peripherals, view this page (you need to scroll down a bit).

Problem Statement

Let’s define a problem statement for us. The simplest one being the LED flasher. Let’s say, we need to flash an LED every 6 ms and we are have a CPU clock frequency of 32 kHz.
Well, I know that an LED flashing at every 6 ms will be always visible as on by our eye, but I could not find any simpler example which does not include prescalers. Take this as a demonstration.

Methodology

Now, as per the following formula, with a clock frequency of 32 kHz and 8-bit counter, the maximum delay possible is of 8 ms. This is quite low (for us, but not for the MCU). Hence for a delay of 6 ms, we need a timer count of 191. This can easily be achieved with an 8-bit counter (MAX = 255).
Timer CountThus, what we need to do is quite simple. We need to keep a track of the counter value. As soon as it reaches 191, we toggle the LED value and reset the counter. For this, we need the help of the following registers.

TCNT0 Register

The Timer/Counter Register – TCNT0 is as follows:
TCNT0 Register
TCNT0 REGISTER
This is where the uint 8-bit counter of the timer resides. The value of the counter is stored here and increases/decreases automatically. Data can be both read/written from this register.
Now we know where the counter value lies. But this register won’t be activated unless we activate the timer! Thus we need to set the timer up. How? Read on…

TCCR0 Register

The Timer/Counter Control Register – TCCR0 is as follows:
TCCR0 Register
TCCR0 REGISTER
Right now, we will concentrate on the highlighted bits. The other bits will be discussed as and when necessary. By selecting these three Clock Select BitsCS02:00, we set the timer up by choosing proper prescaler. The possible combinations are shown below.
Clock Select Bit Description
CLOCK SELECT BIT DESCRIPTION
For this problem statement, we choose No Prescaling. Ignore the bits highlighted in grey. We will be using it later in this tutorial. Thus, we initialize the counter as:
TCCR0 |= (1 << CS00);
Please note that if you do not initialize this register, all the bits will remain as zero and the timer/counter will remain stopped.
Thus now we are ready to write a code for this. To learn about I/O port operations in AVR, view this. To know about bit manipulations, view this.

Block Diagram

2.interfacing array of leds

Schematic:

2 blinking array of leds

Code

// **********************************************
// Project: Interfacing 8-bit timer0 to atmega8
// Author: Hack Projects India
// Module description: Operate array of LED's
// **********************************************

#define F_CPU 8000000UL
#include<avr/io.h>
#include <util/delay.h>

int main()
{
 DDRB=0xff;
 TCCR1B = (1<<CS10) | (1<<CS12); //set the pre-scalar as 1024
 OCR1A = 1562;     //100ms delay
 TCNT1 = 0;
 while(1)
 {
  //If flag is set toggle the led
  while((TIFR & (1<<OCF1A)) == 0);// wait till the timer overflow flag is SET
  PORTB = ~PORTB;
  TCNT1 = 0;
  TIFR |= (1<<OCF1A) ; //clear timer1 overflow flag
 }
}

Downloads:

The code was compiled in Atmel Studio 6 and simulation was made in Proteus v7.7.
To download code and proteus simulation click here.

Further Reading suggestions:

No comments:

Post a Comment