RPM control by varying PWM
connections:
the Arduino's ground (GND) is connected to the 0V of an external 12V power supply, establishing a common ground. The Arduino's 5V pin is connected through a 10k ohm pull-up resistor to the fan's tacho output (yellow wire), and Arduino pin 2 is used to read this tacho signal for RPM measurement. Arduino pin 9 is connected to the fan's control input (blue wire) to provide PWM signals for speed control. The fan is powered directly from the 12V supply, with its power input (red wire) connected to 12V and its ground (black wire) connected to 0V. This configuration allows the Arduino to control and monitor the fan's speed.
1st method:
-Arduino in default settings
-pin 9 outputs 490hz pwm freq
-digital pin2 acts as interrupt to launch the subroutine counter to keep track of pulses
- The motor typically has a built-in sensor ( Hall effect sensor) that generates pulses as the motor rotates. Each pulse corresponds to a fixed angular displacement of the motor shaft.
- the feedback provided by the tachometer (RPM sensor) allows the Arduino to monitor the motor's actual speed, enabling it to adjust the PWM signal accordingly to achieve and maintain the desired speed setpoint. This closed-loop control mechanism helps ensure precise speed control and regulation of the motor.
-in default settings max pwm value is 255, where we increment 51 (0%,20%,40% and so on till 100%)
-further we send the pwm value to fan using analogWrite command and wait 5 secs and further reset count to zero and count how many pulses occur in 1 sec and to convert it to min we multiply by 60 and divide by 2 as there are 4 pulse magnets
Code:
//LOWSPEEDPWM
cost int fan_control_pin = 9;
volatile unsigned long count = 0;
unsigned long start_time;
int rpm;
const int pulses_per_revolution = 2;
void setup() {
pinMode(fan_control_pin, OUTPUT);
analogWrite(fan_control_pin, 0);
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(2), counter, RISING);
}
void loop() {
for (int pwm = 0; pwm <= 255; pwm += 51) {
analogWrite(fan_control_pin, pwm);
delay(5000);
start_time = millis();
count = 0;
while ((millis() - start_time) < 1000) {
}
rpm = (count / pulses_per_revolution) * 60;
Serial.print("PWM = ");
Serial.print(map(pwm, 0, 255, 0, 100));
Serial.print("%, Speed: ");
Serial.print(rpm);
Serial.println(" rpm");
}
}
void counter() {
count++;
}
Output:
PWM = 20%, Speed: 32520 rpm
PWM = 40%, Speed: -4756 rpm
PWM = 60%, Speed: -16712 rpm
PWM = 80%, Speed: -17868 rpm
PWM = 100%, Speed: -19444 rpm
2nd method:
-high freq pwm
-pin 9 still used , outputs 25khz not 490hz
-reconfigures pin 9 and 10 for high pwm output
-to get 25khz we need to get max value to 320 and not 255
-instead of analog output commands we use OCR1A and ORC1B to get pwm on these pins
- we increment 64 here and instead of analog write we set pwm=OCR1A
Code:
//HIGHSPEEDPWM
const int fan_control_pin = 9;
volatile unsigned long count = 0; // volatile for interrupt use
unsigned long start_time;
int rpm;
const int pulses_per_revolution = 2; // Number of pulses per fan revolution
// Declare the counter function before its use in setup
void counter();
void setup() {
// Timer1 configuration for PWM on pin 9
TCCR1A = 0; // Clear Timer1 control registers
TCCR1B = 0;
TCNT1 = 0; // Clear Timer1 counter register
TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11); // Mode 14: Fast PWM, ICR1 is top, non-inverting mode
TCCR1B = _BV(WGM13) | _BV(CS10); // No prescaler, Fast PWM
ICR1 = 320; // Top value for PWM resolution
pinMode(fan_control_pin, OUTPUT);
OCR1A = 0; // Ensure no PWM signal is sent at startup
OCR1B = 0;
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(2), counter, RISING); // Interrupt on pin 2 for tachometer signal
}
void loop() {
for (int pwm = 0; pwm <= 320; pwm += 64) {
OCR1A = pwm;
delay(5000);
start_time = millis();
count = 0;
while ((millis() - start_time) < 1000) {
}
rpm = (count * 60) / pulses_per_revolution;
Serial.print("PWM = ");
Serial.print(map(pwm, 0, 320, 0, 100));
Serial.print("%, Speed: ");
Serial.print(rpm);
Serial.println(" rpm");
}
}
void counter() {
count++;
}
Output:
PWM = 0%, Speed: 6270 rpm
PWM = 20%, Speed: 9732 rpm
PWM = 40%, Speed: -26494 rpm
PWM = 60%, Speed: 10751 rpm
PWM = 80%, Speed: 4300 rpm
PWM = 100%, Speed: -17824 rpm
3rd method:
- Control a 4-pin CPU fan using PWM at 25khz and then read back the fan speed using a 10kohm pullup resistor.
-same connections
Code:
#include <PWM.h>
volatile int half_revolutions; // Allow half_revolutions to be accessed in interrupt
int rpm; // Set rpm as an integer
int current_pwm = 0; // Set initial PWM value (0% duty cycle)
const int pulses_per_revolution = 2; // Set the number of magnets per revolution
void setup() {
InitTimersSafe(); // Initialize timers for PWM control
bool success = SetPinFrequencySafe(9, 25000); // Set PWM frequency to 25kHz
pwmWrite(9, current_pwm); // Set initial PWM value
pinMode(2, INPUT); // Set RPM pin to digital input
half_revolutions = 0;
rpm = 0;
Serial.begin(9600);
}
void loop() {
for (int pwm = 0; pwm <= 255; pwm += 51) { // Vary PWM from 0 to 100%
pwmWrite(9, pwm); // Set PWM value
delay(5000); // Wait for 5 seconds at each PWM value
// Measure RPM
sei(); // Enable interrupts
attachInterrupt(digitalPinToInterrupt(2), fan_rpm, RISING); // Record pulses as they rise
delay(1000); // Wait for 1 second to measure RPM
detachInterrupt(digitalPinToInterrupt(2));
cli(); // Disable interrupts
rpm = (half_revolutions * 60) / pulses_per_revolution; // Calculate RPM based on half revolutions
Serial.print("PWM: ");
Serial.print(map(pwm, 0, 255, 0, 100)); // Map PWM value to percentage
Serial.print("%, SPEED: ");
Serial.print(rpm);
Serial.println(" rpm");
Serial.println();
rpm = 0;
half_revolutions = 0;
}
// Reset PWM to 0% duty cycle at the end
pwmWrite(9, 0);
}
void fan_rpm() {
++half_revolutions; // Increment half revolutions
}
Output:
PWM: 0%, SPEED: 7860 rpm
PWM: 20%, SPEED: 8085 rpm
PWM: 40%, SPEED: 8145 rpm
PWM: 60%, SPEED: 7905 rpm
PWM: 80%, SPEED: 7740 rpm
PWM: 100%, SPEED: 7860 rpm
PWM: 0%, Half-revolutions : 477 (rpm=7155)
PWM: 20%, Half-revolutions : 14482(rpm=217230)
PWM: 40%, Half-revolutions : 17080(rpm=256200)
PWM: 60%, Half-revolutions : 21239(rpm=318585)
PWM: 80%, Half-revolutions : 27077(rpm=406155)
PWM: 100%, Half-revolutions : 23436(rpm=351840)
Expected RPM values:
2%
2500
RPM
10%
6700
RPM
20%
12400
RPM
30%
17700
RPM
40%
22200
RPM
50%
26200
RPM
60%
29600
RPM
70%
33200
RPM
80%
36700
RPM
90%
40000
RPM
100%
40000
RPM
I'm getting varied values please help me as soon as possible










