Hello, everyone.
I've used search and found several similar topics, but was not able to find something that would help me.
I understand electrics at a basic level, but am quite a newbie at electronics. This is my first real Arduino project. I'm, though, a software developer (currently web development, did C/C++ some 15+ years ago), so hopefully will have less trouble in the programming department.
I'm working on a temperature-sensitive automatic fan speed controller for a fan that is cooling my lathe's motor. I decided to approach this step-by-step, so first thing I'd like to do is to be able to control the fan speed using a potentiometer, and also read the actual RPM reported by the fan's tachometer. I will deal with the lathe motor temperature measurement later.
The fan is a 4-pin Noctua NF-A14 industrialPPC-2000 IP67 PWM (basically a fancy 140mm PC fan).
Here's the link for Noctua technical info on their fans.
After hooking up a potentiometer to the Arduino, I followed this article. I've set the PWM frequency to 25 KHz as mentioned in Noctua's pdf. This worked without any issue, the fan can be controlled with the pot from almost 0 to max RPM.
I wanted to be able to measure the fan's RPM, mostly to be able to tell if the fan is not working properly for some reason. So I tried to hook up the tachometer output, based mostly on this instructable. I didn't quite understand why the tachometer signal is pulled up to the 3.3V pin. I modified the code based on other snippets I found, I also tried the original code and several different variants.
The problem is, I'm getting really strange readings. Only with PWM set to 100% duty, I'm getting something that seems somewhat reasonable - around 1760 RPM (the fan is rated at 2000 +/- 10% RPM). At 0% duty I'm getting 0 RPM, and everything is between displays around 20000-30000. It seems that the interrupt is firing really often for some reason. The fan is new so I'm guessing something is wrong either with my code, or with the wiring of the circuit.
Connections:
Arduino UNO, powered via USB
Fan power connected to a 12V bench power supply.
Fan PWM connected to pin 9 on the Arduino.
Fan tachometer connected to pin 2 on the Arduino (directly, internal pull-up resistor enabled).
Power supply's ground connected to Arduino ground.
Attached is a screenshot from Noctua's pdf. It mentions "Vcc for 12V fans: 13V", while I have 5V from the Arduino. I am wondering if this 13V is just the max allowed Vcc. If I understand Arduino's INPUT_PULLUP pin mode correctly, I should have the same circuit as prescribed by the picture.
Code:
const byte OC1A_PIN = 9;
//const byte OC1B_PIN = 10;
const byte TACHO_PIN = 2;
const byte POT_PIN = A0;
const word PWM_FREQ_HZ = 25e3; // Adjust this value to adjust the frequency
const word TCNT1_TOP = 16e6 / (2 * PWM_FREQ_HZ);
volatile unsigned int tachoPulses = 0;
unsigned int rpm = 0;
unsigned long lastRpmMillis = 0;
void setup() {
Serial.begin(9600);
pinMode(OC1A_PIN, OUTPUT);
pinMode(TACHO_PIN, INPUT_PULLUP);
attachInterrupt(0, countTachoPulse, RISING);
// Clear Timer1 control and count registers
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
// Set Timer1 configuration
// COM1A(1:0) = 0b10 (Output A clear rising/set falling)
// COM1B(1:0) = 0b00 (Output B normal operation)
// WGM(13:10) = 0b1010 (Phase correct PWM)
// ICNC1 = 0b0 (Input capture noise canceler disabled)
// ICES1 = 0b0 (Input capture edge select disabled)
// CS(12:10) = 0b001 (Input clock select = clock/1)
TCCR1A |= (1 << COM1A1) | (1 << WGM11);
TCCR1B |= (1 << WGM13) | (1 << CS10);
ICR1 = TCNT1_TOP;
}
void countTachoPulse() {
++tachoPulses;
}
void loop() {
int potValue = analogRead(POT_PIN);
setPwmDuty(map(potValue, 0, 1023, 0, 100));
unsigned long elapsedTime = millis() - lastRpmMillis;
if (elapsedTime >= 1000) {
noInterrupts();
rpm = 30e3 / elapsedTime * tachoPulses;
tachoPulses = 0;
interrupts();
lastRpmMillis = millis();
Serial.println(rpm, DEC);
}
delay(50);
}
void setPwmDuty(byte duty) {
OCR1A = (word) (duty * TCNT1_TOP) / 100;
}
Appreciate your help in advance ![]()
--Gene




