Introduction: Fan RPM With Internal Hall Effect Sensor and Arduino (Intro to Hardware Interrupt and LCD Display)

About: A Researcher, an Engineer and an electronics enthusiast

For my other project for work, i had to measure the rotational speed of rotor in Revolutions Per Minute (RPM) of one modified computer fan. It had three wires coming out and that ticked me that may be it has some way to control its speed. With some 'googling' i found such fans have internal Hall effect sensor (HES) that can be used to measure its rotating speed. (And for 4 pin connections fan, the fourth pin is to control the speed of fan using PWM signals.)

This project gives quick intro to-

1) Using Interrupts of arduino boards (here arduino Due)

2) Interfacing internal Hall effect sensor of fan with arduino

3) Displaying real time information on LCD display (here 16 x 2)

4) Implement basic logic in programming arduino (here i used RGB LED to change color depending upon the different range of rotating speed)

Step 1: Introduction: @ Hall Effect Sensor and 3 Pin Computer Fans

Hall effect sensor (HES) works on the principle of interaction of magnetic field with electrons flowing in the conductor and subsequent generation of secondary voltage known as Hall voltage. Read more here. Using hall effect sensor generally speed ranges upto 100 kHz or 100 thousand ticks per second can be measured.

Source of HES animated image -

In three pin fans with internal hall effect sensor, generally yellow colored wire is output of HES. Most of the time it requires external pull-up resistor of few kohm values depending on supply voltage. Instead of external resistor, internal pull-up resistor of our arduino board pins can be used. digitalWrite(pinno, HIGH); in setup() function enables this internal pull-up resistor. Using this technique, HES output wire can be directly connected to interrupt pin (here pin 12) without using an external 10kohm pull-up resistor. I have used external pull-up resistor.

With every rotation of rotor, depending on type of fan i.e. number of magnets attached to rotor, we get 1, 2 or 4 ticks per revolution of rotor as output signal from HES. Read more here. We will pick up these ticks by interrupting our arduino program using "hardware interrupts". Interrupts help in letting our arduino do its regular job until some signal is received at interrupt pins. This lets us use arduino perform other tasks while waiting for signal at interrupt pins.

Step 2: Connection Diagram and Components


CAUTION: Arduino due has 3.3V tolerant pins. If higher than 3.3V is given to any pin of due, it will damage that pin or probably entire board.

1) 16 x 2 LCD 1602 display runs on 5V power supply, I have supplied 5V from Arduino due 5V output pin. The SCL and SDA pins are directly connected to I2C to LCD driver board. It worked perfectly without using any step down voltage regulator.

2) The fan motor is powerd by 12 volt power supply from power supply adapter of an old wifi modem. Depending on your fan rating, you can use 3V, 5V or 12V etc. Make sure you do not connect such high voltage to any of the pins of LCD or Arduino.

3) The ground lines of 12V power supply, Arduino and LCD should all be connected together.

4) In above sketch i have shown all ground lines in black color, 5V supply with brown color, 3.3V with orange color and 12V with red color.

5) If you do not have pull up resistor, internal pull-up resistor of arduino can be enabled as described here. But I am skipping it here to make is easier for beginners.

6) To have some fun, one RGB LED has been added which changes color depending on the speed ranges.

Instead or RGB LED, normal 2 pin LEDs can be used by connecting all ground pins to the resistor as shown in figure.

Bill of materials:-

1) Arduino due board ( or other boards can be used, provided interrupt pins are selected accordingly- read more )

For Uno, Nano, Mini, other 328-based boards- pins 2,3

For Mega, Mega2560, MegaADK- pins 2, 3, 18, 19, 20, 21

For Micro, Leonardo, other 32u4-based- pins 0, 1, 2, 3, 7

For Zero, MKR1000- pins all digital pins, except 4

For Due- all digital pins

2) Resistors - 10k and 470 ohm (you can use any other resistors in similar ranges)

3) PC fan or any other motor with inbuilt hall effect sensor (Or externally connected HES)

4) LCD display with I2C interface ( you can use parallel LCDs too, but pinout and code needs to be slightly modified). For installing I2CLibrary and getting I2C address, check my video -

5) Power supply as per used fan/motor (here it is 12V DC) Fan running at full speed.

6) 3 LEDs or single RGB LED, to use as optical indicator of fan RPM range

Step 3: Working and Code

The working is simple in principle. The hall effect sensor generates signal when the magnets connected to its rotor shaft (internally). Depending on number of magnets connected, for each 360 degree rotation of rotor, 1,2,4 signals will be generated. These signals are picked up by arduino pin (here pin 12). To calculate revolutions per minute or RPM, we count number of signals received in 1 second multiplied by 60 and the result divided by number of signals received in 1 rotation.

Line 74: Speed = ((ticks * 60)/fanspace[fan].fandiv);

In my fan I have two magnets attached, hence I get two signals per revolution. I have selected {1,2} in following part of my code-

Line 33: fanspec fanspace[3]={{0,1},{1,2},{2,8}}; char fan = 1; it means fan type 1 having 2 signals per revolution.

Current algorithm and code gives reasonable accuracy of around 10 RPM and update speed of around 1 second. By optimizing code both can be optimized for faster response and higher accuracy. This will be discussed in future projects.

In the beginning I had problem of having leading zeros or LCD display retaining old digits for lower speed e.g. actual speed comes down from 330 rpm to 60 rpm, it was still showing 360 rpm. This is standard problem of left padding or leading zeros. To overcome this I have added following code-

Line 87: // Converting integer Speed to an ASCII string of 4 characters padded left

char SpeedString[4]; // Buffer to store string of 4 chars + 0 termination

sprintf(SpeedString, "%4d", Speed); // change this to %3, 4 ,5 etc depending upon your max speed lcd.print(SpeedString);

Here I have converted the calculated speed in integer form to string form and then sent to LCD, in this way LCD prints speed considering all digits as one single string or text data.

The final code is available on my github page here.

Have fun with arduino...................................................................


//original code by Crenn from

//original project by Charles Gantt from