controlling 3-wire PC fan speed and reading rpm accurately

My current project involves controlling the speed of a 3-wire PC fan using a series of resistors and a multi-position switch. The circuitry is still in the prototyping stage, because I want to achieve specific fan speeds, and I’m still finding the right levels of resistance to do this. However, it works fine: increased resistance, decreased fan speed.

I am reading the fan speed with Arduino (specifically a SparkFun RedBoard and code for the Arduino Uno) attached to the 3rd wire of the fan, using the fan’s Hall-effect sensor. This was easy to set up, and it reads the rated speed for several different PC fans with reasonable accuracy for my purposes.

The problem I have is that in my prototyping, when continuing to increase the resistance and lower the fan speed, at a certain point the rpms are no longer being read accurately – my Arduino set-up will actually read the same value as the fan with no resistance or even a higher rpm than the fan’s rating, despite the increased resistance. The fan itself is physically rotating slower with the added resistance, but I cannot get an accurate rpm reading – and my project requires knowing the rpm speed with some certainty.

I’m still a newbie when it comes to coding for Arduino, so I’ve used two different sets of code I’ve found online, with the same results: reads fan speed with no problems, until the speed is lowered beyond a certain point, then it gives me numbers that do not reflect the fan speed (usually these numbers vary more in value than when reading a known fan speed). I’ve also tried this with two fans of the same type, same manufacturer. (I tried this experiment with another fan, but when the resistance gets too large, it just doesn’t start; every fan has its limitations…)

I’m guessing the problem is either with the code I’m using (which seems to be designed for reading whatever speed the fan was designed to run at, without my after-market modifications), or is related to the sensor (how the sensor works, how the manufacturer wired the sensor into the fan, …?).

Any ideas where the problem might be, and if there is a way I can get an accurate rpm reading at those lower speeds/higher resistances?

[I am aware of a project involving reading fan speed with light and a photoresistor, which would work, but that’s getting more complicated than I want for this fan speed project right now.]

Thanks for any help & advice…

Okay could be a number of issues, but most likely it is a hardware problem:

  1. The hall sensor inside the fan gets its power from the fan’s power supply. Depending on the specs of this sensor it may simply be no longer working properly at the low voltage levels. If this is the case, then there is not much you can do other than fitting an external sensor.

  2. I’m not sure what sort of output (open collector, etc) the hall sensor in the fan is producing, but the threshold voltage on the Arduino input at which it can detect pulses is around 2V. If the signal level falls below this, the Arduino is not going to be able to detect the pulses. To be honest, I would expect the signal to disappear completely if this is happening so it may not be the problem.

The easiest way to figure out what is going on is to have a look at the signal with a scope and check the voltage levels and whether it is producing a glitch free output at low speed. If you rule this out then the problem lies in software and you’ll need to take a look at how the code works.

If you don’t have a scope, then its a lot harder. I would try to hook up a transistor buffer to the hall output so you can be sure it is not a voltage level issue. Actually, I would just sample the input with the ADC and use that as an oscilloscope.

If you do need an external sensor, you can probably just tape a hall effect to the outside of the fan motor. The leakage from the rotor magnets should be enough to trigger it.

I once read a tutorial or blog about this. The writer had problems detecting reliable RPM pulses because the Hall sensor failed to detect the passage of the magnet that was due because the power to the fan was turned off. (obvious when you think of it) So, by synchronising the fan On/Off timing with timing of the predicted pulse (the fan should be on while the RPM pulse is going on) he could get reliable pulses. I don’t know how he did the tracking of the pulse and adjusting the power-PWM dutycycle and frequency in detail. Don’t have the link any more unfortunately, but that was the gist of it.