Friday, 7 September 2012

Frequency meter (Counter) using ATmega16 or ATmega8


In this tutorial we are going to build simple frequency meter (frequency counter) using ATmega16 and codevision avr compiler. This simple frequency meter (frequency counter) can measure frequency up to 4Mhz (theoretically) because we are using 8Mhz clock for the ATmega16 micro-controller. But you can use an external crystal oscillator of frequency 16Mhz and increase uo the range to 8Mhz.

How it works :

The idea behind the frequency meter is so simple as frequency or Hz means the number of pulses (cycles) in one second. So, This is what we are going to do. We are going to count the number of pulses of a signal in one second and this is simply the frequency of the signal.

In details, we are going to use timer1 of ATmega16 to count the pulses of the signal we are going to measure it's frequency (external pulses on T1 pin2 (PB1)) and use the normal mode. we will start counting the pulses and make a delay of one second then we stop the timer and read it's register (TCNT1) which contains the number of pulses (counts).

But here you are going to ask what if timer1 have made an overflow???
The answer is very simple, We enable the overflow interrupt of timer1 and we count the number of overflows made by timer1 and the overflow means that timer1 has made 2^16 count (65536 counts as it's a 16 bit register) so the number of pulses in one second will be calculated using the following equation :

Frequency = i*2^16 + TCNT1

Where i is the number of overflows in one second.

The reading of the frequency meter is updated every 1 second.

Here is a sample of the code with comments as possible :

#include <mega16.h>

// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x1B ;PORTA
#endasm
#include <lcd.h>  /* the reading is displayed on LCD */
#include <delay.h>
#include <stdlib.h>  /* this library is used to display variables on lcd ( More details ) */

unsigned long int freq;  /* to store value of frequency value */
unsigned int i=0,dur;  /* i=number of overflows in one second */
/* dur to store the value of TCNT1 register */
char buffer[8];
/* array char to store the frequency value as a string to be displayed on lcd ( More details ) */
float freqf;    /* used to display the fractions of frequency with the suitable unit as shown later */

// Timer1 overflow interrupt service routine

interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
i++ ;  // count the number of overflows in one second
}

void main(void)
{
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x04;

// LCD module initialization
lcd_init(16);

#asm("sei")

while (1)
      {                  
      TIMSK=0x04;  // enable overflow interrupt of timer1 
      TCCR1B=0x07;   /* start timer1 with external pulses (T1 rising edge) */
      delay_ms(1000);    // wait for one second
      TCCR1B=0x00;    //stop timer1
      TIMSK=0x00;     //disable interrupt
      dur=TCNT1;       /* store the number of counts in TCNT1 register */
      freq = dur + i*65536; /* calculate the frequency as in previous equation */
      TCNT1=0x0000;  /* clear TCNT1 register for the next reading */
      i=0;     /* clear number of overflows in one second for the next reading */
//////////////////// display ////////////////////////
      lcd_gotoxy(0,0);
      lcd_putsf("freq=");
      lcd_gotoxy(0,1);
      if(freq>=1000000)    /* if frequency more than or equal 1Mhz use "Mhz" on lcd */
      {
      freqf=(float)freq/1000000;  //divide by 1Mhz scale
      ftoa(freqf,3, buffer);
      lcd_puts(buffer); 
      lcd_putsf("MHZ");
      }
      else if (freq>=1000)  /* if frequency more than or equal 1khz use "Khz" on lcd */
      {
      freqf=(float)freq/1000;
      ftoa(freqf,3, buffer);
      lcd_puts(buffer); 
      lcd_putsf("KHZ");
      }
      else   // if frequency less than 1khz use "hz" on lcd
      {
      ltoa(freq, buffer);
      lcd_puts(buffer); 
      lcd_putsf("HZ");
      }    
      };
}

Practical Results :

Actual Frequency
Measured Frequency
Relative error
10 hz
10 hz
0 %
100 hz
97 hz
3 %
1 khz
0.963 khz
3.7 %
10 Khz
9.62 Khz
3.8 %
100 khz
96.1 khz
3.9 %
1 Mhz
0.961 Mhz
3.9 %
3 Mhz
2.88 Mhz
4 %

The max frequency measured theoritically is 4Mhz but in practical it's 3Mhz with max error 4 % .

Here is a short video showing the circuit working :

video

You can download the code and simulation file from the following link :

NEW : Here is the same cicuit of frequency meter but using ATmega8 microcontroller.


You can download the code and simulation files from the following link :
Download Here

You can download this tutorial in PDF from the following link :
Download Here