Skip to content

Tachometer using AVR Atmega16

March 1, 2008

Overview: Tachometer is used to measure speed of motor or shaft or propeller. This tachometer is designed using ATMega16 micro-controller and runs at 16MHz. It can be configured for multiple propellers. Also measuring time interval can be varied for better accuracy. Attractive feature of this is it measures speed without any physical contact with shaft or motor. It shows RPM speed on LCD and Tachometer setting can be changed from simple push buttons. It uses low cost infrared Tx-Rx pair for sensing propellers. It can measure RPM speed up to 90k RPM. No mechanical part is used hence low cost (less than Rs.500) and maintenance free.


Processor: I have used ATMEGA16 here. It is 8-bit RISC processor with maximum frequency up to 16MHz. It has on chip analog comparator and 3-timers running parallel. One timer is used for frequency calculation where as another timer is used for generating PWM for DC motor. Because of its simple architecture and tool availability it is very popular. If you are working first time on AVR then here are some cool tutorials on AVR micro-controller:

AVR : Tutorial 1: Introduction to AVR

AVR : Tutorial 2 : AVR – Input / Output


Make your own, ultra simple, universal AVR programmer !!

Sensors: Most important part of this Tachometer is sensors. It uses low cost infrared sensors for sensing propellers. IR LED will transmit IR rays and on reflection from propeller receiver generates some analog voltage. This analog voltage is sensed by ATMEGA16on-chip analog comparator and generates an interrupt to micro-controller.  This sensor will generate train of analog voltage pulses. Frequency of these pulses/No of propellers will be equal to frequency of resolution.  While measuring motor speed connect DISC to motor shaft painted with two different colours.

I wanted to design a demo board which will have motor as well as tachometer. So here I am controlling motor also using same micro-controller. PWM is used to vary motor speed.  Motor speed can be set in 8 step sizes.

Input/Output Device: Low cost 16×2 character LCD is used for displaying menu, Tachometer configuration and RPM Speed.  Just four push buttons are used for input – Plus, Minus, Select and Exit. Making small changes in your C Programme you can use UART and use computer serial terminal as output device and computer keyboard as input Device and control it from PC.


LCD Display Connections: Two Line Character LCD is used as Display fro Tachometer. 8-bit LCD is configured in 4-bit mode. Connections are as shown in pic:

NOTE: Here in simulation I have given Sine wave for testing. AINx should be connected to IR sensors.

Tachometer Menu: Tachometer Menu is user friendly. You can change menu using +/-.  Enter into Menu by pressing select and press exit to go previous menu.  LCD shows display as follows.

Tachometer has three main menus:

1. Propellers:While measuring speed MCU need to know how many propellers are used. You can vary number of propeller up to 8. By default it is one.

2.Motor Speed: Motor speed is to just control motor connected to PWM channel. If you are using it as tachometer only then ignore this menu. You can set motor speed in 8 steps. As you increase speed duty cylces are modulated and motor varies its speed.

3.Interval: Interval is in seconds. MCU measures RPM speed over that this time interval. This is helpful for improving accuracy.


Tachometer Simulation (Download and rename it to Tachometer.divx)




1-0.jpg<————–>-SELECT-EXIT<———–>1-1.jpg Varies 1-8


2-0.jpg<————–>-SELECT-EXIT<———–>2-1.jpgVaries 1-8


untitled.jpg<————–>-SELECT-EXIT<———–>3-1.jpgVaries 1-64

Software: Code is written in C and Compiled with CodeVisionAVR.  This code is completely interrupt based and most of the time CPU is Idle. Main code only displays data on LCD where we can configure Tachometer. Once it has been configured (i.e. No of propellers, Time interval for measurement), calculation part is handled by Timer-1 interrupt.  Here I have used two interrupts

1. Analog Comparator interrupt: Which is generated on rising edge of output of analog comparator. Infrared sensor input is connected to AIN0 and some reference voltage should be given at AIN1. Sensitivity of infrared sensor can be varied by changing reference voltage at AIN1. This interrupt subroutine increment counter. In other words it counts simply number of rising edges.

2. Timer 1 interrupt: This interrupt is generated after every 1 second. It has also local counter. If this local counter is equal to time interval set by user then it will start calculation of RPM speed. i.e. If user set time interval as 4 seconds then this interrupt will simply increment interval counter till it reaches to 4. When time interval is equal to 4 seconds then this interrupt subroutine starts RPM calculation also. For this it uses analog comparator counter to find number of rising edges in given time interval. After display it resets all counter.

C code is as follows


Enhancement: As mentioned earlier also hyper terminal can be used to access/control tachometer and vary motor speed from PC. Also for sensing multiple motor speed use 8-in build ADCs (PORTA) to sense analog voltages. Hence No extra hardware is needed.

  1. elecrom permalink

    Hey Nice Tut Ashish !

  2. elecrom permalink

    Hey, how you have uploaded Tachomete.c to wordpress ?

  3. Hi Ashish,

    Contact less tachmeter is a good one, can you tell me how infrared sensing is working and its detail schematics with part number so that it I can purchase proper component and build it
    Uttam Dutta

  4. thank’s ashishd..

  5. woswasi permalink

    nice code but:
    if you write to registers use read/modify/write instead of writing the whole register.

    makes the code more readable and prevents mistakes 😉

    for example: you want to set PORTB[7:3] to output and PORTB[2:0] to input with pull-ups dont use
    DDRB = 0xF8;
    PORTB = 0x07;


    DDRB |= _BV(PB7) | _BV(PB6) | _BV(PB5) | _BV(PB4) | _BV(PB3);
    //DDRB &= ~(_BV(PB0) | _BV(PB1) | _BV(PB2)); //not needed when used for DDR init, because register is initialized with 0x00
    PORTB |= _BV(PB0) | _BV(PB1) | _BV(PB2);
    //PORTB &= ~(_BV(PB7) | _BV(PB6) | _BV(PB5) | _BV(PB4) | _BV(PB3)); //not needed when used for PORT init, because register is initialized with 0x00

    instead (where _BV(x) == (1<<x) )

    yes its more to write but easier to read and debug…


    • ashishd permalink

      I use codevisionavr and initialcode is generated by CodeVisionAVR Wizard. I am not expert in C programming. I recommend you should write your own code.

  6. wlewis permalink


    Hi, very nice.

    Do you happen to have bcd.c / bcd.h and mega16.h ?

  7. manu permalink

    there’s no driver for motor?

    • ashishd permalink

      This is just a simulation. You will have to use driver for L293D motors.

  8. tekno permalink

    I have tried compile the code with code visionAVR but there is an error,,,,
    Error: D:\MIKRO\TACHO\tc.c(83): the expression must be a modifiable lvalue
    Error: D:\MIKRO\TACHO\tc.c(87): the expression must be a modifiable lvalue
    Error: D:\MIKRO\TACHO\tc.c(91): the expression must be a modifiable lvalue
    Error: D:\MIKRO\TACHO\tc.c(95): the expression must be a modifiable lvalue
    Error: D:\MIKRO\TACHO\tc.c(99): the expression must be a modifiable lvalue
    Error: D:\MIKRO\TACHO\tc.c(123): the expression must be a modifiable lvalue

    please help me…
    I’m beginner in microcontroller.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: