#include <Wire.h> // Kommunikation über I2C
#include <LiquidCrystal_I2C.h> // LCD Bibliothek
#define LED1_PIN 22 // LED für Betrieb
#define LED2_PIN 23 // LED für Abtropfschale
#define BUTTON1_PIN 34 // Drucktaster für Zitronensaft
#define BUTTON2_PIN 32 // Drucktaster für Vodka
#define BUTTON3_PIN 33 // Drucktaster für O-Saft
#define BUTTON4_PIN 30 // Drucktaster für Grenadine
#define BUTTON5_PIN 31 // Drucktaster für Tequila
#define BUTTON6_PIN 28 // Drucktaster für Cranberrysaft
#define BUTTON7_PIN 29 // Drucktaster für Pfirsichlikör
#define BUTTON8_PIN 26 // Drucktaster für Wasser
#define BUTTON9_PIN 27 // Drucktaster für Reset
#define BUTTON10_PIN 24 // Drucktaster für Abbruch
#define BUTTON11_PIN 25 // Drucktaster für Dorfmische (Vodka-O -> 50/50)
#define BUTTON12_PIN 53 // Drucktaster für Wartung
#define BUTTON13_PIN 47 // Drucktaster für Reinigung
#define POTI_PIN A0 // Poti zum Einstellen der Ausgabemenge
#define DRUCKSENSOR_PIN 44 // Glas unter Auslauf
#define BUZZER_PIN 45 // Pieper
#define ABTROPFSENSOR_PIN 46 // zwei unabhängige Drähte in einer Schüssel, wenn gewissen Füllstand erreicht, wird der Stromkreis geschlossen
#define RELAY1_PIN 35 // Relais
#define RELAY2_PIN 36
#define RELAY3_PIN 37
#define RELAY4_PIN 38
#define RELAY5_PIN 39
#define RELAY6_PIN 40
#define RELAY7_PIN 41
#define RELAY8_PIN 42
#define LCD_ADDRESS 0x27 // Definieren der Adresse
#define LCD_COLUMNS 20 // Definieren der Anzahl der Zeichen
#define LCD_ROWS 4 // Definieren der Anzahl der Zeilen
LiquidCrystal_I2C lcd(LCD_ADDRESS, LCD_COLUMNS, LCD_ROWS); // Initialisiere das I2C-LCD mit der definierten Adresse und Größe
int PotiWert = 0; // Poti/Ausgabelänge
unsigned long AusgabeZeit = 0; // Ausgabezeit
unsigned long HalbeAusgabeZeit = 0; // Ausgabezeit für 50/50 Mische
long Fuellstand1 = 0; // Zähler1 für ml Ausgabe in Sekunden
long Fuellstand2 = 0;
long Fuellstand3 = 0;
long Fuellstand4 = 0;
long Fuellstand5 = 0;
long Fuellstand6 = 0;
long Fuellstand7 = 0;
long Fuellstand8 = 0;
int EchterFuellstand1 = 0; // tatsächlicher Füllstand,
int EchterFuellstand2 = 0;
int EchterFuellstand3 = 0;
int EchterFuellstand4 = 0;
int EchterFuellstand5 = 0;
int EchterFuellstand6 = 0;
int EchterFuellstand7 = 0;
int EchterFuellstand8 = 0;
// bitte niemals über 999ml eingeben, da sonst das Display Probleme macht.
// Maximaler Füllstand in ml
int MaximalMenge1 = 700; // Zitronensaft
int MaximalMenge2 = 700; // Vodka
int MaximalMenge3 = 700; // O-Saft
int MaximalMenge4 = 700; // Grenadine
int MaximalMenge5 = 700; // Tequila
int MaximalMenge6 = 700; // Cranberrysaft
int MaximalMenge7 = 700; // Pfirsichlikör
int MaximalMenge8 = 999; // Wasser
int TrinkzielWasser = 1000; // Trinkziel Wasser: 1L (1000ml)
int Bezuege = 0; // Zählervariable, die hochgezählt wird, nach jedem Bezug 1-8 oder Dorfmische
bool Reset = false; // wichtige Variable, die dafür sorgt, dass beim resetten nicht ausversehen ein Bezug startet
unsigned long InaktivitaetsTimer = 0; // Inaktivitätstimer
unsigned long ReinigungsDauer = 10UL*1000*60; // 10 min Reinigung/ Durchlaufen aller Pumpen
void setup()
{
Serial.begin(9600); // Initialisiere die serielle Kommunikation, Alternativ wenn zu langsam 115200 nehmen wenn Komplikationen wieder 9600
lcd.init(); // Initialisiere das LCD
lcd.backlight(); // Schalte die Hintergrundbeleuchtung ein
lcd.clear();
lcd.setCursor(0, 0); // Erstes Textfeld oben links
lcd.print("Laden..."); // muss oben stehen, damit das überhaupt angezeigt wird, da es sonst durch das Hauptprogramm in "Bereit" über geht
pinMode(LED1_PIN, OUTPUT); // LEDs
pinMode(LED2_PIN, OUTPUT);
pinMode(BUTTON1_PIN, INPUT); // Taster
pinMode(BUTTON2_PIN, INPUT);
pinMode(BUTTON3_PIN, INPUT);
pinMode(BUTTON4_PIN, INPUT);
pinMode(BUTTON5_PIN, INPUT);
pinMode(BUTTON6_PIN, INPUT);
pinMode(BUTTON7_PIN, INPUT);
pinMode(BUTTON8_PIN, INPUT);
pinMode(BUTTON9_PIN, INPUT); // Reset
pinMode(BUTTON10_PIN, INPUT); // Abbruch
pinMode(BUTTON11_PIN, INPUT); // Mische
pinMode(BUTTON12_PIN, INPUT); // Wartung
pinMode(BUTTON13_PIN, INPUT); // Reinigung
pinMode(DRUCKSENSOR_PIN, INPUT); // Drucksensor
pinMode(ABTROPFSENSOR_PIN, INPUT); // Abtropfschale
pinMode(BUZZER_PIN, OUTPUT); // Buzzer
pinMode(RELAY1_PIN, OUTPUT); // Relais
pinMode(RELAY2_PIN, OUTPUT);
pinMode(RELAY3_PIN, OUTPUT);
pinMode(RELAY4_PIN, OUTPUT);
pinMode(RELAY5_PIN, OUTPUT);
pinMode(RELAY6_PIN, OUTPUT);
pinMode(RELAY7_PIN, OUTPUT);
pinMode(RELAY8_PIN, OUTPUT);
digitalWrite(RELAY1_PIN, LOW); // einmal vorab alle Relais auf Ausgangszustand setzen
digitalWrite(RELAY2_PIN, LOW);
digitalWrite(RELAY3_PIN, LOW);
digitalWrite(RELAY4_PIN, LOW);
digitalWrite(RELAY5_PIN, LOW);
digitalWrite(RELAY6_PIN, LOW);
digitalWrite(RELAY7_PIN, LOW);
digitalWrite(RELAY8_PIN, LOW);
delay(500); // Delay soll einfach dafür sogen, dass es den klassischen anschein hat, die Anlage müsse hochfahren
lcd.clear(); // Display einmal ganz leeren
lcd.setCursor(0, 0); // Erstes Textfeld oben links
lcd.print("Bereit!"); // muss ganz unten im Setup stehen, damit klar ist, dass das Setup durch ist
tone(BUZZER_PIN, 5000, 500); // Piepton, danit man weiß, dass Anlage betriebsbereit ist
}
// TasterHandhabung
void TasterHandhabung(int TasterPin, unsigned long ausgabeZeit, int relayPin, const char* bezugName, long &fuellstand, long echterFuellstand)
// Diese Funktion steuert die Ausgabe eines Getränks über einen bestimmten Taster.
// Die Ausgabe erfolgt nur, wenn bestimmte Bedingungen erfüllt sind (z.B. Taster gedrückt, Glas unter Ausgabe, Abtropfschale nicht voll).
// Eingabeparameter:
// - TasterPin: Der Pin, an dem der Taster angeschlossen ist.
// - ausgabeZeit: Dauer der Ausgabe in Millisekunden.
// - relayPin: Der Pin, der das Relais für die Getränkeförderung steuert.
// - bezugName: Name des Getränks, das ausgegeben wird, zur Anzeige auf dem LCD.
// - fuellstand: Referenz auf den aktuellen Füllstand des ausgegebenen Getränks.
// - echterFuellstand: Der tatsächliche Füllstand des Getränks vor der Ausgabe.
{
// Überprüfung, ob der Taster gedrückt ist, das Glas unter der Ausgabe ist, die Abtropfschale nicht voll ist und kein Reset erfolgt ist.
if (digitalRead(TasterPin) == HIGH && digitalRead(DRUCKSENSOR_PIN) == HIGH && digitalRead(ABTROPFSENSOR_PIN) == LOW && !Reset)
{
InaktivitaetsTimer = millis(); // Aktualisierung des Inaktivitäts-Timers, um die Aktivität zu erfassen.
Bezuege++; // Erhöhen des Bezugszähler um 1, um die Anzahl der Ausgaben zu verfolgen.
lcd.clear(); // LCD-Display löschen.
lcd.setCursor(0, 0);
lcd.print(bezugName); // Anzeige des Getränkenamens auf dem LCD, der Name wird automatisch aus dem Hauptprogramm übernommen.
lcd.setCursor(0, 1);
lcd.print("Verbleibende Zeit:"); // Anzeige der verbleibenden Zeit für die Ausgabe.
unsigned long BeginnAusgabe = millis(); // Startzeitpunkt der Ausgabe speichern.
// Schleife, die die Ausgabe steuert, bis die festgelegte Ausgabezeit erreicht ist.
while (millis() - BeginnAusgabe < ausgabeZeit)
{
// Überprüfung, ob der Abbruchknopf gedrückt wurde oder die Abtropfschale voll ist.
if (digitalRead(BUTTON10_PIN) == HIGH || digitalRead(ABTROPFSENSOR_PIN) == HIGH)
{
break; // Vorzeitiger Abbruch der Ausgabe, die Schleife wird beendet und die Ausgabe gestoppt.
}
unsigned long vergangeneZeit = millis() - BeginnAusgabe; // Berechnung der vergangenen Zeit seit Beginn der Ausgabe.
unsigned long verbleibendeZeit = ausgabeZeit - vergangeneZeit; // Berechnung der verbleibenden Zeit für die Ausgabe.
lcd.setCursor(0, 2);
lcd.print(verbleibendeZeit / 1000); // Anzeige der verbleibenden Zeit in Sekunden.
lcd.print(" Sekunden");
lcd.display(); // Aktualisieren des LCD-Displays.
digitalWrite(LED1_PIN, HIGH); // LED einschalten, um die aktive Ausgabe anzuzeigen.
digitalWrite(relayPin, HIGH); // Einschalten des Relais, um das Getränk auszugeben.
}
unsigned long vergangeneZeit = millis() - BeginnAusgabe; // Erneute Berechnung der vergangenen Zeit nach der Ausgabe.
fuellstand += vergangeneZeit; // Hinzufügen der vergangenen Zeit zum Füllstand des Getränks.
digitalWrite(LED1_PIN, LOW); // LED ausschalten, um das Ende der Ausgabe anzuzeigen.
digitalWrite(relayPin, LOW); // Relais ausschalten, um die Getränkeförderung zu stoppen.
tone(BUZZER_PIN, 5000, 500); // Kurzer Piepton als akustisches Signal am Ende der Ausgabe.
lcd.clear(); // LCD-Display löschen.
lcd.setCursor(0, 0);
lcd.print("Verbleibende Menge:"); // Anzeige des verbleibenden Füllstands des Getränks.
lcd.setCursor(0, 1);
berechneEchterFuellstand(); // Berechnung des tatsächlichen Füllstands nach der Ausgabe.
lcd.print(echterFuellstand - (fuellstand / 1000)); // Anzeige des verbleibenden Füllstands in Millilitern.
lcd.print(" ml");
delay(3000); // Kurze Verzögerung von 3 Sekunden, um dem Benutzer Zeit zu geben, die Anzeige zu lesen.
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Bereit!"); // Anzeige, dass das System bereit für die nächste Ausgabe ist.
}
}
void Dorfmische(unsigned long ausgabeZeit, long &fuellstand2, long &fuellstand3)
// Funktion zur Ausgabe einer "Dorfmische", einer Mischung von zwei Getränken.
// Die Ausgabe erfolgt nur, wenn bestimmte Bedingungen erfüllt sind.
// Eingabeparameter:
// - ausgabeZeit: Die Dauer, für die die Ausgabe erfolgt (in Millisekunden).
// - fuellstand2: Referenz auf den Füllstand des ersten Getränks (z. B. Vodka).
// - fuellstand3: Referenz auf den Füllstand des zweiten Getränks (z. B. Orangensaft).
{
// Überprüfen, ob der Startknopf gedrückt ist, der Drucksensor aktiv ist,
// die Abtropfschale leer ist und kein Reset erfolgt ist.
if (digitalRead(BUTTON11_PIN) == HIGH && digitalRead(DRUCKSENSOR_PIN) == HIGH && digitalRead(ABTROPFSENSOR_PIN) == LOW && !Reset)
{
InaktivitaetsTimer = millis(); // Aktualisieren des Inaktivitäts-Timers
Bezuege += 2; // Erhöhen des Bezugszähler
unsigned long BeginnAusgabe = millis(); // Startzeitpunkt der Ausgabe speichern
lcd.clear();
lcd.setCursor(0, 0); // erste Zeile
lcd.print("Dorfmische"); // Anzeige des Getränkenamens
lcd.setCursor(0, 1); // zweite Zeile
lcd.print("Verbleibende Zeit:");
// Schleife zur Steuerung der Ausgabe, bis die vorgegebene Ausgabezeit erreicht ist
while (millis() - BeginnAusgabe < ausgabeZeit)
{
// Überprüfung, ob der Abbruchknopf gedrückt wurde oder die Abtropfschale voll ist
if (digitalRead(BUTTON10_PIN) == HIGH || digitalRead(ABTROPFSENSOR_PIN) == HIGH)
{
break; // Abbrechen der Ausgabe
}
unsigned long vergangeneZeit = millis() - BeginnAusgabe; // Vergangene Zeit seit Beginn der Ausgabe
unsigned long verbleibendeZeit = ausgabeZeit - vergangeneZeit; // Berechnung der verbleibenden Zeit
lcd.setCursor(0, 2);
lcd.print(verbleibendeZeit / 1000); // Verbleibende Zeit in Sekunden anzeigen
lcd.print(" Sekunden");
lcd.display();
digitalWrite(LED1_PIN, HIGH); // LED einschalten
digitalWrite(RELAY2_PIN, HIGH); // Relais für erstes Getränk einschalten
digitalWrite(RELAY3_PIN, HIGH); // Relais für zweites Getränk einschalten
}
unsigned long vergangeneZeit = millis() - BeginnAusgabe; // Gesamte vergangene Zeit der Ausgabe
fuellstand2 += vergangeneZeit; // Aktualisierung des Füllstands für das erste Getränk
fuellstand3 += vergangeneZeit; // Aktualisierung des Füllstands für das zweite Getränk
digitalWrite(LED1_PIN, LOW); // LED ausschalten
digitalWrite(RELAY2_PIN, LOW); // Relais für erstes Getränk ausschalten
digitalWrite(RELAY3_PIN, LOW); // Relais für zweites Getränk ausschalten
tone(BUZZER_PIN, 5000, 500); // Kurzer Piepton als Signal am Ende der Ausgabe
berechneEchterFuellstand(); // Berechnung des tatsächlichen Füllstands der Getränke
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Rest Vodka:");
lcd.setCursor(0, 1);
lcd.print(EchterFuellstand2 - fuellstand2 / 1000); // Anzeigen des verbleibenden Füllstands von Vodka in Millilitern
lcd.print(" ml");
lcd.setCursor(0, 2);
lcd.print("Rest O-Saft:");
lcd.setCursor(0, 3);
lcd.print(EchterFuellstand3 - fuellstand3 / 1000); // Anzeigen des verbleibenden Füllstands von Orangensaft in Millilitern
lcd.print(" ml");
delay(4000); // Wartezeit von 4 Sekunden, bevor das Display zurückgesetzt wird
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Bereit!"); // Anzeige, dass das System wieder bereit ist
}
}
// Reinigungsprogramm
void Reinigung()
// Die Funktion `Reinigung` steuert den Reinigungsprozess des Geräts.
// Sie prüft, ob die Bedingungen für die Reinigung erfüllt sind, und führt diese dann durch.
{
if (digitalRead(BUTTON13_PIN) == HIGH && digitalRead(ABTROPFSENSOR_PIN) == LOW) // Überprüft, ob der Reinigungsbutton gedrückt und die Abtropfschale leer ist.
{
InaktivitaetsTimer = millis(); // Setzt den Inaktivitätstimer auf die aktuelle Zeit
unsigned long BeginnAusgabe = millis(); // Startzeit der Reinigung wird festgehalten
while (millis() - BeginnAusgabe < ReinigungsDauer) // Diese Schleife läuft für die Dauer der Reinigung, es sei denn, ein Abbruch wird festgestellt.
{
if (digitalRead(BUTTON10_PIN) == HIGH || digitalRead(ABTROPFSENSOR_PIN) == HIGH) // Überprüfung des Abbruchschalters und der Abtropfschale während der Ausgabezeit
{
break; // Wenn ein Abbruch festgestellt wird, wird die Schleife vorzeitig beendet.
}
// Aktiviert die Relais für die Reinigungsvorgänge
digitalWrite(RELAY1_PIN, HIGH);
digitalWrite(RELAY2_PIN, HIGH);
digitalWrite(RELAY3_PIN, HIGH);
digitalWrite(RELAY4_PIN, HIGH);
digitalWrite(RELAY5_PIN, HIGH);
digitalWrite(RELAY6_PIN, HIGH);
digitalWrite(RELAY7_PIN, HIGH);
digitalWrite(RELAY8_PIN, HIGH);
}
// Schaltet alle Relais wieder aus, nachdem die Reinigung beendet ist oder abgebrochen wurde.
digitalWrite(RELAY1_PIN, LOW);
digitalWrite(RELAY2_PIN, LOW);
digitalWrite(RELAY3_PIN, LOW);
digitalWrite(RELAY4_PIN, LOW);
digitalWrite(RELAY5_PIN, LOW);
digitalWrite(RELAY6_PIN, LOW);
digitalWrite(RELAY7_PIN, LOW);
digitalWrite(RELAY8_PIN, LOW);
tone(BUZZER_PIN, 10000, 500); // Gibt einen Signalton aus, um anzuzeigen, dass die Reinigung beendet ist.
}
}
// Füllstandswarnung /-überprüfung
void FuellstandWarnung(long echterFuellstand, unsigned long maxMenge, const char* bezugName) // Diese Funktion hat keine Rückgabeparameter.
// Die Funktion `FuellstandWarnung` überprüft den aktuellen Füllstand und zeigt eine Warnung auf dem LCD an, wenn der Füllstand unter 50 liegt.
// Eingabeparameter:
// - echterFuellstand (long): Der aktuelle Füllstand, der überprüft werden soll.
// - maxMenge (unsigned long): Die maximale Menge, die für den aktuellen Bezug erlaubt ist (nicht verwendet in dieser Funktion).
// - bezugName (const char*): Der Name des Getränks oder der Ressource, deren Füllstand überprüft wird.
{
if (echterFuellstand < 50) // Wenn der Füllstand unter 50 liegt, wird eine Warnung auf dem LCD angezeigt.
{
lcd.setCursor(0, 1); // Setzt den Cursor auf die zweite Zeile des LCDs
lcd.print(bezugName); // Zeigt den Namen der Ressource oder des Getränks an
lcd.setCursor(0, 2); // Setzt den Cursor auf die dritte Zeile des LCDs
lcd.print("ist leer"); // Zeigt die Warnung "ist leer" an
}
}
// Reinigungsempfehlung
void checkReinigung()
{
if(Bezuege == 30)
{
tone(BUZZER_PIN, 7000, 500);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("denk an Reinigung");
lcd.setCursor(0, 1);
lcd.print("und Abtropfschale!");
delay(2000);
Bezuege ++;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Bereit!");
}
}
// Resetfunktion der Füllstände 1-7
void Auffuellen(int TasterPin, long &fuellstand)
// Die Resetfunktion ist zum Resetten der Füllstände, damit man nach dem Wechseln einer Flasche den neuen Füllstand wieeder drin hat.
// Umgesetzt bzw. wichtig war: sperren anderer Funktionen, damit diese nicht ausversehen starten und da das Drücken ebenfalls eine Aktion darstellt, sollte der Inaktivitätstimer auf Null zurückgesetzt werden.
{
if(digitalRead(BUTTON9_PIN) == HIGH) // Startbedingung
{
InaktivitaetsTimer = millis(); // Rücksetzen des Inaktivitätstimers auf Null
Reset = true; // Sperrvariable, als Bedingung in anderen Codeabschnitten, solange true, wie der Taster gedrückt ist
}
else
{
Reset = false; // Sperrvariable zurücksetzen, wenn der Taster nicht gedrückt ist
}
if(digitalRead(BUTTON9_PIN) == HIGH && digitalRead(TasterPin) == HIGH)
{
fuellstand = 0; // hier passiert das eigentliche zurücksetzen der Füllstände, entsprechend der Eingabe
}
}
// Resetfunktion Wasser (Füllstand 8)
void WasserAuffuellen(long &fuellstand)
// hier ist das selbe umgesetzt wie in void Auffuellen, nur um einen Abschnitt erweitert, dass es eine weitere Variable gibt, die dafür sorgt, dass ein beliebiges Trinkziel oberhalb von der Füllmenge einer Flasche Wasser erreicht werden kann.
{
if(digitalRead(BUTTON9_PIN) == HIGH)
{
InaktivitaetsTimer = millis();
Reset = true;
}
else
{
Reset = false;
}
if(digitalRead(BUTTON9_PIN) == HIGH && digitalRead(BUTTON8_PIN) == HIGH)
{
TrinkzielWasser -= fuellstand; // Hier wird die Variable um das inkremental verringert, was der Flasche tatsächlich entnommen wurde, auch wenn schon z.B. nach der Hälfte einer Flasche diese gewechselt würde
fuellstand = 0;
}
}
// Wartungsprogramm
void Wartung()
{
if(digitalRead(BUTTON12_PIN) == HIGH)
{
InaktivitaetsTimer = millis();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Bei Problemen:");
lcd.setCursor(0, 1);
lcd.print("Bitte 123456667890");
lcd.setCursor(0, 2);
lcd.print("anrufen!");
lcd.setCursor(0, 3);
lcd.print("Bezuege: ");
lcd.print(Bezuege);
delay(3000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Zitronensaft: ");
lcd.print(EchterFuellstand1);
lcd.print("ml");
lcd.setCursor(0, 1);
lcd.print("Vodka: ");
lcd.print(EchterFuellstand2);
lcd.print("ml");
lcd.setCursor(0, 2);
lcd.print("O-Saft: ");
lcd.print(EchterFuellstand3);
lcd.print("ml");
lcd.setCursor(0, 3);
lcd.print("Grenadine: ");
lcd.print(EchterFuellstand4);
lcd.print("ml");
delay(4000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Tequila: ");
lcd.print(EchterFuellstand5);
lcd.print("ml");
lcd.setCursor(0, 1);
lcd.print("Cranberrysaft: ");
lcd.print(EchterFuellstand6);
lcd.print("ml");
lcd.setCursor(0, 2);
lcd.print("Pfirsichlikor: ");
lcd.print(EchterFuellstand7);
lcd.print("ml");
lcd.setCursor(0, 3);
lcd.print("Wasser: ");
lcd.print(EchterFuellstand8);
lcd.print("ml");
delay(4000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Bereit!");
}
}
// Inaktivitätstimer
void checkAktivitaet()
{
if(millis() - InaktivitaetsTimer >= 10UL * 60 * 1000)
{
tone(BUZZER_PIN, 7000, 500); // der Ton ist echt sehr grell und nervig
delay(1000);
tone(BUZZER_PIN, 7000, 500);
delay(1000);
tone(BUZZER_PIN, 7000, 500);
delay(1000);
tone(BUZZER_PIN, 7000, 500);
delay(1000);
tone(BUZZER_PIN, 7000, 500);
delay(1000);
tone(BUZZER_PIN, 7000, 500);
delay(1000);
tone(BUZZER_PIN, 7000, 500);
delay(1000);
tone(BUZZER_PIN, 7000, 500);
delay(1000);
tone(BUZZER_PIN, 7000, 500);
delay(1000);
tone(BUZZER_PIN, 7000, 500);
delay(1000);
InaktivitaetsTimer = millis();
}
}
// tatsächlichen Füllstand berechnen
void berechneEchterFuellstand()
{
EchterFuellstand1 = MaximalMenge1 - Fuellstand1 / 1000; // Annahme: 1ml/sek deswegen die 1000
EchterFuellstand2 = MaximalMenge2 - Fuellstand2 / 1000;
EchterFuellstand3 = MaximalMenge3 - Fuellstand3 / 1000;
EchterFuellstand4 = MaximalMenge4 - Fuellstand4 / 1000;
EchterFuellstand5 = MaximalMenge5 - Fuellstand5 / 1000;
EchterFuellstand6 = MaximalMenge6 - Fuellstand6 / 1000;
EchterFuellstand7 = MaximalMenge7 - Fuellstand7 / 1000;
EchterFuellstand8 = MaximalMenge8 - Fuellstand8 / 1000;
}
// Trinkziel für Wasser überprüfen
void checkTrinkzielWasser()
// Funktion sorft dafür, dass wenn genug Wasser entnommen wurde, die meldung "Trinkziel erreicht!"" auf dem Display auftaucht.
{
if(TrinkzielWasser - (Fuellstand8 / 1000) < 0)
{
lcd.setCursor(0, 3); // in der untersten Zeile (4) erscheint die Meldung
lcd.print("Trinkziel erreicht!");
}
}
// Vorschau Ausgabemenge
void zeigeAusgabemenge()
// Die Funktion verbessert das Bedienen der Anlage erheblich, da man jetzt vorher weiß, wie viel anschließend aus der Maschine kommt.
{
lcd.setCursor(0, 1); // in der zweiten Zeile, unter Bereit!, wird die ausgewählte Füllmenge angezeigt
lcd.print("Ausgabemenge: ");
lcd.print(AusgabeZeit / 1000);
lcd.print("ml "); // das Leerzeichen ist sehr wichtig, da ansonsten das "l" nicht überschrieben wird, wenn die Ausgabemenge unter 10 ml fällt
}
// Hauptprogramm
void loop()
{
// Poti und Umrechnung
PotiWert = analogRead(POTI_PIN); // Wert vom Poti auslesen
AusgabeZeit = map(PotiWert, 0, 1023, 0, 200000); // Potentiometer auf 200ml = 200 000 ms, als maximale Füllmenge eingestellt.
HalbeAusgabeZeit = (AusgabeZeit / 2); // Ausgabezeit nur für Dorfmische relevant.
zeigeAusgabemenge(); // Vorschau für anstehende Ausgabemenge
// Abtropfschale-Sensor und LED
if (digitalRead(ABTROPFSENSOR_PIN) == HIGH)
{
digitalWrite(LED2_PIN, HIGH);
lcd.setCursor(0, 0);
lcd.print("Abtropfschale leeren");
delay(1000); // dadurch flackert es "cool" das ist kein Bug sondern ein Feature:D
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Bereit!");
}
else
{
digitalWrite(LED2_PIN, LOW);
}
// Tasterhandhabung aufrufen
TasterHandhabung(BUTTON1_PIN, AusgabeZeit, RELAY1_PIN, "Zitronensaft", Fuellstand1, EchterFuellstand1);
TasterHandhabung(BUTTON2_PIN, AusgabeZeit, RELAY2_PIN, "Vodka", Fuellstand2, EchterFuellstand2);
TasterHandhabung(BUTTON3_PIN, AusgabeZeit, RELAY3_PIN, "O-Saft", Fuellstand3, EchterFuellstand3);
TasterHandhabung(BUTTON4_PIN, AusgabeZeit, RELAY4_PIN, "Grenadine", Fuellstand4, EchterFuellstand4);
TasterHandhabung(BUTTON5_PIN, AusgabeZeit, RELAY5_PIN, "Tequila", Fuellstand5, EchterFuellstand5);
TasterHandhabung(BUTTON6_PIN, AusgabeZeit, RELAY6_PIN, "Cranberrysaft", Fuellstand6, EchterFuellstand6);
TasterHandhabung(BUTTON7_PIN, AusgabeZeit, RELAY7_PIN, "Pfirsichlikoer", Fuellstand7, EchterFuellstand7);
TasterHandhabung(BUTTON8_PIN, AusgabeZeit, RELAY8_PIN, "Wasser", Fuellstand8, EchterFuellstand8);
Dorfmische(HalbeAusgabeZeit, Fuellstand2, Fuellstand3);
berechneEchterFuellstand();
// Resetfunktion aufrufen
Auffuellen(BUTTON1_PIN, Fuellstand1);
Auffuellen(BUTTON2_PIN, Fuellstand2);
Auffuellen(BUTTON3_PIN, Fuellstand3);
Auffuellen(BUTTON4_PIN, Fuellstand4);
Auffuellen(BUTTON5_PIN, Fuellstand5);
Auffuellen(BUTTON6_PIN, Fuellstand6);
Auffuellen(BUTTON7_PIN, Fuellstand7);
WasserAuffuellen(Fuellstand8);
FuellstandWarnung(EchterFuellstand1, MaximalMenge1, "Zitronensaft");
FuellstandWarnung(EchterFuellstand2, MaximalMenge2, "Vodka");
FuellstandWarnung(EchterFuellstand3, MaximalMenge3, "O-Saft");
FuellstandWarnung(EchterFuellstand4, MaximalMenge4, "Grenadine");
FuellstandWarnung(EchterFuellstand5, MaximalMenge5, "Tequila");
FuellstandWarnung(EchterFuellstand6, MaximalMenge6, "Cranberrysaft");
FuellstandWarnung(EchterFuellstand7, MaximalMenge7, "Pfirsichlikoer");
FuellstandWarnung(EchterFuellstand8, MaximalMenge8, "Wasser");
Wartung();
Reinigung();
checkReinigung(); // überprüfen, ob schon 30 Bezüge erfolgt sind
checkAktivitaet(); // überprüfen, ob Inaktivitätszeit überschritten wurde
checkTrinkzielWasser(); // überprüfen, ob Mindest-/Zielmenge Wasser getrunken wurde
}
Nicht wundern, dass so viel und oft doppelt kommentiert wurde, das ist eine Vorgabe der Uni. Einige Features mussten wir uns aus dem Allerwertesten ziehen, da wir sonst nicht genug Zielkriterien hätten.
Update bezüglich der Schaltung: Ich habe jetzt das Display und die Relaiskarte aus einer externen Stromquelle mit 5V gespeist, den Arduino speise ich jetzt via Vin mit 6,7V und den Rest wie gehabt. Jetzt läuft es!
Nun war ich wieder voreilig und habe ein paar nervige Fehler entdeckt: Einige Programmabschnitte, die zum starten nur eine Bedingung erfordern, starten zufällig von alleine. Da ich noch keine Taster mit Pull-Down eingebaut habe, glaube ich die PINs floaten einfach. Eine Berührung der Platine mit dem Finger reicht aus um es auszulösen 
Das Display läuft einwandfrei und ohne zu zicken. die Kabellänge sind übrigens 100cm, da hatte ich mich wohl ein wenig verschätzt
Es mag aber auch daran liegen, dass ich 0,5mm^2 Leitungen nutzen aber keine Ahnung.
Außerdem einmal der Klemmplan (ohne Brücken, aber die blauen sind alle verbunden, die schwarzen auch und bei den roten alle, bis auf die letzte):
zu guter Letzt sollte ich noch sagen, dass ich mit dem Code noch nicht fertig bin und noch an einigen Stellen optimierungsbedarf sehe. Wenn ihr da aber noch grobe Fehler seht oder anstehende Komplikationen, gerne melden 