Using Arduino interrupts to read RPM from a fan
I need to read the RPMs of some 12v PC fans so I wrote up a quick sketch to have an ESP32 monitor and log the RPM for me. You need to use an external interrupt that triggers every time the fan rotates (it triggers 2x per full rotation). I was having crashes before I added the ICACHE_RAM_ATTR
parameter to the function. ICACHE_RAM_ATTR
tell Arduino to store this function in RAM instead of on the flash. The logic here is that your interrupt function will probably be getting called a lot so it needs to be fast.
Connect the yellow RPM wire from your fan to pin 4, and the ground wire from the fan to the ground of the Arduino. Without the ground wire connected you will now have a shared ground between the Arduino and the fan and the interrupt will not fire.
const uint8_t tachoPin = 4;
volatile uint32_t counter = 0;
ICACHE_RAM_ATTR void countPulses() {
counter++;
}
void setup() {
pinMode(tachoPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(tachoPin), countPulses, FALLING);
Serial.begin(115200);
}
void loop() {
delay(1000);
Serial.printf("%u fan revolutions in the last second\n", counter / 2);
counter = 0;
}
Note: This code will work on an Arduino Uno without the ICACHE_RAM_ATTR
which can be confusing.
Note: Using the internal pull-up resistor on the ESP32 means you can connect the yellow fan wire directly to the MCU. On an Arduino Uno an external pull-up resistor is required.