Relative air moisture controlled PWM fan

Target
Exchange humid air inside a box with fresh, dry air from outside. The difference between outside and inside air humidity should be small and (nearly) constant. The fan shall operate economic.

Frame
-> Humidity outside and inside the box are frequently changing.
-> The inside is always more humid than the outside.
-> Installed are:

  • a PWM controlled fan in the boxes wall
  • one air temperature/moisture sensor outside the box
  • one air temperature/moisture sensor inside the box

Approach
The PWM controlled fan sucks fresh, dry air from outside in the box.
The two DHTs (22) are used to compare the air moisture values inside and outside the box. Based on their results the fan is being controlled.
The fan should rev as low as possible to save energy. It should be operated stepless.

Code
My code works somehow, but it's not correctly programmed.
I would want to understand how to do this better:

//-------------------------------------------
//----------Bibliotheken---------------------
//-------------------------------------------
#include <Arduino.h>
#include <DHT.h>

//-------------------------------------------
//----------DEFINITIONEN---------------------
//-------------------------------------------

#define DHTTYPE1   DHT22     // dht 22 sensor 1
#define DHTTYPE2   DHT22     // dht 22 sensor 2

//-----Pinbelegung Aktuatoren-----
const int Abluft = 11;     //(PWM)

//-----Pinbelegung Sensoren-----
const int DHTPIN1 = A0;     // dht 22 (NTC1) sensor 1
const int TachoAbluft = A3;
const int DHTPIN2 = A7;     // dht 22 (NTC1_2)sensor 2

//-----Frequenz Serial Monitor/Display-----
unsigned long AnzeigeSensorwerte  = 3000UL; // ANPASSEN !!!

//-----Millis-----
unsigned long previousTime3 = 0UL;

//-----Declarations NTC1-----
DHT dht1(DHTPIN1, DHTTYPE1);
DHT dht2(DHTPIN2, DHTTYPE2);

double h1, t1;
double h2, t2;

//-----Abluft-Drehzahl-----
int   fanSpeed = 120;        // Variable für die Lüftergeschwindigkeit
long  tachoMillis = 1000UL; // Variable zum speichern der Zeit
float rps = 0;             // Variable mit Kommastelle für die Berechnung der Umdrehungen pro Sekunde
int   rpm = 0;               // Variable für die gemittelte Drehzahl
float umdrZeit = 0;        // Variable mit Kommastelle für die Zeit pro Umdrehung des Lüfters
float flankenZeit = 0;     // Variable mit Kommastelle für die Zeit pro Puls des Lüfters

//---Abluft---
float RampSpeed = 0.2;     // vorher: 0.5, Controls the changing fan speed                 ANPASSEN!!!
float CurrentSpeed = 100.00;    // 1 Lüfter für Abluft   100% = 2500rpm               ANPASSEN!!!
float DesiredSpeed = 0;      // 1 Lüfter für Abluft   100% = 2500rpm                         ANPASSEN!!!
float FanMin = 0;            // Minimum fan speed 0-79
float FanMax = 255;          // Maximum fan speed 0-79

//---------------------------------------------------------------------------------------------------------------------------
//--------------------------------------- V O I D  S  E  T  U  P ------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------
void setup() {
  dht1.begin();
  dht2.begin();
  Serial.begin(115200);

  //-----Pin-Mode Aktuatoren-----
  pinMode(7, OUTPUT);    // Abluft
  digitalWrite(7, LOW);
  pinMode(Abluft, OUTPUT);
  analogWrite(Abluft, 255);

  //-----Pin-Mode Sensoren-----
  pinMode(A0, INPUT); //NTC1    //Inside moisture/temperature
  pinMode(A3, INPUT); //Tacho Pin
  pinMode(A7, INPUT); //NTC1_2 //Outside moisture/temperature

  //-----Lüfterfrequenz-----
  TCCR1B = TCCR1B & 0b11111000 | 0x01;  // Setzt Timer1 (Pin 11 und 12) auf 31300Hz
  TCCR3B = TCCR3B & 0b11111000 | 0x01;  // Setzt Timer3 (Pin 2 etc.) auf 31300Hz
}
//---------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------- V O I D  L  O  O  P ----------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------
void loop() {
  //-----NTC1/NTC1_2-----
  float h1 = dht1.readHumidity();
  float t1 = dht1.readTemperature();
  float h2 = dht2.readHumidity();
  float t2 = dht2.readTemperature();

  //----------LÜFTER STEUERUNG----------
  //---Abluftdefinition---
  float FeuchteSoll = (h2) + 6; //Sollwert über Außenfeuchte.
  float FeuchteSollMin = (h2); 

  //---Definition Lüftergeschwindigkeit---
  if (h1 > FeuchteSoll) {
    DesiredSpeed = FanMax;
  }
  if (h1 <= FeuchteSoll) {
    DesiredSpeed = map(h1, FeuchteSollMin, FeuchteSoll, FanMin, FanMax); // Map the Fan Speed to the Duty Cycle
  }
  //---Abluftansteuerung---
  if ((DesiredSpeed < CurrentSpeed) && ((CurrentSpeed - RampSpeed) > RampSpeed) ) {
    CurrentSpeed = CurrentSpeed - (1 * RampSpeed);
  } else if (DesiredSpeed < CurrentSpeed) {
    CurrentSpeed = CurrentSpeed - 1;
  }
  if ((DesiredSpeed > CurrentSpeed) && ((CurrentSpeed + RampSpeed) > RampSpeed) ) {
    CurrentSpeed = CurrentSpeed + (1 * RampSpeed);
  } else if (DesiredSpeed > CurrentSpeed) {
    CurrentSpeed = CurrentSpeed + 1;
  }
  analogWrite(Abluft, CurrentSpeed);

  //-----Werte TachoAbluft-----
  if ((millis() - tachoMillis) >= 1000UL) {
    flankenZeit = pulseIn(TachoAbluft, LOW);    // Abfrage der Zeit pro Puls in Mikrosekunden
    umdrZeit = ((flankenZeit * 4) / 1000);      // Berechnung der Zeit pro Umdrehung in Millisekunden Standard=4
    rps = (1000 / umdrZeit);                    // Umrechnung auf Umdrehungen pro Sekunde
    rpm = (rps * 6);                            // Schritt 1 zur Rundung auf 10er Schritte der Drehzahl
    rpm = (rpm * 10);                           // Schritt 2 zur Rundung auf 10er Schritte der Drehzahl
    tachoMillis = millis();  //update timing for next event
  }
  //-----------ANZEIGE----------
  unsigned long currentTime3 = millis();
  if (currentTime3 - previousTime3 >= AnzeigeSensorwerte) {

    Serial.println(("NTC1_innen IST Temp|Hum:        " + String(t1)    + "°C") + ("|") + (String(h1) + "%") );
    Serial.println("NTC1_innen SOLL    |Hum:               |" + String(FeuchteSoll) + "%" +("  Δ SOLL/IST:          /" + String(h1 - FeuchteSoll) + "%"));
    Serial.println(("NTC1_außen IST Temp|Hum:        " + String(t2)    + "°C") + ("|") + (String(h2) + "%")+("  Δ innen/außen: " + String(t1 - t2) + "°C") + ("/") + (String(h1 - h2) + "%") );
    Serial.println((("Current|Desired Speed Abluft: "+ String(rpm) + " 1/min,") +" " + String(CurrentSpeed)+ "|" + String(DesiredSpeed)));
    Serial.println("---------------------------------------------------------------------------------");
    previousTime3 = currentTime3;
  }
}

Help would be great!

You forgot to describe how the program actions differ from what was expected. The more detail you provide, the more likely you are to get useful help.

When starting a new project, get each independent function (e.g. measuring humidity, controlling fan speed) working separately, making sure that it is correct and that you understand the code. Then put all the parts together.

Focussing on a fixed value inside the box, does not make sense, because the outside air humidity may get temporary higher then the set value.

What is your plan for that case?

1 Like

Dear jremington,

thank you! I'd like to answer:

Not to rely on a fixed air moisture value, but on the changing value outside the box.

I have problems to get this right:

DesiredSpeed = map(h1, FeuchteSollMin, FeuchteSoll, FanMin, FanMax);
  • h1 is the inside moisture sensor
  • FanMin = 0 and FanMax =255 for the PWM
  • FeuchteSollMin = the outside moisture sensor value
  • FeuchteSoll = outside moisture value +6 (the 6 is the moisture difference between inside and outside value, which I have to accept, due to technical reasons (fan power).
    I want a (half way) stepless operating fan. Currently I do have only 6 steps, right?

I think using these values (FeuchteSollMin , FeuchteSoll), or at least one of them is no good in this mapping function.
Is my problem understandable?

What does that mean, and what is your actual goal for the project?

My goal is to prevent an unacceptable high air moisture within the box. This is given, when the inside air moisture is a bit higher than the outside one.

It means that the fan has to increase it's speed if the difference between the two values is getting to great. He has to hold, or reduce it's speed, if the gap between the two values is ok, to save power

Is the temperature inside the box is the same as the outside?

If so, exchanging air between inside and outside will only tend to equalize the two humidity values.

No it isn't. Inside it's a view degrees warmer. My approach and what I want works already. Just a little dodgy :slight_smile:

Sorry, given the lack of information about your project, goals, or problems with the code, I'm not able to help.

Hello olympdak

I did a quick code review and I noticed that the values for the humidity were not limited before it was given to the map() function.

Replace these untested lines of code and test it again:

  //---Definition Lüftergeschwindigkeit---
  if (h1 > FeuchteSoll) {
    DesiredSpeed = FanMax;
  }
  if (h1 <= FeuchteSoll) {
	h1 = constrain (h1,FeuchteSollMin,FeuchteSoll);
    DesiredSpeed = map(h1, FeuchteSollMin, FeuchteSoll, FanMin, FanMax); // Map the Fan Speed to the Duty Cycle
  }

hth

Dear paulpaulson,

thank you!

I tried it with your suggestion and I cannot feel any difference to before.

I try to describe in detail what I think should work better by looking at these values:

  • NTC1_innen IST Temp|Hum: shows the actual/current values of the sensor inside the box
  • NTC1_innen SOLL |Hum: shows the desired value inside the box (FeuchteSoll = (h2) + 6.0;)
  • Δ SOLL/IST: shows the deviation between the both. In this example it is negative, because we are already above expectation. I want to get the deviation close to zero
  • Current|Desired Speed Abluft: shows the current fan control value and the desired fan control value.

One problem is, that there are currently only 6 steps (h2 and h2+6 within the map function) for the PWM control available. I am not sure, but I think this leads to the negative value at the Δ SOLL/IST.

I would want to have more steps to adjust the PWM signal, but I don't know how to do this.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.