Bewässerungsautomat Programmversion 0.5
Achtung!
Programmversion 0.5 eliminiert den delay()-Befehl am Ende der 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:
- http://blog.humblecoder.com/arduino-multitasking-using-finite-state-machines/ (Sehr gute Erklärung.)
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 <Wire.h>
#include <Adafruit_NeoPixel.h>
#include <Adafruit_Sensor.h>
#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