Relais schaltet nicht (Gewächshaussteuerung)

Hallo liebe Community,

ich hoffe ihr könnt mir weiterhelfen, komme nach stundenlanger Fehlersuche einfach nicht vorran und hoffe ihr könnt mal über meinen Programmcode schauen.

Es handelt sich um folgendes Problem, ich habe eine Gewächshaussteuerung mit einem Arduino Nano gebaut, ich werte mittels Dht22 Temperatur und Luftfeuchtigkeit aus und steuere daraufhin Aktoren (Ultraschalnebler und Heizlüfter) über eine Transistorverstärkerschaltung die Relais an.

Mein Ultraschalnebler funktioniert einwandfrei, das Relais schaltet voll durch, allerdings der Transistor für den Heizlüfter schaltet nicht voll durch wenn dieses angesteuert wird, es liegt nur ca die häflte der Spannung an. Ich habe bereits ein Code rübergespielt indem ich nur alle Ausgänge (Relais) auf High schalte und zu testen ob ich villeicht ein Fehler auf meiner Platine habe, allerdings hat dann auch das Relais für den Heizlüfter voll durchgeschaltet. Nur wenn ich mein Programmcode draufspiele schaltet er nicht voll durch.

Somit lässt sich der Fehler auf mein Code einkesseln und ich hoffe ihr könnt mir weiterhelfen :slight_smile:

#include <Wire.h>                 
#include <LiquidCrystal_I2C.h>
#include <DHT.h>                 //Libaries einbinden

#define DS3231_ADDRESSE 0x68     //DS3231 Adresse geben
#define DHTPIN 2                 //DHT Pin definieren
#define DHTTYPE DHT22            //DHT Typ definieren

DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

float temp=0;
float potTemp=0;
float tempIst=0;
float tempAdd=0;

float luft=0;
float potLuft=0;
float luftIst=0;
float luftAdd=0;       //Variabeln den Wert 0 geben

boolean buttonState=HIGH;
boolean merker=LOW;     //Variabeln auf High/Low setzen

int menue=0;
int stundeAn=0;
int stundeAus=0;
int minuteAn=0;
int minuteAus=0;

int led = 12;
int heizung = 10;
int luefter = 6;
int nebler = 8;
int wasserstand = 4;
int potTempPin = A6;
int potLuftPin = A7;
int buttonMinute = A1;
int buttonStunde = A0;
int buttonMenue = 13;    //Pins definieren


void setup() 
{
pinMode(led,OUTPUT);
pinMode(heizung,OUTPUT);
pinMode(luefter,OUTPUT);
pinMode(nebler,OUTPUT);
pinMode(wasserstand,INPUT);
pinMode(potTempPin,INPUT);
pinMode(potLuftPin,INPUT);
pinMode(buttonMinute,INPUT);
pinMode(buttonStunde,INPUT);
pinMode(buttonMenue,INPUT);   //definierte Pins als Eingang/Ausgang deklarieren

dht.begin();   //DHT22 starten
Wire.begin();  //Wire starten
//einstellenDS3231zeit(0,38,8,6,20,01,18);  //aktuelle Zeit speichern

lcd.begin(20,4);   //LCD Größe angeben
lcd.backlight();   //Hintergundbeleuchtung aktivieren
}


void loop() 
{ 
byte sekunde,minute,stunde,wochentag,tag,monat,jahr;
leseDS3231zeit(&sekunde,&minute,&stunde,&wochentag,&tag,&monat,&jahr);  //Daten vom DS3231 hohlen

temp = tempauslesen(temp,tempAdd);               //Temperatur auslesen
potTemp = potTempauslesen(potTemp,potTempPin);   //Potentiometer auslesen
luft = luftauslesen(luft,luftAdd);               //Luftfeuchtigkeit auslesen
potLuft = potLuftauslesen(potLuft,potLuftPin);   //Potentiometer auslesen

tempregel(luefter,heizung,temp,potTemp);         //Temperatur regeln
luftregel(luefter,nebler,wasserstand,luft,potLuft);    //Luftfeuchte regeln

buttonState = digitalRead(buttonMenue);          //Taster einlesen
if((buttonState == HIGH) && (merker == LOW))     //Merker setzen wenn Taster gedrückt
{merker = HIGH;}

if((buttonState == LOW) && (merker == HIGH))     //Gucken ob Taster wieder losgelassen wurde
{menue++;                                        //Menü hochzählen
if(menue==5)
{menue=0;}
merker = LOW;}

switch(menue)           //Menü Wahl
{
  case 0:               //Startbildschirm 
  lcdausgabe(temp,luft);
  zeigeZeit();
  zeigeDatum();
  break;

  case 1:               //Temperatur Anzeige
  zeigetemp(temp,potTemp); 
  break;

  case 2:               //Luftfeuchtigkeits Anzeige
  zeigeluft(luft,potLuft);
  break;

  case 3:               //Einschaltzeit Anzeige
  lcd.setCursor(0,0);
  lcd.print("-- Einschaltzeit: --");
  lcd.setCursor(0,1);
  lcd.print("----- ");
  if(stundeAn < 10){lcd.print("0");}
  lcd.print(stundeAn);
  lcd.print(":");
  if(minuteAn < 10){lcd.print("0");}
  lcd.print(minuteAn);
  lcd.print(" Uhr ----");
  zeigeZeit2();
  break;

  case 4:                //Ausschaltzeit Anzeige
  lcd.setCursor(0,0);
  lcd.print("-- Ausschaltzeit: --");
  lcd.setCursor(0,1);
  lcd.print("----- ");
  if(stundeAus < 10){lcd.print("0");}
  lcd.print(stundeAus);
  lcd.print(":");
  if(minuteAus < 10){lcd.print("0");}
  lcd.print(minuteAus);
  lcd.print(" Uhr ----");
  zeigeZeit2();
  break;
}
  
if(menue==3)    
{
  if(digitalRead(buttonStunde)==HIGH)    //Stunde der Einschaltzeit einstellen
  {
    stundeAn++;
    delay(100);
    if(stundeAn==25)
    {stundeAn=1;}
  }
  if(digitalRead(buttonMinute)==HIGH)    //Minute der Einschaltzeit einstellen 
  {
    minuteAn++;
    delay(100);
    if(minuteAn==61)
    {minuteAn=1;}
  }
}

if(menue==4)
{
  if(digitalRead(buttonStunde)==HIGH)    //Stunde der Ausschaltzeit einstellen
  {
    stundeAus++;
    delay(100);
    if(stundeAus==25)
    {stundeAus=1;}
  }
  if(digitalRead(buttonMinute)==HIGH)    //Minute der Ausschaltzeit einstellen 
  {
    minuteAus++;
    delay(100);
    if(minuteAus==61)
    {minuteAus=1;}
  }
}

if((stunde>=stundeAn)&&(minute>=minuteAn))   //Licht einschalten
{digitalWrite(led,HIGH);}

if((stunde>=stundeAus)&&(minute>=minuteAus))   //Licht ausschalten
{digitalWrite(led,LOW);}
}


void lcdausgabe(float temp,float luft)
{
  lcd.setCursor(0,0);          //Cursor setzen
  lcd.print("Temperatur:  ");  //LCD schreibt "Temperatur: "
  lcd.print(temp,1);           //LCD gibt den Temperaturwert wieder
  lcd.print(" C "); 
  lcd.setCursor(0,1);
  lcd.print("Luftfeuchte: ");
  lcd.print(luft,1);
  lcd.print(" % ");
}

void zeigetemp(float temp,float potTemp)
{
lcd.setCursor(0,0);
lcd.print("Temperatur aktuell: ");
lcd.setCursor(0,1);
lcd.print("------ ");
lcd.print(temp,1);
lcd.print(" C ------");
lcd.setCursor(0,2);
lcd.print("Temperatur soll:    ");
lcd.setCursor(0,3);
lcd.print("------ ");
lcd.print(potTemp,1);
lcd.print(" C ------");
}


void zeigeluft(float luft, float potLuft)
{  
lcd.setCursor(0,0);
lcd.print("Luftfeuchte aktuell:");
lcd.setCursor(0,1);
lcd.print("------ ");
lcd.print(luft,1);
lcd.print(" % ------");
lcd.setCursor(0,2);
lcd.print("Luftfeuchte soll:   ");
lcd.setCursor(0,3);
lcd.print("------ ");
lcd.print(potLuft,1);
lcd.print(" % ------");
}


 float tempauslesen(float temp,float tempAdd)
{
  for(int i=0;i<50;i++)              //Schleife mit 50 durchläufen um Termperatur zu ermitteln
  {
    temp = dht.readTemperature();    //Temperatur auslesen
    tempAdd = tempAdd + temp;        //Temperatur mit Anzahl an durchläufen zusammenzählen
  }
  temp = tempAdd/50;                 //Temperatur durch Anzahl an durchläufen teilen um Mittel-
  tempAdd = 0;                       //wert zu bilden     

  return temp;                       //Temperatur zurückgeben
}


  float luftauslesen(float luft,float luftAdd)
{
  for(int i=0;i<50;i++)
  {
    luft = dht.readHumidity();
    luftAdd = luftAdd + luft;
  }
  luft = luftAdd/50;
  luftAdd = 0;

  return luft;
}


    float potTempauslesen(float potTemp,byte potTempPin)
{
  potTemp = analogRead(potTempPin);     //Poti auslesen
  potTemp = potTemp/10.23;              //Potiwert umrechen auf 0-100

  return potTemp;                       //Potiwert zurückgeben
}


  float potLuftauslesen(float potLuft,byte potLuftPin)
{
  potLuft = analogRead(potLuftPin);
  potLuft = potLuft/10.23;

  return potLuft;
}
 void tempregel(int luefter,int heizung,byte temp,byte potTemp)  //Temperatur regeln
{
 if(temp > potTemp)                //Wenn Temperatur größer als Poti ist, dann
 {digitalWrite(luefter,HIGH);}     //Lüfter anschalten
 else                              //wenn nicht,
 {digitalWrite(luefter,LOW);}      //Lüfter ausschalten

 if(temp < potTemp)
 {digitalWrite(heizung,HIGH);}
 else 
 {digitalWrite(heizung,LOW);}
}


void luftregel(int luefter,int nebler,int wasserstand,byte luft,byte potLuft)
{
 if((luft < potLuft) && (digitalRead(wasserstand) == HIGH))  //Wenn Luft kleiner als Poti ist und
 {digitalWrite(nebler,HIGH);}  
 else
 {digitalWrite(nebler,LOW);}                                                                                          
}


void einstellenDS3231zeit(byte sekunde,byte minute,byte stunde,byte wochentag,byte tag,byte monat,byte jahr) //Datum und Uhrzeit einstellen
{
 Wire.beginTransmission(DS3231_ADDRESSE);
 Wire.write(0);
 Wire.write(decToBcd(sekunde));
 Wire.write(decToBcd(minute));
 Wire.write(decToBcd(stunde));
 Wire.write(decToBcd(wochentag));
 Wire.write(decToBcd(tag));
 Wire.write(decToBcd(monat));
 Wire.write(decToBcd(jahr));
 Wire.endTransmission();   
}


void leseDS3231zeit(byte *sekunde,byte *minute,byte *stunde,byte *wochentag,byte *tag,byte *monat,byte *jahr)
{
 Wire.beginTransmission(DS3231_ADDRESSE);
 Wire.write(0);
 Wire.endTransmission();
 Wire.requestFrom(DS3231_ADDRESSE,7);
 *sekunde = bcdToDec(Wire.read() & 0x7f);
 *minute = bcdToDec(Wire.read());
 *stunde = bcdToDec(Wire.read() & 0x3f);
 *wochentag = bcdToDec(Wire.read());
 *tag = bcdToDec(Wire.read());
 *monat = bcdToDec(Wire.read());
 *jahr = bcdToDec(Wire.read());
}


void zeigeZeit()
{
 byte sekunde,minute,stunde,wochentag,tag,monat,jahr;
 leseDS3231zeit(&sekunde,&minute,&stunde,&wochentag,&tag,&monat,&jahr);  //Daten vom DS3231 hohlen
 lcd.setCursor(0,2);
 lcd.print("Zeit:     ");
 if(stunde < 10){lcd.print("0");}
 lcd.print(stunde,DEC);
 lcd.print(":");
 if(minute < 10){lcd.print("0");}
 lcd.print(minute,DEC);
 lcd.print(":");
 if(sekunde < 10){lcd.print("0");}
 lcd.println(sekunde,DEC);
 lcd.print("");
}


 void zeigeZeit2()
{
 byte sekunde,minute,stunde,wochentag,tag,monat,jahr;
 leseDS3231zeit(&sekunde,&minute,&stunde,&wochentag,&tag,&monat,&jahr);
 lcd.setCursor(0,2);
 lcd.print("--------------------");
 lcd.setCursor(0,3);
 lcd.print("Zeit:  ");
 if(stunde < 10){lcd.print("0");}
 lcd.print(stunde,DEC);
 lcd.print(":");
 if(minute < 10){lcd.print("0");}
 lcd.print(minute,DEC);
 lcd.print(":");
 if(sekunde < 10){lcd.print("0");}
 lcd.println(sekunde,DEC);
 lcd.print("Uhr");
}


void zeigeDatum()
{
 byte sekunde,minute,stunde,wochentag,tag,monat,jahr;
 leseDS3231zeit(&sekunde,&minute,&stunde,&wochentag,&tag,&monat,&jahr);
 lcd.setCursor(0,3);
 lcd.print("Datum:    ");
 if(tag < 10){lcd.print("0");}
 lcd.print(tag);
 lcd.print(":");
 if(monat < 10){lcd.print("0");}
 lcd.print(monat);
 lcd.print(":20");
 lcd.print(jahr);
 lcd.print("");
}

byte decToBcd(byte val)      
{return((val/10*16) + (val%10));}
byte bcdToDec(byte val)
{return((val/16*10) + (val%16));}

Vorab schonmal vielen Dank :slight_smile:

Setze Deinen Code bitte in Codetags (</>-Button oben links im Forumseditor oder [code] davor und [/code] dahinter ohne *).
Das kannst Du auch noch nachträglich ändern.

Übrigens Relais schalten oder schalten nicht.

Eine Schaltung wie Du das aufgebaut hast, wäre sinnvoll.

Gruß Tommy

Danke für deine schnelle Antwort, habe den Schaltplan hochgeladen :slight_smile:

Hänge das Bild lieber direkt als Attachment an den Beitrag. Auf diesen Servern werden die Daten irgendwann gelöscht und dann fehlen hier die Informationen.

Gruß Tommy

Alles klar, habe noch das Platinenlayout drangehängt.

Gruß Philipp

Vermutlich liegt dein Problem an einer fehlenden Hysteresis. Die vermisse ich in deinem Sketch.

Hi

Wenn man will, wäre die Hysterese 1, Wenn wärmer, geht der Lüfter an, wenn kälter, die Heizung.
Ob das Ding dann taktet, wird sich zeigen (aber sehr sehr wahrscheinlich!!).
Trotzdem müsste das Relais schalten - sind die Pins als OUTPUT eingestellt?
Das sehe ich in den Snipped nämlich nicht.
Wenn JA - pflastere viele Serial.print() in Deinen Code, damit Du siehst, woher der Arduino geht, was in welcher Reihenfolge ausgeführt wird.
Denke, irgendwo ist ein Denkfehler programmiert, daß Du gar nicht in Deine Abfragen rein kommst, daß ein Relais geschaltet werden könnte.

MfG

Danke für eure Antworten :slight_smile:

Also ich habe meinen Wert, welchen ich vom DHT22 auslese in "Temp" gespeichert, wenn Temp kleiner als Poti(Sollwert) ist, dann schalte Heizung an.

Habe auch alle ausgänge als Output deklaiert.

Gruß Philipp

wachtiiii:
Also ich habe meinen Wert, welchen ich vom DHT22 auslese in "Temp" gespeichert, wenn Temp kleiner als Poti(Sollwert) ist, dann schalte Heizung an.

Ja, schön.
Und wenn die Temperatur geringfügig ansteigt, schaltet die Heizung wieder aus. So ist es in deinem Sketch gewollt.
Das auch für den Lüfter.

Hi

Sofern der Lüfter nicht die Heizungsluft direkt wieder raus bläst, sehe ich noch keine Probleme der beiden Zwei-Punkt-Regelungen.
Je nach erwärmtem Medium bzw. Abstand zum Sensor, dauert auch dieses Kelvin bestimmte Zeit.
Befürchte aber, es geht um Luft und die Regelstrecke ist nicht sonderlich lang - Das muß aber der TO bedenken.

MfG

Wo genau ist die halbe Spannung. Ein Digitalausgang kann nur an oder aus sein. Wenn er halbe Spannung hat, wird er entweder durch Übergangswiderstände zum Spannungsteiler zusammen mit deinem Basisivorwiderstand oder ist defekt. Da du aber auch sagtest, im Testprogramm auf Daueron funktioniert es, bleibt nur die Hysterese als Ursache über.

Als nächstes fällt mir auf, das du float einliest aus dem Analogeingang (zb Poti) was eigentlich ein Intergerwert ist. Danach übergibts du dieses float an ein Subprogramm als Byte. Was immer der Compiler dann draus macht, gesund sieht das nicht aus. Selbst wenn er eine Typ-Convertierung davor schaltet, bekommst du heftige Rundungsfehler rein wenn du von Float auf Byte wandelst. Der Analogeingang ist 10Bit(0-1023) und damit weit höher als Byte (0-255).

Arbeite an dem Punkt mal durch, benutze nur die Typen die deine Sensoren auch liefern und wandle zur Not selbst um aus Float dann Integer zu machen für den Potivergleich. So kannst du die Rundungsfehler selbst ausmerzen. Und dann verwende durchgängig int auch im Regelsubprogramm.

Wenn die Temperatur mit Kommastellen geliefert wird und die Feuchte nur als Prozentzahl ohne Kommastelle, dürfte das schon das unterschiedliche verhalten erklären. Wenn die letzte Stelle nach dem Komma wackelt schaltest du schon. Das MUSS ja flackern.Schon weil dein Potieinlesen nie 100% genau sein wird, je nach dem wie die Versorgungsspannung während der Wandlung sich leicht ändert. Du misst ca 5mV pro Digit am Analogeingang. Eine Änderung der Versorgungsspannung während der Wandlung von 5mV würde also einen Wert hoch oder runter gehen.

Du kennst das doch sicher, wenn du die Spannung mit dem Multimeter misst und die letzte Stelle wackelt, selbst wenns eine einfache Batterie ist die du misst und eigentlich weist das die Spannung 100% konstant bleibt.

Danke für deine Antwort :slight_smile:

Die halbe Spannung messe ich am Relais. Scheint als würde der Digitale Ausgang meines Arduinos ständig aus und wieder einschalten, woraufhin der Transistor nicht voll durchschaltet..

Habe gerade festgestellt, dass sobald ich mein RTC Module und das Display aus meinem Code rauslasse, alles funktioniert.. könnte der Fehler evtl sein, dass das RTC und LCD Störfrequenzen verursachen, welche meinen digitalen ausgang beeinflussen?

Füge noch Bilder vom Aufbau hinzu. Das RTC befindet sich im Gehäuse, das LCD im Frontpanelgehäuse, welches ich mit einem ca. 50cm langem Kabel verbinde, in dem sich alles vom Frontpanel befindet. Enstehen dort evtl Kapazitäten? Allerdings ist das RTC ja direkt im Gehäuse verbaut und wenn ich nur das mit in meinem Code einbringe läufts ja auch nicht.. :confused:

Störfrequenzen sind das sicher nicht, aber das könnte ein Spannungsproblem sein.

Mit welcher Spannung an welchem Anschluss betreibst du den Arduino ?
Was für ein Relais verwendest du ?
Hast du eine Freilaufdiode angeschlossen ?

Habe 12V eingangsspannung, welche ich mit einem Festspannungsregler auf 5V regel. Damit versorge ich meinen Arduino über den 5V Anschluss und dessen Komponenten.

Um die Relais zu schalten verwende ich einen BC337 Transistor, habe einen Basiswiderstand von 620 Ohm. Verwende eine IN4148 Freilaufdiode. Reilais benutze ich Finder 40.52 12V

Funktioniert soweit ja auch alles, nur wenn ich das LCD und RTC verwende klappts nicht mehr..

wachtiiii:
Habe 12V eingangsspannung, welche ich mit einem Festspannungsregler auf 5V regel. Damit versorge ich meinen Arduino über den 5V Anschluss und dessen Komponenten.

Was für einen Regler ?
Ist der genug gekühlt ?

Und was ist mit den anderen Fragen ?

Habe einen LM7805T. Denke der Kühlkörper ist groß genug (siehe Bild Gehäuse).

Hallo...nochmal.

Was für ein Relais verwendest du ?
Hast du eine Freilaufdiode angeschlossen ?

OK....sorry. Hatte übersehen, dass in deinem 2. Post ein Schaltbild vorhanden ist.

Ich kann aktuell keinen Zusammenhang zwischen deinem Fehler und der RTC bzw. dem LCD sehen.

Hast du das mit der Hysterese mal probiert ?

Sorry aber was genau wird mit Hysterese gemeint? Bzw in welchem Bezug ?