Arduino hängt sich ab und zu auf! Tankspülung Steuerung

Hallo alle zusammen,

also erstmal vorweg ich bin ganz neu in der Programmierung unterwegs!
Aufgrund einer defekten Steuerung für die Tankspülung von meinen Eltern (Landwirtschaft), habe ich mich in einer einfachen Relais Steuerung mittels Arduino versucht. Die Steuerung funktioniert auch soweit bis auf das der Arduino sich selten jedoch ab und zu aufhängt.

Ich würde mich freuen wenn mal Jemand anders sich den Quellcode anschaut und mich auf Programmierfehler aufmerksam macht.

PS: Den Plan für die Steuerung lege ich nach, jedoch sollen lediglich Relais geschaltet werden.

Vielleicht könnt ihr mir weiterhelfen.

Lieben Gruß aus Ostfriesland

Steffen

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C lcd(0x27,16,2);

//Relais 1 ist an Digital out 2 angeschlossen usw.
boolean relais_1=2;
boolean relais_2=3;
boolean relais_3=4;
boolean relais_4=5;
boolean relais_5=6;
boolean relais_6=7;
boolean relais_7=8;
boolean relais_8=9;
const boolean buttonStart=11;
boolean buttonStateStart=0;

void setup() 
{                
  lcd.init();
 
  // initialize the digital pin as an output.
  pinMode(relais_1, OUTPUT); //ablass Ventil
  pinMode(relais_2, OUTPUT); // Kaltes Wasser Schütz
  pinMode(relais_3, OUTPUT); // Reinigungspumpe
  pinMode(relais_4, OUTPUT); //Warm Wasser vorspülen
  pinMode(relais_5, OUTPUT); // Warmes Wasser
  pinMode(relais_6, OUTPUT); //reserve
  pinMode(relais_7, OUTPUT); //reserve
  pinMode(relais_8, OUTPUT); //reserve
  pinMode(buttonStart, INPUT);
}

void loop() 
{
  delay(1000);
  buttonStateStart = digitalRead(buttonStart);
  while(buttonStateStart==LOW){
    lcd.setCursor(0,0);
    lcd.print("Zum Tank spuelen");
    lcd.setCursor(0,1);
    lcd.print("Start Druecken..");
    buttonStateStart=digitalRead(buttonStart);
    //solange start gleich 0 ist, bleibt er in der Schleife
  }//wenn er auf HIGH kommt wird das programm abgearbeitet
  //Display ini
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Tankspuelung in");
  lcd.setCursor(0,1);
  lcd.print("in 5 Sekunden");
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("in 4 Sekunden");
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("in 3 Sekunden");  
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("in 2 Sekunden");
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("in 1 Sekunden");
  delay(1000);
  lcd.clear();
  //Ablass Ventil
  lcd.setCursor(0,0);
  lcd.print("Ablass Ventil");
  lcd.setCursor(0,1);
  lcd.print("Offen->20Sek");
  digitalWrite(relais_1, HIGH); //Relais 1 Ablass ON
  delay(20000); //20 Sekunden
  digitalWrite(relais_1, LOW); //Relais 1 Ablass OFF
  //Ablass ende
   //Kaltes Wasser+Reinigungspumpe
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Kaltes Wasser");
  digitalWrite(relais_2, HIGH); //Relais 2 Kaltes Wasser ziehen ON
  delay(60000);
  lcd.setCursor(0,1);
  lcd.print("Reinigungspumpe");
  digitalWrite(relais_3, HIGH); //Relais 3 Reinigungspumpe ON
  delay(90000);
  digitalWrite(relais_2, LOW); //Relais 2 Kaltes Wasser ziehen OFF  
  digitalWrite(relais_3, LOW); //Relais 3 Reinigungspumpe OFF
  //Kaltes Wasser+Reinigungspumpe ende
  
  //Ersten 5 Minuten Ende
 
  //Ablass Ventil
  lcd.setCursor(0,0);
  lcd.print("Ablass Ventil");
  lcd.setCursor(0,1);
  lcd.print("             1/6");
  digitalWrite(relais_1, HIGH); //Relais 1 Ablass ON
  delay(120000); //2 Minuten
  digitalWrite(relais_1, LOW); //Relais 1 Ablass OFF
  //Ablass ende
  
  //Warm Wasser vorspuelen
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Warmwasser Vorsp");
  digitalWrite(relais_4, HIGH); //Relais 4 Warmwasser Vorspuelen ON
  delay(120000);
  lcd.setCursor(0,1);
  lcd.print("Reinigungspumpe");
  digitalWrite(relais_3, HIGH); //Relais 3 Reinigungspumpe ON
  delay(30000); //30 sekunden warten
  digitalWrite(relais_4, LOW); //Relais 4 Warmwasser Vorspuelen OFF
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Reinigungspumpe");
  delay(60000);
  lcd.setCursor(0,1);
  lcd.print("Ablass Ventil");
  digitalWrite(relais_1, HIGH); //Relais 1 Ablass ON
  delay(60000);
  lcd.setCursor(0,0);
  lcd.print("Ablass Ventil");
  lcd.setCursor(0,1);
  lcd.print("             2/6");
  digitalWrite(relais_3, LOW); //Relais 3 Reinigungspumpe OFF
  delay(60000);
  digitalWrite(relais_1, LOW); //Relais 1 Ablass OFF
  //11 1/2 Minuten ENDE
  //Warmes Wasser ziehen
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Spuelm+Warmwasse");
  digitalWrite(relais_5, HIGH); //Relais 5 Warmes Wasser ziehen ON
  delay(120000);
  lcd.setCursor(0,1);
  lcd.print("Reinigungspumpe");
  digitalWrite(relais_3, HIGH); //Relais 3 Reinigungspumpe ON
  delay(60000);
  digitalWrite(relais_5, LOW); //Relais 5 Warmes Wasser ziehen OFF
  lcd.setCursor(0,0);
  lcd.print("Reinigungspumpe");
  lcd.setCursor(0,1);
  lcd.print("             3/6");
  delay(300000);
  lcd.setCursor(0,1);
  lcd.print("             4/6");
  delay(450000);
  //Ablass Ventil
  lcd.setCursor(0,0);
  lcd.print("Ablass Ventil");
  lcd.setCursor(0,1);
  lcd.print("             5/6");
  digitalWrite(relais_1, HIGH); //Relais 1 Ablass ON
  delay(30000);
  digitalWrite(relais_3, LOW); //Relais 3 Reinigungspumpe OFF
  lcd.setCursor(0,0);
  lcd.print("Ablass Ventil");
  lcd.setCursor(0,1);
  lcd.print("             5/6");
  delay(90000);
  digitalWrite(relais_1, LOW); //Relais 1 Ablass oFF
  
  //30 Minuten Ende
  

 //Kaltes Wasser+Reinigungspumpe
  lcd.setCursor(0,0);
  lcd.print("Kaltes Wasser");
  lcd.setCursor(0,1);
  lcd.print("             5/6");
  digitalWrite(relais_2, HIGH); //Relais 2 Kaltes Wasser ziehen ON
  delay(100000);
  lcd.setCursor(0,1);
  lcd.print("Reinigungspumpe");
  digitalWrite(relais_3, HIGH); //Relais 3 Reinigungspumpe ON
  delay(30000);
  digitalWrite(relais_2, LOW); //Relais 2 Kaltes Wasser ziehen OFF
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Reinigungspumpe");
  delay(60000);
  //Ablass Ventil
  lcd.setCursor(0,1);
  lcd.print("Ablass Ventil");
  digitalWrite(relais_1, HIGH); //Relais 1 Ablass ON
  
  delay(30000); 
  digitalWrite(relais_3, LOW); //Relais 3 Reinigungspumpe OFF
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Ablass Ventil");
  delay(60000);
  digitalWrite(relais_1, LOW); //Relais 1 Ablass OFF

  //35 Minuten Ende
 //Kaltes Wasser+Reinigungspumpe
  lcd.setCursor(0,0);
  lcd.print("Kaltes Wasser");
  lcd.setCursor(0,1);
  lcd.print("             6/6");
  digitalWrite(relais_2, HIGH); //Relais 2 Kaltes Wasser ziehen ON
  delay(100000);
  lcd.setCursor(0,1);
  lcd.print("Reinigungspumpe");
  digitalWrite(relais_3, HIGH); //Relais 3 Reinigungspumpe ON
  delay(30000);
  digitalWrite(relais_2, LOW); //Relais 2 Kaltes Wasser ziehen OFF
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Reinigungspumpe");
  delay(60000);
  //Ablass Ventil
  lcd.setCursor(0,1);
  lcd.print("Ablass Ventil");
  digitalWrite(relais_1, HIGH); //Relais 1 Ablass ON
  
  delay(30000); 
  digitalWrite(relais_3, LOW); //Relais 3 Reinigungspumpe OFF
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Ablass Ventil");
  delay(60000);
  digitalWrite(relais_1, LOW); //Relais 1 Ablass OFF
  lcd.noBacklight();
  lcd.setCursor(0,0);
  lcd.print("Tankspuelung");
  lcd.setCursor(0,1);
  lcd.print("abgeschlossen");
  delay(60000);
}

Wie sieht denn die elektrische Verschaltung (Schaltplan) aus?


Der Treiber für die Relais ist ein ULN2803.-> ON Semiconductor 366828, DS datasheet pdf
Pin 1-8 -> An Digital Pins des Arduino
pin 10 auf +5V,
pin 9 auf masse,
die ausgaenge 11-18 an die 5V des Relais, die andere Seite der Steuerspule der Relais an +5V.
An jeden Eingang habe ich zusätzlich einen 10k Ohm pull-down Widerstand gegen Masse gesetzt.

Quelle: http://www.loetstelle.net/projekte/relaiskarte/relaiskarte.php und http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1237818951

Hallo Steffen,
stürzt das gesamte Programm ab oder nur das Display?
Ich denke es liegt sicherlich nicht am Programm sondern an den Einschaltspitzen der Relais.
Ich habe leider solche Erfahrungen auch gemacht.
Allerdings würde ich das Programm umbauen, dein gesamtes Programm besteht ja fast nur aus delays (Warteschleifen),
das ist in meine AUgen extrem "unschön".
gruß

Hey maverick1509, danke für den Tipp :).
Weißt du wie ich das angehen kann bzw. anhand von welchem Beispiel.
Zum Absturz:

-->Da die Tankspülung nur jeden 2ten Tag benutzt wird, läuft der Arduino natürlich mal 50 Stunden in der Schleife und erwartet ein HIGH am Taster.
Wenn er dann gedrückt wird startet das Programm jedoch nicht immer..-> erst nach einem Reset kann ich dann das Programm mit Hilfe des Tasters starten.

--> Dann kommt es ab und zu vor das es an unterschiedlichen Stellen einfach stehen bleibt -> z.B. Ablass offen --> hier bleibt er dann hängen und kommt nicht mehr weiter.

Achso und mit den Einschaltspritzen -= bringt der den Arduino durcheinander? Sollte ich die Relais vielleicht mit einem eigenen Netzteil betreiben

--> Es ist auch schon vorgekommen dann nach einem Tag nicht mehr "Zum Start bitte Taste Drücken" stand sondern einfach irgendwelche Hieroglyphen.

Ist vielleicht meine Taster Abfrage falsch?

Achso und mit den Einschaltspritzen -= bringen die Relais den Arduino beim anziehen durcheinander? Sollte ich die Relais vielleicht mit einem eigenen Netzteil betreiben?

Danke Gruß Steffen

Komisches Fehlerbild, denn stehenbleiben kann der Script ja eigentlich nicht.

Stimmt die Stromversorgung des Aruduinos? Bei Versorgung über Netzteil sollten immer 7-12 V da sein. Welche Leistung und Spannung hat dein Netzteil?

//Relais 1 ist an Digital out 2 angeschlossen usw.
boolean relais_1=2;
boolean relais_2=3;
boolean relais_3=4;
boolean relais_4=5;
boolean relais_5=6;
boolean relais_6=7;
boolean relais_7=8;
boolean relais_8=9;
const boolean buttonStart=11;
boolean buttonStateStart=0;

Wieso definierst du diese Variablen als boolean, boolean Variablen können doch nur true oder false enthalten.
int wäre hier der richtige Datentyp.

Ich glaube nicht, dass dies Dein Problem ist, aber Du verschwendest viel RAM durch die Zeichenketten in print-Aufrufen. Du kannst das verhindern, indem Du überall, wo eine konstante Zeichenkette (in "") in einem print- oder println-Aufruf steht, einfach ein F()-Macro drum herum machts:

lcd.print("Start Druecken..");

wird dann

lcd.print(F("Start Druecken.."));

Das dürfte Dir ca. 600 Byte zusätzliches RAM geben (ist ein Drittel des auf einem UNO zur Verfügung stehenden Speichers).

Hallo,
wenn das Display Schrott angezeigt hat, dann liegt der Fehler wohl an den Relais.
Das hab ich nur in den Griff bekommen, indem ich das Display nicht in der Void setup resette oder initialisiere, sondern ständig in der void loop.
Das mit den delays kann man z.B. so lösen, ich versuchs mal an deinem Beispiel:

startzeit=millis(); // wenn das Programm startet wird die interne Zeit gemerkt

lcd.setCursor(0,0);
  lcd.print("Ablass Ventil");
  lcd.setCursor(0,1);
  lcd.print("Offen->20Sek");
  
 if ((millis() - startzeit) < 20000) digitalWrite(relais_1, HIGH); //Relais 1 Ablass ON
  else digitalWrite(relais_1, LOW); //Relais 1 Ablass OFF
  //Ablass ende
   //Kaltes Wasser+Reinigungspumpe
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Kaltes Wasser");
  
if ((millis() - startzeit) > 20000 && (millis() - Startzeit) < 150000){ 
 if (millis() - Startzeit) < 60000) digitalWrite(relais_2, HIGH); //Relais 2 Kaltes Wasser ziehen ON
 if ((millis() - startzeit) > 60000) digitalWrite(relais_3, HIGH); //Relais 3 Reinigungspumpe ON
 }
 else { 
 digitalWrite(relais_2, LOW); //Relais 2 Kaltes Wasser ziehen OFF  
  digitalWrite(relais_3, LOW); //Relais 3 Reinigungspumpe OFF
  //Kaltes Wasser+Reinigungspumpe ende
}

und so weiter..................

ich habs jetzt einfach mal so hingeschrieben ohne Syntaxprüfung.
Aber so wird ein Programm nie angehalten und läuft ständig weiter.

Falls etwas unklar ist, einfach fragen.

gruß
Bernward

Danke für die Tipps erstmal :).

--> das "Display Init" habe ich nun in den void loop gepackt.
--> das mit den F()-Macros kannte ich nicht habe ich einfach mal gemacht
--> Netzteil hängt ein 7.5V 1,5A an dem Arduino
--> @ kduin wie ist das nun mit den Variablen ich hatte diese erst als "int" gesetzt dann habe ich aber gedacht das die Relais ja auch nur ein HIGH oder LOW können müssen also habe ich boolean genommen und am Anfang des Codes setze ich doch nur die Digitalen Ausgänge für die Variablen ?!

@ maverick1509 . danke für das Beispiel und im Prinzip verstehe ich diese Programmierweise aber
"startzeit=millis(); // wenn das Programm startet wird die interne Zeit gemerkt" ist das nun schon ein fertiger Timer der läuft?

Aber kann es den sein das der Arduino wegen zu vieler Delays einfach abstürzt?

dann habe ich aber gedacht das die Relais ja auch nur ein HIGH oder LOW können müssen also habe ich boolean genommen

In den Variablen speicherst Du aber nicht die Zustände, sondern die Pins, an welchen die Relays angeschlossen sind. Dafür ist zwar nicht unbedingt ein int notwendig, aber ein uint8_t sollte es schon sein. Dein Glück war, dass für die Speicherung eines boolean auch ein Byte verwendet wird und der Compiler scheinbar keine Wertprüfung macht.

Aber kann es den sein das der Arduino wegen zu vieler Delays einfach abstürzt?

Nein, aufgrund der Delays stürzt das Programm sicher nicht ab, denn das sind einfach Warteschlaufen. Aufgrund Deiner Fehlerbeschreibung gehe ich momentan auch eher von einer elektrischen als einer programm-technischen Ursache aus.

Wie gross ist der Abstand zwischen dem Arduino und dem Display (I2C Kabel-Länge)?

Wie gross ist der Abstand zwischen dem Arduino und dem Display (I2C Kabel-Länge)?

ca. 20cm auf keine Fall mehr

Die Variablen werde ich auf "int" ändern mehr Werte benötige ich ja auch nicht.

Und ich mache mich mal an die Stromversorgung vom Arduino dran, es ist ja nun auch auf einem alten Bauernhof und dann kommt noch dazu das die Milchtank Kühlung und co. natürlich auch das Netz gut runterziehen kann. Ich werde zum testen mal einfach einen 5V 1A Handylader+Travel Usb Akku als sozusagen Buffer anschließen.

Danke erstmal für die vielen Tipps --> ich werde Berichten :slight_smile:

Nimm uint_8 statt int. Der normale Integer ist eine 16-Bit-Zahl, das heißt für jeden definierten Int werden 16Bit vom RAM belegt, um Zahlen im Wertebereich zwischen -32768 bis 32768 speichern zu können. Nachdem du das alerdings nur zur Portzuweisung nimmst, benötigst du keinen so riesigen Bereich. ein unsigned 8-Bit Integer (uint_8) speichert dir dagegen positive Werte von 0-255 und benötigt nur die Hälfte. 8 bzw. 16 Bit speicherverbrauch klingt im ersten moment nicht viel, aber wenn man das konsequent abprüft, welche Werte man braucht, summiert es sich - und manchmal geht es genau um diese 1-2 Bytes an die fehlen.

Also an der Versorgung scheint es nicht zu liegen :/.. Ich werde mich nun darum kümmern eine neue Relaisplatine zu bauen mittels Optokoppler. Ich glaube darin liegt mein Fehler weil das Ding 2 mal hintereinander beim ersten Relais abschalten sich aufgehängt hat.

Gruß Steffen

Habe mir nun die Fertige Platine bestellt.--> http://cgi.ebay.de/ws/eBayISAPI.dll?ViewItem&item=150748614175&ssPageName=ADME:X:DERP:DE:1123