RPM control using PWM for blower ba5025h12b

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

Welcome to the forum

As your topic does not relate directly to the installation or operation of the IDE it has been moved to the Programming Questions category of the forum

Please follow the advice given in the link below when posting code, in particular the section entitled 'Posting code and common code problems'

Use code tags (the < CODE/ > icon above the compose window) to make it easier to read and copy for examination

https://forum.arduino.cc/t/how-to-get-the-best-out-of-this-forum

In my experience the easiest way to tidy up the code and add the code tags is as follows
Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

pls tell me what to do to the code to make it run so i get correct rpm values

First do what @UKHeliBob suggested.
We can't read your code as posted.

Hi, @kaushik0_0
Welcome to the forum.
We need some basic information so we can help you.

Can you please tell us your electronics, programming, arduino, hardware experience?

Can you please post a copy of your circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

What model Arduino are you using?

Can you please post a link to specs/data on the fan?
Does the data indicate the PWM frequency required?

Do you have a DMM? (Digital MultiMeter)

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

i did that can you please help

yeah sure
i am a beginner in arduino programming
using arduino IDE with arduino uno


the above is my circuit diagram
the fan is blower ba5025h12b
i basically want to control RPM using PWM
but i am getting negative values of rpm when i power it with 12v external supply and run the code
and yes i have DMM

//method 1:
const int pwm_pin = 9;
const int tach_pin = 2;
volatile unsigned long pulse_count = 0;
unsigned long start_time;
int rpm;
const int pulses_per_revolution = 2;

void setup() {
  pinMode(pwm_pin, OUTPUT);
  analogWrite(pwm_pin, 0);

  pinMode(tach_pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(tach_pin), pulseCounter, RISING);

  Serial.begin(9600);
}

void loop() {
  for (int pwm = 0; pwm <= 255; pwm += 51) {
    analogWrite(pwm_pin, pwm);
    delay(5000);

    pulse_count = 0;
    start_time = millis();
    delay(1000);

    rpm = (pulse_count * 60) / pulses_per_revolution;

    Serial.print("PWM is: ");
    Serial.print(map(pwm, 0, 255, 0, 100));
    Serial.print("%, RPM: ");
    Serial.print(rpm);
    Serial.println(" rpm");
  }
}

void pulseCounter() {
  pulse_count++;
}

i tried the above code also but I'm getting huge varying outputs can you please help me out asap
output:
image

but according to datasheet output is supposed to be this:
image

i also used the below code to count the pulseper revolution as it is required for rpm : that also gives me varies values:
image
code:

const int tach_pin = 2;
volatile unsigned long pulse_count = 0;
unsigned long start_time;
unsigned long elapsed_time;
int known_rpm = 1200;
float pulses_per_revolution;

void setup() {
  pinMode(tach_pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(tach_pin), pulseCounter, RISING);
  Serial.begin(9600);
}

void loop() {
  pulse_count = 0;
  start_time = millis();
  delay(1000);

  elapsed_time = millis() - start_time;

  pulses_per_revolution = (pulse_count * 60.0) / known_rpm;

  Serial.print("Pulses counted in ");
  Serial.print(elapsed_time);
  Serial.print(" ms: ");
  Serial.println(pulse_count);

  Serial.print("Pulses per revolution: ");
  Serial.println(pulses_per_revolution);

  delay(5000);
}

void pulseCounter() {
  pulse_count++;
}

the pulses per reV according to many fans are around 2 right?

What does the datasheet say about the tach output?
Is it open collector, NPN, PNP, 12V pulse?

Hi, @kaushik0_0

Can you post some images of your project?
So we can see your component layout.
Please show your 12V power supply.

Thanks Tom.. :smiley: :+1: :coffee: :australia:

not sure have asked the vendors will let you know soon nothing is mentioned in data sheet though but it is powered by 12v and the board attached to the blower has hall sensor integrated

yeah sure will do


the above is the 12v power supply i used

the connections are:
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.



sir it is an open collector NPN circuit where i have pulled up the tach output with a 10k resistor and connected to 5V of the arduino

How many pulses per revolution?
PPR is fixed in hardware and does not vary, so if the rotor turns 1 revolution, how many pulses are produced?

there are 2 Pulses per revolution when fan runs for one round but when i used 2 in the code it still was giving me negative value of rpm and like when i reverse engineered it to find the pulses per revolution from a fixed rpm i was getting varied values of ppr

I have set the pwm duty cycle as 100% and tried but I'm not getting rpm closer to 40,000 as mentioned in datasheet

const int pwm_pin = 9;
const int tach_pin = 2;
volatile unsigned long pulse_count = 0;
unsigned long start_time;
int rpm;
const int pulses_per_revolution = 2;  

void setup() {
  pinMode(pwm_pin, OUTPUT);
  analogWrite(pwm_pin, 0);

  pinMode(tach_pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(tach_pin), pulseCounter, RISING);

  Serial.begin(9600);
}

void loop() {

  int pwm = 255;
  analogWrite(pwm_pin, pwm);
  delay(5000);

  pulse_count = 0;
  start_time = millis();
  delay(1000);

  rpm = (pulse_count * 60) / pulses_per_revolution;

  Serial.print("PWM is: ");
  Serial.print(map(pwm, 0, 255, 0, 100));
  Serial.print("%, RPM: ");
  Serial.print(rpm);
  Serial.println(" rpm");
}

void pulseCounter() {
  pulse_count++;
}

output:
image

See what this does:

const int pwm_pin = 9;
const int tach_pin = 2;
volatile unsigned long pulse_count = 0;
unsigned long pulseCopy;
unsigned int rpm;
const int pulses_per_revolution = 2;  

void setup() {
  pinMode(pwm_pin, OUTPUT);
  analogWrite(pwm_pin, 0);

  pinMode(tach_pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(tach_pin), pulseCounter, FALLING);

  Serial.begin(9600);
}

void loop() {

  int pwm = 255;
  analogWrite(pwm_pin, pwm);
  delay(1000);
  noInterrupts();
  pulseCopy = pulse_count;
  pulse_count = 0;
  interrupts();
  rpm = (pulseCopy * 60) / pulses_per_revolution;

  Serial.print("PWM is: ");
  Serial.print(map(pwm, 0, 255, 0, 100));
  Serial.print("%, RPM: ");
  Serial.print(rpm);
  Serial.println(" rpm");
}

void pulseCounter() {
  pulse_count++;
}

image
i tried didnt make a difference its still varying too much