4-pin PWM fan controller works, but...

Finally, I built the PWM fan controller wit a temperature sensor using Arduino Uno. All things are physically correct, but on the software side, there is a problem.

This is also useful for guys in the future.

Here are the elements:

  • LM35 temperature sensor
  • LCD 16x2
  • Arduino Uno
  • 4-pin PWM fan
  • A potentiometer (5k) for LCD contrast
  • A 200-600 ohm resistor for the LCD back light (between pin #15 and 12v)

The code looks like

#include <LiquidCrystal.h>

// Fan sens (tach) wire connected to digital_8 port
int fanSens = 8; 

// Fan PWM wire connected to digital_9 port
int fanPWM = 9;

// Middle pin of LM35 connected to analog_A1 port
int tempPin = 1;

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);


void showRPM() {
  unsigned long pulseDuration = pulseIn(fanSens, LOW);
  double frequency = 1000000/pulseDuration;
  lcd.setCursor(0, 1);  // cursor at bottom left
  lcd.print("RPM:");
  lcd.setCursor(5, 1);  // fifth column on the second row
  lcd.print(frequency/2*60);
}

void setup()
{
  pinMode(fanSens, INPUT);
  digitalWrite(fanSens,HIGH);
}

void loop()
{
  float val = analogRead(tempPin); 
  float mv = (val/1024.0)*5000;
  float cel = mv/10; // this is the celcuis

  lcd.setCursor(0, 0); // cursor at top left
  lcd.print( "TMP:" );
  lcd.setCursor(5, 0); // fifth column on the first row
  lcd.print( cel );
  
  if (cel <= 27.0)
    analogWrite(fanPWM, 70);   // write value 70 to the fan
  else if (27.0 < cel)
    analogWrite(fanPWM, 220); // write value 220 to the fan
  
  showRPM();
}

Here is the schematic:

Here are 4 pictures:

As you can see, the second line of the LCD doesn’t show the RPM and its value. In fact, it is in the same position as the TMP!! (the first line)

You can verify that in the third picture (shows messy characters)

Why? Any idea on that?

Too many digits [in the float decimal (mantissa)] forcing it to the top line?
Truncate (or otherwise constrain) the decimal/s, see how that works.

First, You have not initialized the display with lcd.begin(16,2)

Second, the unchanging text ("TMP" "RPM") of your display should be written in setup.

Third, the values written in loop should updated at a fixed interval, say every 500ms, instead of every pass through the loop. Call a function to update the display, using the millis() timer method of the of "blink without delay" example.

OK thanks… the first two ideas solved the problem.

Third, the values written in loop should updated at a fixed interval, say every 500ms, instead of every pass through the loop. Call a function to update the display, using the millis() timer method of the of “blink without delay” example.

So, what is the difference between putting 500ms delay and not putting that? I mean, the loop function repeats. So, without any delay, the changes are more realtime! Isn’t that?

So, what is the difference between putting 500ms delay and not putting that? I mean, the loop function repeats. So, without any delay, the changes are more realtime! Isn't that?

You won't use code with delay, but rather a millis() based timer which will let other things, like the update of temperature and pwm duty cycle happen independently of the display. The loop should be running faster than the lcd can respond, and faster than you could read any changes. Printing to the lcd ever pass through loop will slow the program down. It's best to manage the display with some thing like this.

Declare two variables

unsigned long lastDisplay =0;
unsignd long displayInterval = 500//or what ever time you want  in ms between display updates
if (millis() - lastDisplay >=displayInterval) //update lcd display every half second
  {
    lastDisplay  += displayInterval; 
    updateLcd();    
  }

updateLcd() is a function with the cursor management and the changing variables you want to display. Some of it will be similar to showRPM();

mahmoodn:
So, without any delay, the changes are more realtime! Isn’t that?

Not really. The display is pretty slow. So with the loop running free you can send the next update even before the display finished displaying you first update.