#include "ClassRotMenue.h"
# include <Wire.h>
////////////////// Display //////////////////////////
#include <LiquidCrystal_I2C.h>
//# include <LiquidCrystal_I2C.h> //LCD Modul aufrufen
LiquidCrystal_I2C lcd(0x27, 20, 4);
////////////////////Urzeit Datum ///////////////////
/*
ec2021 - Beispiel für die Anwendung der Klasse RotMenue
*/
// Verschiedene - zum Teil über den Encoder anwählbare -
// States einer beispielhaften State Machine
// a) Hauptmenü zur Auswahl der Submenüs
// - Ansteuerung einer grünen Led
// - Ansteuerung vom Schalter Aussenlicht
// - Ansteuerung eines Servos
// b) In den Submenüs für die Leds
// - Einschalten der Led
// - Ausschalten der Led
// - Rückkehr ins Hauptmenü
// c) In dem Submenü für den Servo
// - Auslösen eines Tones 262 Hz für 250 ms
// - Rückkehr ins Hauptmenü
enum MenueStates{
MAIN, // Zustand Hauptmenü
SUBGREEN, // Submenü Grüne Led
SUBGREENON, // Einschalten der grünen Led -> automatisch zurück Submenü Grüne Led
SUBGREENOFF, // Ausschalten der grünen Led -> automatisch zurück Submenü Grüne Led
SUBRELAUSSEN, // Submenü Relay Aussen Licht
SUBRELAUSSENON, // Einschalten des Relay Licht aussen -> automatisch zurück Submenü Schalter Aussenlicht
SUBRELAUSSENOFF, // Ausschalten des Relay Licht aussen -> automatisch zurück Submenü Schalter Aussenlicht
SUBSERVO, // Submenü Servo
SUBSERVOTONE // Auslösen des Tones -> automatisch zurück zu SUBSERVO
};
// Pinbelegung
const int clkPin = 2; // CLK Anschluss des Encoders
const int dtPin = 3; // DT Anschluss des Encoders
const int swPin = 4; // SW Anschluss des Encoders
const int GreenLedPin = 5; // Grüne Led
const int RelayAussenPin = 6; // Rote Led
const int servoPin = 8; // Servo
int state = MAIN; // Startzustand der State Machine
// Instanziieren der verschiedenen Menüobjekte
RotMenue HauptMenue(clkPin,dtPin, swPin, "Hauptmen\365 ");
RotMenue GreenLedMenue(clkPin,dtPin, swPin, "Control Green");
RotMenue RelayAussenMenue(clkPin,dtPin, swPin, "Relay Aussen Licht");
RotMenue ServoMenue(clkPin,dtPin, swPin, "Control Servo");
void setup() {
Serial.begin(115200);
// lcd vorbereiten
lcd.init();
lcd.backlight();
lcd.clear();
// Startausgabe
lcd.setCursor(0,0);
lcd.print(" Projekt X 2022");
lcd.setCursor(0,2);
lcd.print(" Menu start...");
delay(1000);
pinMode(GreenLedPin, OUTPUT);
pinMode(RelayAussenPin, OUTPUT);
// Mit true oder false kann im Folgenden für alle Menüs
// das Verhalten "endlos durchwählen" oder "Anschlag links/rechts"
// gewählt werden; Default wäre "true" also endloses Durchwählen
boolean Revolve = true;
HauptMenue.SetRevolving(Revolve);
// Hier werden die Einträge des "Hauptmenüs" eingegeben
// Der State neben der Bezeichnung legt fest, welcher Zustand
// vom Menü mit HauptMenue.ActMenueState() zurückgegeben wird.
HauptMenue.Add("Control Green",SUBGREEN);
HauptMenue.Add("Aussen Beleuchtung",SUBRELAUSSEN);
HauptMenue.Add("Control Servo",SUBSERVO);
// Submenü für die Grüne Led
// Hier wird (wie auch bei den weiteren Submenüs)
// mit dem Eintrag "Back to..." und MAIN die Möglichkeit
// gegeben, wieder ins Hauptmenü zu kommen
// Praktisch könnte man aber von hier aus aber auch
// in weitere Submenüs wechseln.
// Die Möglichkeiten dazu werden im Hauptsketch verwaltet,
// für das Objekt sind Zusammenhänge wie Haupt-, Sub- oder Subsub-Menü
// transparent.
GreenLedMenue.SetRevolving(Revolve);
GreenLedMenue.Add("Green On",SUBGREENON);
GreenLedMenue.Add("Green Off",SUBGREENOFF);
GreenLedMenue.Add("Back to Main",MAIN);
// Submenü für die Aussen Licht Relay
RelayAussenMenue.SetRevolving(Revolve);
RelayAussenMenue.Add("Licht On",SUBRELAUSSENON);
RelayAussenMenue.Add("Licht Off",SUBRELAUSSENOFF);
RelayAussenMenue.Add("Back to Main",MAIN);
// Submenü für den Servo
ServoMenue.SetRevolving(Revolve);
ServoMenue.Add("Tone",SUBSERVOTONE);
ServoMenue.Add("Back to Main",MAIN);
// Startzustand sicherheitshalber hier nochmals gesetzt
state = MAIN;
}
void loop() {
StateMachine();
}
void StateMachine(){
switch(state){
case MAIN : ActMenue(HauptMenue);
break;
case SUBGREEN : ActMenue(GreenLedMenue);
break;
case SUBGREENON : digitalWrite(GreenLedPin,HIGH);
state = SUBGREEN;
break;
case SUBGREENOFF : digitalWrite(GreenLedPin,LOW);
state = SUBGREEN;
break;
case SUBRELAUSSEN : ActMenue(RelayAussenMenue);
break;
case SUBRELAUSSENON : digitalWrite(RelayAussenPin,HIGH);
state = SUBRELAUSSEN;
break;
case SUBRELAUSSENOFF : digitalWrite(RelayAussenPin,LOW);
state = SUBRELAUSSEN;
break;
case SUBSERVO : ActMenue(ServoMenue);
break;
case SUBSERVOTONE : tone(servoPin, 262, 250); // Freq 252, Dauer 250 msec
state = SUBSERVO;
break;
default : state = MAIN;
break;
}
}
// Diese Funktion erledigt die Abfrage, ob der Encoder
// gedreht und ob der Taster betätigt wurde und gibt dies
// bei positivem Ergebnis über Serial aus. Hier würde man ggf.
// Routinen zur Ausgabe eines Displays einfügen.
//
// Außerden wird bei Bestätigung durch den Taster (confirmed())
// der Zustand der State Machine auf den Wert gesetzt, der dem
// aktuell ausgewählten Menüpunkt zugewiesen wurde.
// Auf diese Weise gelangt die State Machine dann ggf. in einen
// neuen Zustand (siehe die enums oben)
//
void ActMenue(RotMenue &aMenue){
if (aMenue.StateHasChanged() || aMenue.Changed()) {
Serial.print(aMenue.ActMenueNo());
Serial.print("\t");
Serial.println(aMenue.ActMenueName());
WriteLcd(aMenue.ActMenueName(),aMenue.ActMenueTitle());
}
if (aMenue.confirmed()) {
Serial.println(" Confirmed Menue\t"+aMenue.ActMenueName());
state = aMenue.ActMenueState();
}
}
void WriteLcd(String MenueName, String MenueTitle){
lcd.clear();
lcd.setCursor(0,0);
lcd.print(MenueTitle);
lcd.setCursor(0,1);
lcd.print(MenueName);
}