====== Bewässerungsautomat Programmversion 0.5 ====== Diese Programmversion wird nicht mehr weiter entwickelt. Weiter geht es mit [[programmversion_0.6|Programmversion 0.6]] Programmversion 0.5 eliminiert den delay()-Befehl am Ende der [[bewaesserungsautomat:programmversion_0.4|Programmversion 0.4]]. Diese Umstellung ist notwendig, um die Neopixel nicht nur an- und ausschalten zu können, sondern sie in der Helligkeit "pulsieren" können zu lassen. Mit delay() wartet die Programmschleife nach jedem Durchlauf eine definierte Zeit, bevor sie nochmals durchlaufen wird. Mit dem millis()-Befehl kann man die Programmschleife so umbauen, dass einzelne if-Abfragen nach einer vorgegebenen Zeit ausgeführt werden. Auf diese Weise ist es möglich, verschiedene if-Abfragen mit unterschiedlichen Frequenzen ausführen zu können. Beispielsweise kann die if-Abfrage für die Steuerung der NeoPixel alle 10 ms durchlaufen werden, während die restliche Programmschleife weiterhin nur alle 1000 ms ausgeführt wird. Hilfreiche Links: * https://learn.adafruit.com/multi-tasking-the-arduino-part-3/overview * http://www.vielsichtig.de/index.php?id=120 * http://blog.humblecoder.com/arduino-multitasking-using-finite-state-machines/ (Sehr gute Erklärung.) * https://www.baldengineer.com/millis-tutorial.html * https://www.baldengineer.com/arduino-how-do-you-reset-millis.html * https://www.baldengineer.com/millis-cookbook.html Der folgende Code läuft, allerdings nicht ganz rund: Der Fading-Effekt hakelt etwas. Durch einige Optimierungen des Programms konnte das Hakeln gemildert werden, ganz verschwunden ist es aber noch nicht. Was noch zu tun ist: * Der Fading-Effekt muss geschmeidiger laufen. // Bibliotheken einbinden #include #include #include #include "Adafruit_TSL2591.h" #include "DHT.h" // Definiert die Pins für die NeoPixel #define neoPin1 36 // Neopixel an Blumenkastenensor 1 #define neoPin2 38 // Neopixel an Blumenkastenensor 2 #define neoPin3 40 // Neopixel an Blumenkastenensor 3 #define neoPin4 42 // Neopixel an Blumenkastenensor 4 #define neoPin5 44 // Neopixelring am Wasserstandssensor im Vorratsbehälter #define neoPin6 48 // Neopixelring im Gehäusedeckel //#define neoPin6 = 50 // Reserviert für Erweiterungen // Definiert die NeoPixel Adafruit_NeoPixel neopix1 = Adafruit_NeoPixel(1, neoPin1, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel neopix2 = Adafruit_NeoPixel(1, neoPin2, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel neopix3 = Adafruit_NeoPixel(1, neoPin3, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel neopix4 = Adafruit_NeoPixel(1, neoPin4, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel neopix5 = Adafruit_NeoPixel(12, neoPin5, NEO_RGBW + NEO_KHZ800); Adafruit_NeoPixel neopix6 = Adafruit_NeoPixel(24, neoPin6, NEO_RGBW + NEO_KHZ800); // pass in a number for the sensor identifier (for your use later) Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // Definiert die Pins für die Hall-Sensoren #define hallPin1 35 // Hall-Sensor 1 #define hallPin2 33 // Hall-Sensor 2 #define hallPin3 31 // Hall-Sensor 3 #define hallPin4 29 // Hall-Sensor 4 // Definiert die Pins für die Verfügbarkeitskontrolle #define massePin1 47 // Masse an Blumenkastenensor 1 #define massePin2 49 // Masse an Blumenkastenensor 2 #define massePin3 51 // Masse an Blumenkastenensor 3 #define massePin4 53 // Masse an Blumenkastenensor 4 // Definiert die Pins des Wasserstandssensor für den Vorratsbehälter #define refPin A0 // Rref #define levelPin A1 // Rsense // Definiert den Pin für den DHT22 #define dhtPin 28 // Definiert den angeschlossenen Sensor #define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321) // Initialisiert den DHT-Sensor DHT dht(dhtPin, DHTTYPE); // Definiert die Variablen int hall1 = LOW; int hall2 = LOW; int hall3 = LOW; int hall4 = LOW; int masse1 = LOW; int masse2 = LOW; int masse3 = LOW; int masse4 = LOW; int rlevel; int rref; int level; float h; float t; float taupunkt; uint16_t ir; uint16_t full; uint32_t lum; float brightness = 127; byte green; byte red; byte blue; boolean pumpe1 = false; boolean pumpe2 = false; boolean pumpe3 = false; boolean pumpe4 = false; // Definiert die Tracking-Variablen für die IF-Abfragen unsigned long previousMillisNeoPixel = 0; unsigned long previousMillisWaterPumps = 0; unsigned long previousMillisTankSensor = 0; unsigned long previousMillisSerialWrite = 0; // Definiert die Intervalle für die IF-Abfragen int intervalNeoPixel = 10; int intervalWaterPumps = 500; int intervalTankSensor = 500; int intervalSerialWrite = 2000; byte counter = 0; boolean sw = true; void setup() { // Initialisiere die NeoPixel-Pins pinMode(neoPin1, OUTPUT); pinMode(neoPin2, OUTPUT); pinMode(neoPin3, OUTPUT); pinMode(neoPin4, OUTPUT); pinMode(neoPin5, OUTPUT); pinMode(neoPin6, OUTPUT); // Initialisiere die Hall-Pins als Inputs mit Pullup. Außerdem werden die internen Pullup-Widerstände aktiviert. // Liegt an dem Hall-Sensor ein Magnetfeld an, ist der Input LOW, ansonsten ist der Input HIGH. pinMode(hallPin1, INPUT_PULLUP); pinMode(hallPin2, INPUT_PULLUP); pinMode(hallPin3, INPUT_PULLUP); pinMode(hallPin4, INPUT_PULLUP); pinMode(massePin1, INPUT_PULLUP); pinMode(massePin2, INPUT_PULLUP); pinMode(massePin3, INPUT_PULLUP); pinMode(massePin4, INPUT_PULLUP); //Initialisiert den Pin für den DHT22 als Input mit Pullup pinMode(dhtPin, INPUT_PULLUP); // Initialisiere den Wasserstandssensor pinMode(rlevel, INPUT); pinMode(rref, INPUT); // Initialisiere alle NeoPixels neopix1.begin(); neopix1.show(); // Initialize all pixels to 'off' neopix2.begin(); neopix2.show(); // Initialize all pixels to 'off' neopix3.begin(); neopix3.show(); // Initialize all pixels to 'off' neopix4.begin(); neopix4.show(); // Initialize all pixels to 'off' neopix5.begin(); neopix5.show(); // Initialize all pixels to 'off' neopix6.begin(); neopix6.show(); // Initialize all pixels to 'off' // Konfiguration des TSL2591 // You can change the gain on the fly, to adapt to brighter/dimmer light situations //tsl.setGain(TSL2591_GAIN_LOW); // 1x gain (bright light) tsl.setGain(TSL2591_GAIN_MED); // 25x gain // tsl.setGain(TSL2591_GAIN_HIGH); // 428x gain // Changing the integration time gives you a longer time over which to sense light // longer timelines are slower, but are good in very low light situtations! tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS); // shortest integration time (bright light) // tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS); // tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS); // tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS); // tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS); // tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS); // longest integration time (dim light) // Initialisiere die serialle Schnittstelle Serial.begin(9600); //Initiallisiere die Sensoren dht.begin(); //Temperatur- und Feuchtigkeitssensor tsl.begin(); //Lichtsensor delay(2000); // Diese Pause benötigt der DHT22 um erste Messwerte zu lesen. // Perspektivisch könnte eine Startanimation des NeoPixel-Rings die Wartezeit verkürzen. } void loop() { // Aktuelle Zeit abfragen unsigned long currentMillis = millis(); // Abfrage der analogen und digitalen Eingänge und Steuerung der Pumpen if ((unsigned long)(currentMillis - previousMillisWaterPumps) >= intervalWaterPumps) { // Auslesen der digitalen Eingänge hall1 = digitalRead(hallPin1); hall2 = digitalRead(hallPin2); hall3 = digitalRead(hallPin3); hall4 = digitalRead(hallPin4); masse1 = digitalRead(massePin1); masse2 = digitalRead(massePin2); masse3 = digitalRead(massePin3); masse4 = digitalRead(massePin4); // Auslesen der analogen Eingänge rlevel = analogRead(levelPin); rref = analogRead(refPin); //Auslesen des Helligkeitssensors lum = tsl.getFullLuminosity(); ir = lum >> 16; full = lum & 0xFFFF; // Auslesen des DHT22 // Reading temperature or humidity takes about 250 milliseconds! // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) h = dht.readHumidity(); // Luftfeuchte auslesen t = dht.readTemperature(); //Temperatur in Grad Celsius auslesen // Berechnung des Wasserstands im Vorratsbehälter in Prozent int rlevelmin = 830; // Messwert bei minimalem Wasserstand int rlevelmax = 430; // Messwert bei maximalem Wasserstand level = 100 - (((rlevelmax - rlevel) / (rlevelmax - rlevelmin)) * 100); // Berechnung der Helligkeit der NeoPixel brightness = log(full) / 10; // Taupunkt berechnen float a = 17.271; float b = 237.7; float taupunktTmp = (a * t) / (b + t) + log(h/100); taupunkt = (b * taupunktTmp) / (a - taupunktTmp); // Ansteuerung der Pumpen. // Ist der Wasserstand niedrig, liegt kein Magnetfeld am Hall-Sensor an (hall = 1). // Die entsprechende Pumpe wird aktiviert, bis der Soll-Wasserstand erreicht ist (hall = 0), // - sofern keine andere Pumpe läuft und // - sofern Wasser im Vorratsbehälter ist. // Pumpe 1 an PWM-Pin 2 if (masse1 == 0 && hall1 == 1 && level > 5 && pumpe2 == false && pumpe3 == false && pumpe4 == false) { analogWrite(11, 20); pumpe1 = true; } else { analogWrite(11, 0); pumpe1 = false; } // Pumpe 2 an PWM-Pin 3 if (masse2 == 0 && hall2 == 1 && level > 5 && pumpe1 == false && pumpe3 == false && pumpe4 == false) { analogWrite(10, 20); pumpe2 = true; } else { analogWrite(10, 0); pumpe2 = false; } // Pumpe 3 an PWM-Pin 4 if (masse3 == 0 && hall3 == 1 && level > 5 && pumpe1 == false && pumpe2 == false && pumpe4 == false) { analogWrite(9, 20); pumpe3 = true; } else { analogWrite(9, 0); pumpe3 = false; } // Pumpe 4 an PWM-Pin 5 if (masse4 == 0 && hall4 == 1 && level > 5 && pumpe1 == false && pumpe2 == false && pumpe3 == false) { analogWrite(8, 20); pumpe4 = true; } else { analogWrite(8, 0); pumpe4 = false; } //Speichere die aktuelle Zeit in die zughörige Variable previousMillisWaterPumps = currentMillis; } // Steuerung der NeoPixel if ((unsigned long)(currentMillis - previousMillisNeoPixel) >= intervalNeoPixel) { // Ansteuerung der NeoPixels in den Blumenkastensensoren if(sw) { counter++; if(counter==255) sw = !sw; } if(!sw) { counter--; if(counter==10) sw = !sw; } // fade led mit counter green = counter*brightness; red = counter*brightness; //NeoPixel an Blumenkastensensor 1 if (hall1 == 0) { neopix1.setPixelColor(0, 0, red, 0); } else { neopix1.setPixelColor(0, green, 0, 0); } neopix1.show(); //NeoPixel an Blumenkastensensor 2 if (hall2 == 0) { neopix2.setPixelColor(0, 0, red, 0); } else { neopix2.setPixelColor(0, green, 0, 0); } neopix2.show(); //NeoPixel an Blumenkastensensor 3 if (hall3 == 0) { neopix3.setPixelColor(0, 0, red, 0); } else { neopix3.setPixelColor(0, green, 0, 0); } neopix3.show(); //NeoPixel an Blumenkastensensor 4 if (hall4 == 0) { neopix4.setPixelColor(0, 0, red, 0); } else { neopix4.setPixelColor(0, green, 0, 0); } neopix4.show(); //Speichere die aktuelle Zeit in die zughörige Variable previousMillisNeoPixel = currentMillis; } //Ansteuerung der NeoPixel in dem Messstab für den Vorratstank if ((unsigned long)(currentMillis - previousMillisTankSensor) >= intervalTankSensor) { //Ansteuerung des NeoPixel-Rings im Wasserstandssensor für den Vorratsbehälter neopix5.setPixelColor(0, 0, 0, 0, 255*brightness); neopix5.setPixelColor(11, 0, 0, 0, 255*brightness); if (level >= 90) { neopix5.setPixelColor(10, 0, 255*brightness, 0, 0); } else if (level < 90) { neopix5.setPixelColor(10, 0, 0, 0, 0); } if (level >= 80) { neopix5.setPixelColor(9, 0, 255*brightness, 0, 0); } else if (level < 80) { neopix5.setPixelColor(9, 0, 0, 0, 0); } if (level >= 70) { neopix5.setPixelColor(8, 0, 255*brightness, 0, 0); } else if (level < 70) { neopix5.setPixelColor(8, 0, 0, 0, 0); } if (level >= 60) { neopix5.setPixelColor(7, 0, 255*brightness, 0, 0); } else if (level < 60) { neopix5.setPixelColor(7, 0, 0, 0, 0); } if (level >= 50) { neopix5.setPixelColor(6, 127*brightness, 127*brightness, 0, 0); } else if (level < 50) { neopix5.setPixelColor(6, 0, 0, 0, 0); } if (level >= 40) { neopix5.setPixelColor(5, 127*brightness, 127*brightness, 0, 0); } else if (level < 40) { neopix5.setPixelColor(5, 0, 0, 0, 0); } if (level >= 30) { neopix5.setPixelColor(4, 127*brightness, 127*brightness, 0, 0); } else if (level < 30) { neopix5.setPixelColor(4, 0, 0, 0, 0); } if (level >= 20) { neopix5.setPixelColor(3, 255*brightness, 0, 0, 0); } else if (level < 20) { neopix5.setPixelColor(3, 0, 0, 0, 0); } if (level >= 10) { neopix5.setPixelColor(2, 255*brightness, 0, 0, 0); } else if (level <10) { neopix5.setPixelColor(2, 0, 0, 0, 0); } neopix5.show(); // Warnung bei Unterschreiten der Gehäuseinnentemperatur unter den Taupunkt if (t <= taupunkt) { neopix5.setPixelColor(0, 255*brightness, 0, 0, 0); neopix5.setPixelColor(11, 255*brightness, 0, 0, 0); } else if (t > taupunkt) { neopix5.setPixelColor(0, 0, 0, 0, 255*brightness); neopix5.setPixelColor(11, 0, 0, 0, 255*brightness); } //Speichere die aktuelle Zeit in die zughörige Variable previousMillisTankSensor = currentMillis; } //Ausgabe an die serielle Schnittstelle if ((unsigned long)(currentMillis - previousMillisSerialWrite) >= intervalSerialWrite) { Serial.println("------------------------------------"); //Ausgabe des Zeitstempels Serial.print("[ "); Serial.print(millis()); Serial.println(" ms ] "); // Ausgabe der Eingangssignale an den digitalen Masse-Pins an die serielle Schnittstelle // Der Ausgabewert "0" bedeutet, dass der entsprechende Blumenkastensensor angeschlossen ist Serial.print("Sensor Kasten 1: "); Serial.print(masse1); Serial.print(" \t"); Serial.print("Sensor Kasten 2: "); Serial.print(masse2); Serial.print(" \t"); Serial.print("Sensor Kasten 3: "); Serial.print(masse3); Serial.print(" \t"); Serial.print("Sensor Kasten 4: "); Serial.print(masse4); Serial.println(" \t"); // Ausgabe der Eingangssignale an den digitalen Hall-Pins an die serielle Schnittstelle // Der Ausgabewert "1" bedeutet, dass kein Magnetfeld gemessen wird Serial.print("Hallschalter 1: "); Serial.print(hall1); Serial.print(" \t"); Serial.print("Hallschalter 2: "); Serial.print(hall2); Serial.print(" \t"); Serial.print("Hallschalter 3: "); Serial.print(hall3); Serial.print(" \t"); Serial.print("Hallschalter 4: "); Serial.print(hall4); Serial.println(" \t"); //Ausgabe des Status der Pumpen Serial.print("Pumpe 1: "); Serial.print(pumpe1); Serial.print(" \t"); Serial.print("Pumpe 2: "); Serial.print(pumpe2); Serial.print(" \t"); Serial.print("Pumpe 3: "); Serial.print(pumpe3); Serial.print(" \t"); Serial.print("Pumpe 4: "); Serial.print(pumpe4); Serial.println(" \t"); // Ausgabe des Eingangssignals an den analogen Wasserstands-Pins an die serielle Schnittstelle Serial.print("Wert Sensorwiderstand: "); Serial.print(rlevel); Serial.print("\t"); Serial.print("Wert Referenzwiederstand: "); Serial.print(rref); Serial.println("\t"); // Ausgabe des Wasserstands im Vorratsbehälter in Prozent an die serielle Schnittstelle Serial.print("Wasserstand: "); Serial.print(level); Serial.println(" %"); //Ausgabe verschiedener Helligkeitswerte an die serielle Schnittstelle Serial.print("IR: "); Serial.print(ir); Serial.print(" "); Serial.print("Full: "); Serial.print(full); Serial.print(" "); Serial.print("Visible: "); Serial.print(full - ir); Serial.print(" "); Serial.print("Lux: "); Serial.println(tsl.calculateLux(full, ir)); //Ausgabe der Temperatur-, Luftfeuchte und des berechneten Taupunkts an die serielle Schnittstelle Serial.print("Luftfeuchte: "); Serial.print(h); Serial.print(" %\t"); Serial.print("Temperatur: "); Serial.print(t); Serial.print(" *C\t"); Serial.print("Taupunkt: "); Serial.print(taupunkt); Serial.println(" *C"); //Ausgabe des berechneten Helligkeitswerts an die sereille Schnittstelle Serial.print("Helligkeit: "); Serial.println(brightness); // Check if any reads failed and exit early (to try again). if (isnan(h) || isnan(t)) { Serial.println("DHT22 konnte nicht ausgelesen werden!"); return; } previousMillisSerialWrite = currentMillis; } } Tags: #Arduino #Bewässerungsautomat #Code