Lueftersteuerung um den Keller zu trocknen

Hallo,
ich habe leider einen feuchten Keller, und möchte diesen nun mit Lüftern trocknen. Wenn die absolute Luftfeuchtigkeit draußen geringer ist als im Keller, sollen die Lüfter sich anschalten.

Die Hardware:

  1. Alte (unbenutzte) Papst-Lüfter, made in W-Germany mit einer Menge Power.
  2. Arduino R3 (China)
  3. LCD Keypad Shield (China) scheint ein 1602 Clone zu sein (http://goo.gl/xnjjc)
  4. 2x DHT22 (auch aus China ;-))
  5. 2 Relay Module (mit 2x IN)

Die (Beta)Software: (Soweit ich bisher halt bin)

Die Probleme die noch zu lösen sind:

  1. Relais schaltet sich ständig ein aus, da der immer wieder auf LOW springt, womit natürlich das Relais angeht.
  2. Menuestruktur muss noch fertig gemacht werden, hab da aber schon eine Idee.
  3. In LiquidCrystal sind irgendwie die Pins 4,5,6,7 für das LCD zugeordnet, obwohl die im Shield durchgeschliffen sind. Habe ich noch keine Ahnung
    ob das Probleme verursacht, bzw wie ich das löse.
  4. Muss mir noch eine Logik überlegen, wie die Steuerung mit Taupunkten umgeht die beieinander schwanken, damit der Lüfter nicht ständig an und
    aus geht.
  5. Später noch soll noch eine RTC dazu kommen, um zu gewissen Zeiten schalten zu können.

Wenn jemand Fragen oder Anregungen hat, immer zu 8)

Erklär mal bitte

da der immer wieder auf LOW springt

wer ist "der" ?

Macht der Arduino einen Reset wenn ein Lüfter startet, oder brauchst du nur eine größere Hystere ?

Nachtrag: Mein Problem Nachtrag: Mit deinen Links komm ich nicht zurecht ...

Also das Relais (optoelektr.) geht bei jedem Durchlauf an. Vermutlich weil es am LCD-Shield angeschlossen ist.

Schema des LCD-Shields: http://sainsmart.com/zen/documents/20-011-901/schematic.pdf

In dem Beispiel Sketch der Firma steht : LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
Damit wird vermutlich dann auch das Relais geschaltet, wenn etwas auf das LCD geschickt wird.
Aber was kann ich machen, ich hab auf dem Shield nur PIN 4,5,6,7 ???

Der Code lautet:

#include <dht.h>
#include <LiquidCrystal.h>
#include <DFR_Key.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


dht DHT;
DFR_Key keypad;

#define dhtA 5
#define dhtI 6
#define relais 7

int localKey = 0;      //Tastenerkennung
String keyString = ""; //??

double dewPointFast(double celsius, double humidity) //Taupunkt berechnung
{
        double a = 17.271;
        double b = 237.7;
        double temp = (a * celsius) / (b + celsius) + log(humidity/100);
        double Td = (b * temp) / (a - temp);
        return Td;
}

float dewI = 0; //Taupunkt Innen
float dewA = 0; //Taupunkt Aussen
float tempI = 0;//Temperatur Innen
float tempA = 0;//Temperatur Aussen
float humI = 0; //Luftfeuchtigkeit Innen
float humA = 0; //Luftfeuchtigkeit Aussen
int count = 0;  //Counter fuer die Eingabe
int statL = 1;  //Status der Luefter
int menueH = 0; //Durchs Hauptmenue gehen
int statS = 0;  //brauche ich das??


void setup()
{
  Serial.begin(115200); //Verbindung Computer
  digitalWrite(relais, HIGH);
  pinMode(relais, OUTPUT);  
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("0.01 by Jules");
  delay(2500);  
}

void loop()
{
  
    if(statL == 1)  //notwendig um Relais zu schalten!!
    {
      digitalWrite(relais, LOW);       
    }
    
    else
    {
      digitalWrite(relais, HIGH);        
    }
  
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Messung laeuft");
  
  
  DHT.read22(dhtI); //Sensor Innen auslesen
  delay(500);
  DHT.read22(dhtI);
  float humI = DHT.humidity;
  float tempI = DHT.temperature;
  float dewI = (dewPointFast(DHT.temperature, DHT.humidity));    
  
  DHT.read22(dhtA); //Sensor Aussen auslesen
  delay(500);
  DHT.read22(dhtA);
  float humA = DHT.humidity;
  float tempA = DHT.temperature;
  float dewA = (dewPointFast(DHT.temperature, DHT.humidity)); 
  
  dewA = dewA + 5; //Test!!!!!!!!!!!!!!!!!!!
 
  if (dewA > dewI)  //Ueberprueft die Luftfeuchtigkeit schaltet die Luefter und speichert den Status in statL
  {   
    digitalWrite(relais, HIGH); //Luefter ausschalten
    statL = 0;
  }
  
  else 
  {
    digitalWrite(relais, LOW); //Lufter einschalten
    statL = 1;
  }
  
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Erwarte Befehle");
    
    
    count = 0; //integer, wenn zu hoch Speicherüberlauf!!!
 
  while(count < 30000) //Menuefunktion
  {
    keypad.getKey();
    menueH = keypad.getKey();
    
    if(statL == 1) //notwendig um Relais zu schalten!!
    {
      digitalWrite(relais, LOW);       
    }
    
    else
    {
      digitalWrite(relais, HIGH);        
    }
    
    
    switch (menueH) //Einzelne Menuepunkte
    {
      case 1:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Taste1");
      delay(2000);
      lcd.clear();
      break;
      
      case 2:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Taste2");
      delay(2000);
      lcd.clear();
      break;
      
      case 3:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Taste3");
      delay(2000);
      lcd.clear();
      break;
      
      case 4:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Taste4");
      delay(2000);
      lcd.clear();
      break;
      
      case 5:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Taste5");
      delay(2000);
      lcd.clear();
      break;
    }
      
    if(menueH != SAMPLE_WAIT) //Setzt den Counter auf Null wenn Eingabe erfolgt ist.
    {
      count = 0;
    }
    
    
    else   
    {
      count++; //Ohne Einmgabe laueft der Counter
    } 
    
    //Serial.println(count);      
    
        
  }
 
 
//  Serial.println ("Innensensor:");
//  Serial.print ("humI: ");
//  Serial.println (humI);
//  Serial.print ("tempI: ");
//  Serial.println (tempI);
//  Serial.print ("dewI: ");
//  Serial.println (dewI);
//  Serial.println ("");
//  
// 
//  Serial.println ("Aussensensor:");
//  Serial.print ("humA: ");
//  Serial.println (humA);
//  Serial.print ("tempA: ");
//  Serial.println (tempA);
//  Serial.print ("dewA: ");
//  Serial.println (dewA);
//  Serial.println ("____________________");

}

Tja, das passt nicht zu

#define dhtA 5
#define dhtI 6
#define relais 7

Fragt sich wo das Umlöten leichter geht :wink:

Oder, wenn man die Shields nicht aufeinander steckt sondern alles erforderliche einzeln verbindet ...

Was ich nicht verstehe, wenn ich die Schematik richtig verstehe, (und es sieht von hinten auf der Platine auch so aus) sind die Pins 4,5,6,7 nicht mit der Schaltung des Shields verbunden, sondern werden nur durchgeschliffen, andererseits wieder: LiquidCrystal lcd(8, 9, 4, 5, 6, 7);. Ich verstehe es wirklich nicht.

Es werden diese PINs für das Keypad Shield benötigt: LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
Nutzte auch das Shield.

Dies hier musst du auf andere PINs verlegen:

#define dhtA 5
#define dhtI 6
#define relais 7

Für das Menü empfehle ich das hier: http://forum.arduino.cc/index.php/topic,73816.0.html

RTC kannst du dir sparen und selber programmieren oder mich fragen, ist genau so ungenau wie die 1307.

Welche Pin´s kann ich denn nehmen, bzw wo muss ich anlöten?

Ausserdem seh ich noch D10 , mit dem die Beleuchtung des LCD-Shields geschaltet wird.

Auf dem LCD Shield kannst du
an J5 die Signale D0..D3 und D11..D13 und
an J6 die Signale A1 .. A5 "frei" verwenden.

So lese ich jedenfalls deine pdf Datei...

Punkt 4 ist ganz einfach:

if(wert >= schaltpunkt + hysterese)
{
      Lüfter an
}
else if(wert < schaltpunkt - hysterese)
{
     Lüfter aus
}

Dann behält er innerhalb von 2 * hysterese seinen Zustand. "Schaltpunkt +/- Hysterese" kann man natürlich auch als eine Konstante schreiben

@Serenifly:

Mach dir mal keine Sorgen, mit

const int SCHALTPUNKT=100;
const int HYSTERESE = 20;

wird der Compiler auch SCHALTPUNKT+HYSTERESE direkt beim Compilieren ausrechnen und genauso wie 120 verwenden.

Ich war mehr um die Übersichtlichkeit als die Speicherverwendung besorgt :slight_smile:

Ist auch Geschmackssache hier. Eventuell braucht man das ja gar nicht getrennt.

So, ich hab jetzt die Sensoren an Pin 12 und 13 und das Relais an Pin 3 angelötet. jedoch springt das Relais nach wie vor ständig an?

:wink:
dann such doch mal, wie du statL verwendest :wink:

( Oder nimm die erste Stelle

  if(statL == 1)  //notwendig um Relais zu schalten!!
    {
      digitalWrite(relais, LOW);       
    }
    
    else
    {
      digitalWrite(relais, HIGH);        
    }

einfach mal weg :wink:

Julianchr, Deine Auflistung hat einen Fehler:
"2. Arduino R3 (China)"
Es gibt keinen Arduino R3 Made in China. Wenn Du ihn in China gekauft hast, ist es kein Arduino.
Grüße Uwe

Wie meinst du das mit dem Fehler in statL?

Ja, der Arduino ist eine Replik!

Nachtrag: Hab mal das Relais an PIN 11 gelötet, und siehe da es klappt :sweat_smile:
Pin 3 war wohl dorch irgendwie mit dem LCD verbunden

Wie meinst du das mit dem Fehler in statL?

Entweder du hast es inzwischen korrigiert oder ich hab mich verguckt. :wink:

( Sorry, klar. Ich muss mich wohl verguckt haben )

(statL=1) und digitalWrite(relais, LOW), sowie dessen Gegenteil, müssen immer zusammenpassen. Und das tun sie auch.

Allerdings fehlt die Hysterese, also ein Bereich, in dem nichts verändert wird, sondern nur der alte Zustand beibehalten wird.
Und mehrmals in loop() einen Digitalausgang setzen muss nicht falsch sein, könnte aber :wink:

Blinkt der "unbenutzte" Pin 3 denn jetzt ( wenn du eine LED mit Vorwiderstand dransteckst )?
Dass das Relais permanent hin und her geschaltet hat, kann ja nur mit der loop - Zeit von 2 * delay(500) zusammenhängen, schätze ich...

So, im Prinzip funktioniert jetzt alles XD
mal sehen, was noch dazu kommt.
Vielen Dank für die kompetente Hilfe.

___________________________________                                                                                                                        
Verwendete Teile:

Arduino R3
Sainsmart 1602 LCD Keypad Shield
optoelektronisches Relais
2x DHT22
___________________________________
Key Codes (in left-to-right order):

None   - 0
Select - 1
Left   - 2
Up     - 3
Down   - 4
Right  - 5
___________________________________

*/

#include <dht.h>
#include <LiquidCrystal.h>
#include <DFR_Key.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


dht DHT;
DFR_Key keypad;

#define dhtA 12
#define dhtI 13
#define relais 11


int localKey = 0;      //Tastenerkennung
String keyString = ""; //??

double dewPointFast(double celsius, double humidity) //Taupunkt berechnung
{
        double a = 17.271;
        double b = 237.7;
        double temp = (a * celsius) / (b + celsius) + log(humidity/100);
        double Td = (b * temp) / (a - temp);
        return Td;
}

float dewI = 0; //Taupunkt Innen
float dewA = 0; //Taupunkt Aussen
float tempI = 0;//Temperatur Innen
float tempA = 0;//Temperatur Aussen
float humI = 0; //Luftfeuchtigkeit Innen
float humA = 0; //Luftfeuchtigkeit Aussen
int hysterese = 1; //Hysterse (mal 2) für die Schaltung 

long count = 0;  //Counter fuer die Eingabe
int statL = 0;  //Status der Luefter 
int menueH = 0; //Durchs Hauptmenue gehen
//int menueS = 0; //Menue bei Select
int menueC = 0;
int intro = 0;

long previousMillis = 0;
long milliMil = 0;
long milliMin = 0;
long milliStd = 0;



void setup()
{
  Serial.begin(115200); //Verbindung Computer
  pinMode(relais, OUTPUT);
  digitalWrite(relais, HIGH);

  
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Fan Control");
  lcd.setCursor(0, 1);
  lcd.print("Version 0.1.9");
  
  while(intro < 5)
  {
    lcd.setCursor(15, 1);
    lcd.print((char)0x7C);
    delay(500);
    lcd.setCursor(15, 1);
    lcd.print((char)0x2D);
    delay(500);    
    intro++;
  }
  
  delay(2500);  
}

void loop()
{
  unsigned long currentMillis = millis();
  milliMil = currentMillis - previousMillis;
  milliMin = milliMil / 60000;
  milliStd = milliMin / 60;
  
  
  
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Hello Dave,");
  lcd.setCursor(0, 1);
  lcd.print("I'm very busy");
  
  

    
  DHT.read22(dhtI); //Sensor Innen auslesen
  //delay(500);
  //DHT.read22(dhtI);
  float humI = DHT.humidity;
  float tempI = DHT.temperature;
  float dewI = (dewPointFast(DHT.temperature, DHT.humidity));    
  
  delay(1500);
  
  DHT.read22(dhtA); //Sensor Aussen auslesen
  //delay(500);
  //DHT.read22(dhtA);
  float humA = DHT.humidity;
  float tempA = DHT.temperature;
  float dewA = (dewPointFast(DHT.temperature, DHT.humidity)); 
  
  //dewA = dewA - 5; //Test!!!!!!!!!!!!!!!!!!!
 
  if (dewA <= dewI - hysterese)  //Ueberprueft die Luftfeuchtigkeit schaltet die Luefter und speichert den Status in statL
  {   
    digitalWrite(relais, LOW); //Luefter einschalten
    
    if (statL == 0)
    {
    previousMillis = millis();
    }
    statL = 1;
  }
  
  else if (dewA > dewI + hysterese)
  {
    digitalWrite(relais, HIGH); //Lufter ausschalten
    
    if (statL == 1)
    {
    previousMillis  = millis();
    }
    statL = 0;
    
  }
  
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("HAL:Im waiting");
    lcd.setCursor(0, 1);
    lcd.print("    for command");
    
    
    count = 0; 
 
  while(count < 300000) //Menuefunktion
  {
    keypad.getKey();
    menueH = keypad.getKey();
        
    switch (menueH) //Einzelne Menuepunkte
    {
      case 1:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Luefter:");
      lcd.setCursor(9, 0);
      Serial.println(statL);//loeschen
      if(statL == 1)
      {
        lcd.print("AN");
      }
      if(statL == 0)
      {
        lcd.print("AUS");
      }
      
      lcd.setCursor(0, 1);
      lcd.print(milliStd);
      lcd.print("Std ");
      lcd.print(milliMin);
      lcd.print("Min ");
      delay(1000);
      break;          
      
      case 2: //Relais ausschalten Pfeil nach links
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Luefter: Aus");
      digitalWrite(relais, HIGH); //Schalte Relais AUS
      delay(1000);//Verzögere um erneute Eingabe zu verhindern
      
      menueC = 0; //setze Schaltzustand auf 0      
      while(menueC != 1) //Manueller Luefter
      {
        keypad.getKey();
        localKey = keypad.getKey();
         
        if (localKey == 2) //Wenn 2 gedrückt wird wird die Schleife beendet
        {
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Automatikmodus");
          lcd.setCursor(0, 1);
          lcd.print("ist AN");
          previousMillis  = millis(); //setze Timer auf Null
          digitalWrite(relais, HIGH); //Schaltet Luefter wegen Hysterese aus!
          delay(1000);
          menueC = 1; //beende Schleife
        }
         
      }
      break;
      
        
      case 3: //Anzeige Daten Aussen Pfeil nach oben
  
      //Erste Zeile
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Aussen: ");
      
      lcd.print(dewA);
      lcd.print((char)223);
      lcd.print("C");
  
      //Zweite Zeile
      lcd.setCursor(0, 1);
      lcd.print(tempA);
      lcd.print((char)223);
      lcd.print("C ");
  
      lcd.print(humA);
      lcd.print((char)0x25);
      delay(1000);
      break;
      
      case 4: //Anzeige Daten Keller Pfeil nach unten
  
      //Erste Zeile
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Keller: ");
  
      lcd.print(dewI);
      lcd.print((char)223);
      lcd.print("C");
  
      //Zweite Zeile
      lcd.setCursor(0, 1);
  
      lcd.print(tempI);
      lcd.print((char)223);
      lcd.print("C ");
  
      lcd.print(humI);
      lcd.print((char)0x25);
      delay(1000);
      break;
      
      case 5: //Luefter einschalten Pfeil nach rechts
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Luefter: An");
      digitalWrite(relais, LOW); //Schalte Relais AN
      delay(1000);//Verzögere um erneute Eingabe zu verhindern
      
      menueC = 0; //setze Schaltzustand auf 0      
      while(menueC != 1) //Manueller Luefter
      {
        keypad.getKey();
        localKey = keypad.getKey();
         
        if (localKey == 5) //Wenn 5 gedrückt wird wird die Schleife beendet
        {
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Automatikmodus");
          lcd.setCursor(0, 1);
          lcd.print("ist AN");
          previousMillis  = millis(); //setze Timer auf Null
          digitalWrite(relais, HIGH); //Schaltet Luefter wegen Hysterese aus!
          delay(1000);
          menueC = 1; //beende Schleife
        }
         
      }
      break;
    }
      
    if(menueH != SAMPLE_WAIT) //Setzt den Counter auf Null wenn Eingabe erfolgt ist.
    {
      count = 0;
    }
    
    
    else   
    {
      count++; //Ohne Einmgabe laueft der Counter
    } 
    
    
 }
 
 
  Serial.println ("Innensensor:");
  Serial.print ("humI: ");
  Serial.println (humI);
  Serial.print ("tempI: ");
  Serial.println (tempI);
  Serial.print ("dewI: ");
  Serial.println (dewI);
  Serial.println ("");
  
 
  Serial.println ("Aussensensor:");
  Serial.print ("humA: ");
  Serial.println (humA);
  Serial.print ("tempA: ");
  Serial.println (tempA);
  Serial.print ("dewA: ");
  Serial.println (dewA);
  Serial.println ("____________________");

}

Für Code musst du diese Tags verwenden:
[.code]
[./code]

Ohne die Punkte. Oder Einfach auf den # Knopf klicken.

Deine Ausgabe auf dem LCD solltest du zumindest teilweise in eine Methode auslagern und die Position auf dem Display und den Inhalt mit Parametern übergeben. Das wird dann wesentlich übersichtlicher. z.B. so ähnlich:

void printLCD(byte x, byte y, char* str)
{
    lcd.setCursor(x,y);
    lcd.print(str);
}

Oder eine PrintTemp Methode die das "°C" dranhängt, da du das mehrmals machst

Double bringt dir hier übrigens keine höhere Präzision als Float. Beide haben auf dem Arduino 4 Byte

String keyString = ""; //?? <--- das ist einfach ein leeres String-Objekt falls dich das noch wundert

Wenn du nur zwei Zustände in einer Variable speichern willst ist int Verschwendung. Da nimmt man bool/boolean. Der nimmt true/false an.

Das kannst du einfach so abfragen:

bool state = false;

void loop()
{
     if(state)    //oder deutlich: if(state == true)
     {
         ...
     }
}

Andersherum:

if(!state)    //oder: if(state == false)
{
}

Also wie ich jetzt den Code poste habe ich irgendwie noch nicht verstanden :roll_eyes:

Pin 3, hing am Shield und deshalb hat er bei jeder LCD Ausgabe geschaltet.

Ja, der Code muss noch aufgeräumt werden :wink:
bin aber froh, dass er zumindest rudimentär funktioniert.
Dass mit der Hysterese war ein super Tipp, der macht das deutlich einfacher...
Danke nochmal, ich werde aber weiterhin über das Projekt schreiben. Vielleicht kann das ja jemand gebrauchen.

Das sind die normalen Tags in eckigen Klammern wie sie in allen Foren sind.

[.code]
//Code hier
[./code]

Und die Punkte nach der ersten Klammer weglassen. Die habe hier nur reingemacht damit man es sieht.

Oder: Code markieren und oben bei den Icons auf den #-Knopf klicken (untere Reihe, dritter von rechts)