Go Down

Topic: Controlling 4pin fan with PWM 25Khz (Read 9135 times) previous topic - next topic

Myneo

Hello, first of all thanks for reading this post. I'm completely stuck on a project. I am currently doing my first project with my first microcontroller.
I'm making a culture chamber with a CFL bulb, 2 relays, a DHT11 (a temperature sensor), a moisture sensor and so far everything was doing well. (i'll post the code for the entire project if needed, but it's a bit long)
However, if most of it worked i couldn't manage to set the Fan I used at the speed i wanted, with any code it would run full speed.

The Fan is a Cooler Master A14025-20RB-4CP-F1.
It functions on 12v 0,8A.
And is powered by an adaptor (the ground is connected to the adaptor and to the arduino)
- on -
+12v on red
and signal plugged correctly

When i plug the adaptor The fan runs at full speed.
I wrote this code to see if i could Set the fan's speed;

Code: [Select]

 int VentPin=3;
void setup() {

pinMode(VentPin, OUTPUT);
}

void loop() {
  analogWrite(VentPin, 60);

  delay(5000);
 
  analogWrite(VentPin, 60);

  delay (5000);

  analogWrite(VentPin, 255);
 

}


But the Fan just kept going 100%. So I've found that the PWM of my Arduino Uno wasn't in 25KhZ which was the frequency of my PWM's fan. (can't say if i've said in properly haha)

I Used this new code using a PWM library:

Library can be found here:
http://forum.arduino.cc/index.php?topic=117425.0
on this link:
https://code.google.com/archive/p/arduino-pwm-frequency-library/downloads

And Here's the code:
Code: [Select]

#include <PWM.h>

//use pin 11 on the Mega instead, otherwise there is a frequency cap at 31 Hz
int led = 7;                // the pin that the LED is attached to
        // how many points to fade the LED by
int32_t frequency = 25000; //frequency (in Hz)

void setup()
{
  //initialize all timers except for 0, to save time keeping functions
  InitTimersSafe();

  //sets the frequency for the specified pin
  bool success = SetPinFrequencySafe(led, frequency);
 
  //if the pin frequency was set successfully, pin 13 turn on
  if(success) {
    pinMode(13, OUTPUT);
    digitalWrite(13, HIGH);   
  }
}

void loop()
{
  //use this functions instead of analogWrite on 'initialized' pins
  pwmWrite(led, 0);
 
  delay(5000);
   
  pwmWrite(led, 120);
   
  delay(5000);
     
  pwmWrite(led, 255);
}


And nothing happened, and now i read few posts saying that 25Khz is impossible with an arduino since the base frequencies divided by 2,4,8 etc... don't match with 25Khz.

Can I set the speed of the fan with my arduino ? Or Maybe i have made a mistake i can't see..
thank you for your time.

MorganS

"The problem is in the code you didn't post."

dlloyd

Yes, 25kHz PWM is possible ...

Code: [Select]
word VentPin = 3;

void setup() {
  pinMode(VentPin, OUTPUT);
  pwm25kHzBegin();
}

void loop() {
  pwmDuty(19); // 25% (range = 0-79 = 1.25-100%)
  delay(5000);
  pwmDuty(39); // 50% (range = 0-79 = 1.25-100%)
  delay (5000);
  pwmDuty(59); // 75% (range = 0-79 = 1.25-100%)
  delay (5000);
}

void pwm25kHzBegin() {
  TCCR2A = 0;                               // TC2 Control Register A
  TCCR2B = 0;                               // TC2 Control Register B
  TIMSK2 = 0;                               // TC2 Interrupt Mask Register
  TIFR2 = 0;                                // TC2 Interrupt Flag Register
  TCCR2A |= (1 << COM2B1) | (1 << WGM21) | (1 << WGM20);  // OC2B cleared/set on match when up/down counting, fast PWM
  TCCR2B |= (1 << WGM22) | (1 << CS21);     // prescaler 8
  OCR2A = 79;                               // TOP overflow value (Hz)
  OCR2B = 0;
}

void pwmDuty(byte ocrb) {
  OCR2B = ocrb;                             // PWM Width (duty)
}

Myneo

Hello again, yes the ground is connected both to the arduino and the adaptor.
And i tried the code you just posted dlloyd. It doesn't seem to have any effect, the fan just keep going full speed. And any code i write doesn't seem to do anything....
Is this possible that my fan is damaged, something else is going on ? With the program on my arduino, i can even unplug the PWM of my fan and absolutely nothing happens...

Myneo

Update: Hello everyone and thank for you patience. Turns out that the code dlloyd wrote works perfectly and it seems that i made a wiring mistake. So if you have the same issue verify twice your wiring haha:
PS: this is the wiring of my first project, i'm sure you'll understand why i made a mistake in this mess !
Thank you everybody ! And special thanks dlloyd you made a code that will be very useful for me :)

drFeelGood

dlloyd it is possibile to control more than 1 fan by arduino uno or mega with your code?

dlloyd

Dual 25kHz PWM using Timer1 ...

Code: [Select]
//Dual 25kHz PWM using Timer1 Mode 10

word pwmA = 160; // 50% duty (0-320 = 0-100% duty cycle)
word pwmB = 288; // 90% duty (0-320 = 0-100% duty cycle)

void setup() {
  pinMode(9, OUTPUT);  //pwmA
  pinMode(10, OUTPUT); //pwmB

  TCCR1A = 0;            //clear timer registers
  TCCR1B = 0;
  TCNT1 = 0;

  TCCR1B |= _BV(CS10);   //no prescaler
  ICR1 = 320;            //PWM mode counts up 320 then down 320 counts (25kHz)

  OCR1A = pwmA;          //0-320 = 0-100% duty cycle
  TCCR1A |= _BV(COM1A1); //output A clear rising/set falling

  OCR1B = pwmB;          //0-320 = 0-100% duty cycle
  TCCR1A |= _BV(COM1B1); //output B clear rising/set falling

  TCCR1B |= _BV(WGM13);  //PWM mode with ICR1 Mode 10
  TCCR1A |= _BV(WGM11);  //WGM13:WGM10 set 1010
}

void loop() {}

drFeelGood

Thanks for inspirations :-) What about other UNO timers ? Can I use Timer1 and Timer2 together to control 4 fans or 3 timers to control 6 fans ? Something like that:
Code: [Select]



word pwmA = 160; // 50% duty (0-320 = 0-100% duty cycle)
word pwmB = 32; // 10% duty (0-320 = 0-100% duty cycle)
word pwmC = 64; // 20% duty (0-320 = 0-100% duty cycle)
word pwmD = 128; // 40% duty (0-320 = 0-100% duty cycle)

void setup() {
  pinMode(9, OUTPUT);  //pwmA
  pinMode(10, OUTPUT); //pwmB
  pinMode(3, OUTPUT);  //pwmC
  pinMode(11, OUTPUT); //pwmD

  TCCR1A = 0;            //clear timer registers
  TCCR1B = 0;
  TCNT1 = 0;

  TCCR1B |= _BV(CS10);   //no prescaler
  ICR1 = 320;            //PWM mode counts up 320 then down 320 counts (25kHz)
 

  OCR1A = pwmA;          //0-320 = 0-100% duty cycle
  TCCR1A |= _BV(COM1A1); //output A clear rising/set falling

  OCR1B = pwmB;          //0-320 = 0-100% duty cycle
  TCCR1A |= _BV(COM1B1); //output B clear rising/set falling

  TCCR1B |= _BV(WGM13);  //PWM mode with ICR1 Mode 10
  TCCR1A |= _BV(WGM11);  //WGM13:WGM10 set 1010

  TCCR2A = 0;            //clear timer registers
  TCCR2B = 0;
  TCNT2 = 0;

  TCCR2B |= _BV(CS10);   //no prescaler
   ICR2 = 320;            //PWM mode counts up 320 then down 320 counts (25kHz)

 
  OCR2A = pwmC;          //0-320 = 0-100% duty cycle
  TCCR2A |= _BV(COM1A1); //output A clear rising/set falling

  OCR2B = pwmD;          //0-320 = 0-100% duty cycle
  TCCR2A |= _BV(COM1B1); //output B clear rising/set falling

  TCCR2B |= _BV(WGM13);  //PWM mode with ICR1 Mode 10
  TCCR2A |= _BV(WGM11);  //WGM13:WGM10 set 1010
}

void loop() {}


Jiggy-Ninja

There's only one ICR register unfortunately, so the other Timers are less flexible than Timer1.
Hackaday: https://hackaday.io/MarkRD
Advanced C++ Techniques: https://forum.arduino.cc/index.php?topic=493075.0

drFeelGood

:-( so, no chance to control more than 2 pwm fan by arduino uno/mega?

dlloyd

#10
Dec 12, 2016, 11:20 pm Last Edit: Dec 12, 2016, 11:40 pm by dlloyd
On an Uno:

With timer2, could get dual pwm at 31.37kHz using Mode 1. Using Mode 5 only get one pwm at 25kHz.

So, using timer 1 and timer 2, could get 4 pwm, 2 at 25kHz and 2 at 31.37kHz.

or 3 pwm at 25kHz.

Squaraine84

Hi there,

I was wondering how would you actually use dlloyd's code to control the PWM? Wouldn't you need something like digitalWrite() somewhere in there to tell the Arduino to have a certain PWM value?

Yes, 25kHz PWM is possible ...

Code: [Select]
word VentPin = 3;

void setup() {
  pinMode(VentPin, OUTPUT);
  pwm25kHzBegin();
}

void loop() {
  pwmDuty(19); // 25% (range = 0-79 = 1.25-100%)
  delay(5000);
  pwmDuty(39); // 50% (range = 0-79 = 1.25-100%)
  delay (5000);
  pwmDuty(59); // 75% (range = 0-79 = 1.25-100%)
  delay (5000);
}

void pwm25kHzBegin() {
  TCCR2A = 0;                               // TC2 Control Register A
  TCCR2B = 0;                               // TC2 Control Register B
  TIMSK2 = 0;                               // TC2 Interrupt Mask Register
  TIFR2 = 0;                                // TC2 Interrupt Flag Register
  TCCR2A |= (1 << COM2B1) | (1 << WGM21) | (1 << WGM20);  // OC2B cleared/set on match when up/down counting, fast PWM
  TCCR2B |= (1 << WGM22) | (1 << CS21);     // prescaler 8
  OCR2A = 79;                               // TOP overflow value (Hz)
  OCR2B = 0;
}

void pwmDuty(byte ocrb) {
  OCR2B = ocrb;                             // PWM Width (duty)
}

Thanks!

ErikL68

#12
Apr 25, 2017, 05:03 pm Last Edit: Apr 25, 2017, 05:12 pm by ErikL68
No.

This is unfortunately not the "usual" Arduino code.  In this case you write to a register, specifically "OCR2B" with a byte, after configuring a number of related registers, as seen in the "pwm25kHzBegin" subroutine.  For the code dlloyd provided, the subroutine "pwmDuty" does the job.  "pwm25kHzBegin" configures Timer2 to run at the speed necessary to do this, in this case 2 MHz (the Arduino's 16 MHz clock divided by 8), and has it reset to 0 when it hits 80, so it "cycles" at 25 KHz, with each cycle divided into 80 "ticks". Because it's only divided into 80 "ticks" of the timer, the value can only vary from 0 to 79, so you get a PWM with each step at (100/80 = ) 1.25%. It also never fully turns off the PWM output (the lowest output is a duty cycle of 1.25% on).

If you want to better understand these registers, you'll need to read the docs on the Atmel microprocessor that's on the Arduino, the ATMega 328P (or 168 depending on how old your Arduino is).  See here: http://www.microchip.com/wwwproducts/en/ATMEGA328P

Thinkerer

#13
Nov 10, 2017, 12:59 pm Last Edit: Nov 10, 2017, 01:11 pm by Thinkerer
This works very well for an application that I'm building, but...how is it that I can't use another pin assignment (pin 5, for example) just by changing the VentPin declaration?  I've tried it and there's no PWM output on that pin showing on the scope; is this coupled to the timer routine in a way I'm not seeing?



Yes, 25kHz PWM is possible ...

Code: [Select]
word VentPin = 3;

void setup() {
  pinMode(VentPin, OUTPUT);
  pwm25kHzBegin();
}

.
.
.

diyhouse

For anyone reading this thread,.. I to was trying to get PWM control on pin 2 of a mega,.. and failing miserably,... as this code does not work on a mega 2560,.. however, I found a solution by using the 'timerthree.h' library.

Go Up