4 Position PWM Fan Controller

Hello,

I am using my Arduino board to make a PWM fan controller, my fan is a huge 140mm unit capable of pushing some serious air and luckily it has a PWM input.

I have tested a simple code to output a PWM signal with 50% duty cycle at 37khz (acceptable PWM frequency input is 25-50khz for the fan), this runs the fan at approx. 50% speed.

The next step is to write some simple code to allow me to run a Rotary 4 position switch OFF/1/2/3. My idea was to supply the input on the switch with 5v from the Arduino and simply look for a High/Low state on either of the input pins and then trigger some code depending on their state.

For some reason I cannot get this to work and the fan simply remains off, which it should do if no signal is detected on any input. I cannot measure 5v on the Arduino 5v output so I think this could be the error?

Please see my code below:

//Project -- 3 Speed PWM Fan Controller


int Spd1 = 8; // Switch Position 1
int Spd2 = 12; // Switch Position 2
int Spd3 = 13; // Switch Position 3


void setup()
{
 DDRD |= 1 << PD3;  // set pin 3 as an output (the same as pinMode(3, OUTPUT))
}

void loop()
{
{
if (Spd1 == 1)
{
 // 37 kHz means 27 us per cycle, calculation below for 25% on time duty cycle.
 PORTD |= 1 << PD3;  // set pin 3 high (much faster than digitalWrite)
 delayMicroseconds(7);
 PORTD &= ~(1 << PD3); // set pin 3 low (much faster than digitalWrite)
 delayMicroseconds(20);
}
}

{
if (Spd2 == 1)
{
 // 37 kHz means 27 us per cycle, calculation below for 50% on time duty cycle.
 PORTD |= 1 << PD3;  // set pin 3 high (much faster than digitalWrite)
 delayMicroseconds(13);
 PORTD &= ~(1 << PD3); // set pin 3 low (much faster than digitalWrite)
 delayMicroseconds(14);
}
}

{
if (Spd3 == 1)
{
 // 37 kHz means 27 us per cycle, calculation below for 100% on time duty cycle.
 PORTD |= 1 << PD3;  // set pin 3 high (much faster than digitalWrite)
}
}
{
if (Spd1 == 0  && Spd2 == 0 && Spd3 == 0) {
 PORTD &= ~(1 << PD3); // set pin 3 low (much faster than digitalWrite)
}

}

}
if (Spd1 == 1)

Did you mean?:-

if(digitalRead(Spd1)==HIGH)

(Same all through your code.)

For active-high switching, I assume you have pulldown resistors on the pins. It's easier to wire so that the switching is to 0V, then use internal pullups.

All what OldSteve says plus

Once you start numbering the variables it’s time to start using arrays :wink:

Great article to read:
http://www.gammon.com.au/tips

DDRD |= 1 << PD3;  // set pin 3 as an output (the same as pinMode(3, OUTPUT))

Then why mess with registers then? Please just use pinMode.

Mudgey:
acceptable PWM frequency input is 25-50khz for the fan

That’s a very wide range. Or did you mean 25k-50kHz :wink:

And another tip, just use the hardware PWM. Just connect the fan to pin 3 or pin 11 and do

TCCR2B = (TCCR2B & 0b11111000) | 0x01; //sets PWM frequency to 31kHz
analogWrite(3, speed);

Hi OldSteve,

Thanks for your super quick reply.

Knew I missed something obvious, its been ages since I played with an Arduino and I think i'll go back and refresh the basics!!

Cheers, code tags added!

Autoformat in the tools menu or ctrl-t will automatically indent your code. Makes code easier to follow and will point out mismatched brackets and parenthesis.

Bludy hell, I am not used to receiving such quick replies to questions!

Is there a benefit to using the hardware PWM over how I have done so?

I read another forum members post, who said that this was more efficient to generate a PWM signal, than other ways. I admit I don't understand how this works but it seems to.

My bad, indeed 25k-50khz, missed out an important identifier there.

Mudgey: Hi OldSteve, Thanks for your super quick reply.

No worries. Glad to help.

Cheers, code tags added!

Thanks for that. (I edited and removed my suggestion. Now it's all nice and clean. :) )

And using a hardware timer is much better. It doesn't slow down the 'loop()' with delays.

Using the hardware is like telling somebody else to do the PWM, freeing the Arduino from doing so. With hardware PWM it's a piece of cake for the Arduino to control 4 fans.

Awesome, really appreciate the help and the solutions to these problems!

So a couple of you have pointed out things which I haven’t had any experience of before, for example controlling PWM is new to me and I only have a few hours of research under my belt. If you guys do know of any good reading to explain your suggestions or even the keywords I should use to search the forum or google to find out more I would really appreciate that!

Here is the pdf document to the fan I am using, more importantly details on the PWM input signal is on page 9 of 16.

I presume the pulldown resistor guarantees the line is 0v when it is not live so to speak? It does look like the fan has an internal 10k resistor connected to ground, am I correct in thinking this would be the pull down resistor?

here is my current code, currently when neither of the 3 inputs are HIGH the fan doesn’t turn off. I am a little confused as to why the fan continues running even without this bit of code at the end?

//Project -- 3 Speed PWM Fan Controller
/*
   Description: Turn LED on and off every other second.
*/

int Spd1 = 8; // Switch Position 1
int Spd2 = 12; // Switch Position 2
int Spd3 = 13; // Switch Position 3
int PWMOut = 3; // PWM Output


void setup()
{
  DDRD |= 1 << PD3;  // set pin 3 as an output (the same as pinMode(3, OUTPUT))
}

void loop()
{
  {
    if (digitalRead(Spd1) == HIGH)
    {
      TCCR2B = (TCCR2B & 0b11111000) | 0x01; //sets PWM frequency to 31kHz
      analogWrite(3, 64); // 0 - 255 = 0 - 100%
    }
  }

  {
    if (digitalRead(Spd1) == HIGH)
    {
      TCCR2B = (TCCR2B & 0b11111000) | 0x01; //sets PWM frequency to 31kHz
      analogWrite(3, 130); // 0 - 255 = 0 - 100%
    }
  }

  {
    if (digitalRead(Spd3) == HIGH)
    {
      TCCR2B = (TCCR2B & 0b11111000) | 0x01; //sets PWM frequency to 31kHz
      analogWrite(3, 255); // 0 - 255 = 0 - 100%
    }
  }
  {
    if (digitalRead((Spd1) == LOW)  && ((Spd2) == LOW) && ((Spd3) == LOW))) {
       {
      TCCR2B = (TCCR2B & 0b11111000) | 0x01; //sets PWM frequency to 31kHz
      analogWrite(3, 0); // 0 - 255 = 0 - 100%
    }

    }

  }

}

Mudgey:
Here is the pdf document

You forgot to link it :wink:

Mudgey:
If you do know of any good reading to explain your suggestions or even the keywords I should use to search the forum or google to find out more I would really appreciate that!

“Arduino analogWrite” and “Arduino Pwm”, not that hard hè?

Mudgey:
I presume the pulldown resistor guarantees the line is 0v when it is not live connected so to speak?

(See change above ;)) But yes, a not connected pin (which includes a not closed switch) isn’t guaranteed to be either high or low, it’s floating. It picks up signals in the air and will flap around high and low. A pull up/down resistor will pull it a certain way when not connected.

But instead of an external pull down resistor you can just use the internal pull up resistors. Enable then with

pinMode(pin, INPUT_PULLUP);

And connect the switch between GND and the pin. This is the normal way to do it :wink: Only thing to remember is a pin now reads HIGH when the switch is not pressed/closed and LOW when it is.

Mudgey:
It does look like the fan has an internal 10k resistor connected to ground, am I correct in thinking this would be the pull down resistor?

Fan in on the output, the output is driven HIGH and LOW so it does nothing.

Mudgey:
here is my current code,

Mm, looks like you did absolutely nothing with the other comments :confused: And I’ll quote:

septillion:
Once you start numbering the variables it’s time to start using arrays :wink:

Great article to read:
Gammon Forum : Electronics : Microprocessors : Arduino programming traps, tips and style guide

DDRD |= 1 << PD3;  // set pin 3 as an output (the same as pinMode(3, OUTPUT))

Then why mess with registers then? Please just use pinMode.
That’s a very wide range. Or did you mean 25k-50kHz :wink:

Okay, off to other comments:

You only set the frequency once thus in setup. After that you only use analogWrite() to set the speed.

analogWrite(3, 0); // 0 - 255 = 0 - 100%

What’s 3? :wink: Aka, use the name of the pin.

You have some extra/not needed brackets floating around:

  { // <------ What is this doing here?
    if (digitalRead(Spd1) == HIGH)
    {
      TCCR2B = (TCCR2B & 0b11111000) | 0x01; //sets PWM frequency to 31kHz
      analogWrite(3, 64); // 0 - 255 = 0 - 100%
    }
  } //<---- Same for this one ;)

And for the if’s, use if, else if, else if, else. That will save you checking each pin each time. Example (with changes of all above comments in it):

  //Is the switch on position 1?
  if(digitalRead(SwitchPins[0]) == LOW){
    analogWrite(PwmOutPin, 64); // 0 - 255 = 0 - 100%
  }
  //is the switch on position 2?
  else if(digitalRead(SwitchPins[1]) == LOW){
    analogWrite(PwmOutPin, 130); // 0 - 255 = 0 - 100%
  }
  //is the switch in position 3 then?
  else if(digitalRead(Spd3) == HIGH){
    analogWrite(PwmOutPin, 255); // 0 - 255 = 0 - 100%
  }
  //if not in 1, 2 or 3 then it must be off :)
  else{
    analogWrite(PwmOutPin, 0); // 0 - 255 = 0 - 100%
  }