Projekt Ballenwickler Steuerung macht Probleme

Hallo liebe Gemeinde,

ich bin neu hier und habe mich gleich mit meinem ersten großen Projekt so richtig übernommen und komme nicht mehr weiter. Vielleicht hat jemand von euch ja eine Idee wie ich weiter machen kann.

Ich fange mal von vorne an.

Ich habe einen Ballenwickler mit defekter Steuerung und da die vorher schon nicht das konnte was ich wollte habe ich mir gedacht das es ja eine super Idee wäre mir selber eine zu entwickeln und zu schreiben.

Der Ballenwickler hat 3 Drehzahlfühler die ich schon durch aktive ersetzt habe.

Ich muss mit meiner neuen Steuerung, über ein 16-fach Relais Board 7 Magnetventile und einen Elektromotor ansteuern.

Dazu habe ich 10 Taster verbaut.

Mit einem Rotary Encoder möchte ich das 2004 LCD Display steuern.

Das ganze sitzt auf einem Arduino Mega2560 mit einem Prototypen Board.

Verkabelt ist soweit alles und funktioniert auch soweit ich es bis jetzt prüfen kann.

Ich bin soweit das alle Taster schon mal die passenden Relais ansteuern.

Mein Problem besteht darin das alles auf das LCD zu bekommen, ein Menü zu erstellen was ich mit dem Rotary Decoder betätige kann und dann noch die ganzen zusätzlichen Funktionen zu schreiben die die Steuerung können soll.

Das wird jetzt leider viel Text, aber ich hoffe es hilft ein wenig.

Im Automatikmodus soll die Steuerung erstmal nur den Ballenheber heben und senken erlauben.

Wenn der Ballen dann auf dem Tisch liegt muss der Ballenheber abgesengt werden, da er sonst in den Tisch knallt. (Nicht das mir das schon mal passiert wäre hust).

Um das zu verhindern ist an dem Ballenheber ein Sensor verbaut der registrieren soll ob er im weg ist oder nicht.

Wenn er im weg ist soll es beim drücken der Start Taste eine Warnmeldung geben.

Wenn nicht dann soll er anfangen den Tisch schnell zu drehen (einstellbar) und die letzte Umdrehung soll er langsam drehen (das wird über einen der Drehzahlfühler abgefragt) und dabei das Messer spannen. Die Zeit für das Messer spannen muss leider auch einstellbar sein, da es dafür auch keine Sensoren gibt.

Wenn er mit dem drehen fertig ist soll der Tisch kippen (die Zeit dafür muss auch einstellbar sein das es dafür leider keinen Sensor gibt), bis das Messer die Folie greifen kann.

Dann soll das Messer entspannen. Wieder das leidige thema mit der verstellbaren Zeit.

Danach soll der tisch weiter kippen bis der letzte Sensor in der Familie anzeigt das der Ballen abgeworfen wurde.

Wenn der Ballen abgeworfen ist soll ein Zähler für die an diesem Tag gewickelten Ballen einen hochzählen und das ganze auch für einen gesamt Zähler dauerhaft abspeichern.

Als letztes muss der tisch noch runter gekippt werden.

Dann beginnt das ganze Spiel von vorne.

Ich habe um den Sketch übersichtlicher zu machen alle Taster in .h und .cpp ausgelagert.

Ich habe keine Ahnung ob ich nur Müll fabriziert habe oder ob man darauf aufbauen kann.

Und ich habe leider keine Ahnung wie ich weiter machen soll.

Ich bin für alle Ratschläge offen und bedanke mich im voraus das ihr euch dieses Monster von Text überhaupt durchgelesen habt.



#include <Wire.h>
#include <Bounce2.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SD.h>
#include <EEPROM.h>
#include "BHH.h"
#include "BHR.h"
#include "LWR.h"
#include "LWL.h"
#include "SWR.h"
#include "MS.h"
#include "ME.h"
#include "THK.h"
#include "TRK.h"
#include "START.h"
#include "KS.h"
#include "DF.h"
#include "BHS.h"



LiquidCrystal_I2C lcd(0x3F, 20, 4);


#define rotaryPin_A 2
#define rotaryPin_B 3
#define rotaryButtonPin 9



#define BHHR 25  // Relais Ballenheber hoch
#define BHRR 27  // Relais Ballenheber runter
#define LWRR 29  // Relais Langsam wickeln rechts rum
#define LWLR 31  // Relais Langsam wickeln links rum
#define MSR 39   // Relais Messer spannen
#define MER 37   // Relais Messer entspannen
#define THKR 33  // Relais Tisch hoch klappen
#define TRKR 35  // Relais Tisch runter klappen
#define HDER 23  // Relais fuer ERHÖHUNG des Hydraulikdrucks. Nur für LWR und LWL nicht bestromt
#define SBH A0   // Sensor Ballenheberarm
#define SDT A1   // Sensor Drehzahlerfassung Tisch
#define STK A2   // Sensor Tisch kippen


void setup() {

  // Init aller Taster

  bhh_init();
  bhr_init();
  lwr_init();
  lwl_init();
  swr_init();
  ms_init();
  me_init();
  thk_init();
  trk_init();
  start_init();

  // Init aller Relais ausgänge

  pinMode(BHHR, OUTPUT);     //Setzt "Ballenheber heben" Relais als Output
  digitalWrite(BHHR, HIGH);  //Setzt "Ballenheber heben" Relais auf High
  pinMode(BHRR, OUTPUT);     //Setzt "Ballenheber runter" Relais als Output
  digitalWrite(BHRR, HIGH);  //Setzt "Ballenheber runter" Relais auf High
  pinMode(LWRR, OUTPUT);     //Setzt "langsam wickeln rechts rum" Relais als Output
  digitalWrite(LWRR, HIGH);  //Setzt "langsam wickeln rechts rum" Relais auf High
  pinMode(LWLR, OUTPUT);     //Setzt "langsam wickeln links rum" Relais als Output
  digitalWrite(LWLR, HIGH);  //Setzt "langsam wickeln links rum" Relas auf High
  pinMode(MSR, OUTPUT);      //Setzt "Messer spannen" Relais als Output
  digitalWrite(MSR, HIGH);   //Setzt "Messer spannen" Relais auf High
  pinMode(MER, OUTPUT);      //Setzt "Messer entspannen" Relais als Output
  digitalWrite(MER, HIGH);   //Setzt "Messer entspannen" Relais auf High
  pinMode(THKR, OUTPUT);     //Setzt "Tisch hoch kippen" Relais als Output
  digitalWrite(THKR, HIGH);  //Setzt "Tisch hoch kippen" Relais auf High
  pinMode(TRKR, OUTPUT);     //Setzt "Tisch runter kippen" Relais als Output
  digitalWrite(TRKR, HIGH);  //Setzt "Tisch runter kippen" Relais auf High
  pinMode(HDER, OUTPUT);     //Setzt "Hydraulik druck erhöhen" Relais als Output
  digitalWrite(HDER, HIGH);  //Setzt "Hydraulik druck erhöhen" Relais auf High

  //Init LCD

  lcd.init();                 //LCD initialisieren
  lcd.backlight();            //LCD backlight anschalten
  lcd.setCursor(4, 0);        //Coursor setzen Zeile 1
  lcd.print("BW Steuerung");  //Ausgegebener Text Zeile 1
  lcd.setCursor(4, 1);        //Coursor setzen Zeile 2
  lcd.print("Version 1.00");  //Ausgegebener Text Zeile 2
  lcd.setCursor(4, 2);        //Coursor setzten Zeile 3
  lcd.print("");              //Ausgegebener Text Zeile 3
  lcd.setCursor(3, 3);        //Coursor setzten Zeile 4
  lcd.print("");              //Ausgegebener Text Zeile 4
  delay(5000);                //Anzeigedauer
  lcd.clear();                //LCD leeren


  Serial.begin(9600);
}

void Taster_Test() {

  if (BHH_Taster()) {
    Serial.println("BHH gedrueckt");
  }

  if (BHR_Taster()) {
    Serial.println("BHR gedrueckt");
  }

  if (LWR_Taster()) {
    Serial.println("LWR gedrueckt");
  }

  if (LWL_Taster()) {
    Serial.println("LWL gedrueckt");
  }

  if (SWR_Taster()) {
    Serial.println("SWR gedrueckt");
  }

  if (MS_Taster()) {
    Serial.println("MS gedrueckt");
  }

  if (ME_Taster()) {
    Serial.println("ME gedrueckt");
  }

  if (THK_Taster()) {
    Serial.println("THK gedrueckt");
  }

  if (TRK_Taster()) {
    Serial.println("TRK gedrueckt");
  }

  if (START_Taster()) {
    Serial.println("START gedrueckt");
  }

  delay(500);
}

void Manuell() {

  if (BHH_Taster()) {                 //Ballenheber hoch
    digitalWrite(BHHR, LOW);
    digitalWrite(HDER, LOW);
  } else {
    digitalWrite(BHHR, HIGH);
    digitalWrite(HDER, HIGH);
  }

  if (BHR_Taster()) {                 //Ballenheber runter
    digitalWrite(BHRR, LOW);
    digitalWrite(HDER, LOW);
  } else {
    digitalWrite(BHRR, HIGH);
    digitalWrite(HDER, HIGH);
  }

  if (LWR_Taster()) {                 //Langsam wickeln rechts
    digitalWrite(LWRR, LOW);
  } else if (SWR_Taster()) {          //Schnell wickeln rechts
    digitalWrite(LWRR, LOW);
    digitalWrite(HDER, LOW);
  } else {
    digitalWrite(LWRR, HIGH);
    digitalWrite(HDER, HIGH);
  }

  if (LWL_Taster()) {                 //Langsam wickeln links
    digitalWrite(LWLR, LOW);
  } else {
    digitalWrite(LWLR, HIGH);
  }

  if (MS_Taster()) {                  //Messer spannen
    digitalWrite(MSR, LOW);
  } else {
    digitalWrite(MSR, HIGH);
  }

  if (ME_Taster()) {                  //Messer entspannen
    digitalWrite(MER, LOW);
  } else {
    digitalWrite(MER, HIGH);
  }

  if (THK_Taster()) {                 //Tisch hoch kippen
    digitalWrite(THKR, LOW);
    digitalWrite(HDER, LOW);
  } else {
    digitalWrite(THKR, HIGH);
    digitalWrite(HDER, HIGH);
  }

  if (TRK_Taster()) {                 //Tisch runter kippen
    digitalWrite(TRKR, LOW);
    digitalWrite(HDER, LOW);
  } else {
    digitalWrite(TRKR, HIGH);
    digitalWrite(HDER, HIGH);
  }
}

void Automatik() {

  if (BHH_Taster()) {  //Wenn Ballenheber heben gedrückt wird, Ballenheber heben
    digitalWrite(BHHR, LOW);
    digitalWrite(HDER, LOW);
  } else {  //Wenn nicht dann Relais nicht ansteuern
    digitalWrite(BHHR, HIGH);
    digitalWrite(HDER, HIGH);
  }

  if (BHR_Taster()) {  //Wenn Ballenheber runter gedückt wird, Ballenheber runter
    digitalWrite(BHRR, LOW);
    digitalWrite(HDER, LOW);
  } else {  //Wenn nicht dann Relais nicht ansteuern
    digitalWrite(BHRR, HIGH);
    digitalWrite(HDER, HIGH);
  }
  if (START_Taster()) {           //Start löst das automatische wickeln aus
    if (analogRead(SBH) < 250) {  //Startet nur wenn der Ballenheber nicht im weg ist
      lcd.clear();
      lcd.setCursor(0, 1);
      lcd.print("Ballenheber senken");  //Wenn der Ballenheber im weg ist, Warnung ausgeben und dabei blinken
      delay(500);
      lcd.clear();
      delay(500);
    } else {  //Wenn der Ballenheber nicht im weg ist, Automatik weiter ausführen
      int Wicklungen_ist = Wicklungen_ist;
      int Wicklungen_soll = 20;
      lcd.clear();  //Zeigt die Wicklungen an
      lcd.backlight();
      lcd.setCursor(5, 1);
      lcd.print("Wicklungen");
      lcd.setCursor(7, 2);
      lcd.print(Wicklungen_ist);  //Aktuelle Anzahl an Wicklungen
      lcd.print(" / ");
      lcd.print(Wicklungen_soll);  //Zu wickelde Umdrehungen
      for (Wicklungen_ist = 0; Wicklungen_ist <= Wicklungen_soll; Wicklungen_ist++) {
        analogRead(SDT < 250);
        digitalWrite(LWRR, LOW);  //Ansteuerung Relais langsam wickel rechts
        digitalWrite(HDER, LOW);  //Ansteuerung Relais Hydraulikdruck erhöhen
      }
    }
  }
}

void loop() {
  Automatik();
  //  Taster_Test();
  //  Manuell();
}

Aua, du hast da übelsten Spagetticode produziert. Such' ein Tutorial zu Arrays und statemachine ...

Hallo Mats7588

Bilder und ein Blockschaltbild sagen immer mehr als 1000 Worte.

Einige Diagramme sagen mehr als Tausend Worte.

das ist nett, aber dann müsstest schon auch alles in ein ZIP packen und hier hochladen oder wie sollen wir da sonst sehen was du gemachst hast?

Und noch ein Tipp:

Verwende keine kryptischen Namen für die Variablen und Funktionen.
Variablen und Funktioen freuen sich über funktionale Namen.

Dann fang halt kleiner an. Kein "Projekt" ist von Anfang an fertig.
Ein schönes "Projekt" zum Anfangen wäre, rauszukriegen was die Drehzahlfühler fühlen.

Wenn das oder ähnliches kein Thema ist, wäre es sinnvoll, das zu erzählen und konkretere Fragen zu stellen.

Hier habe ich noch einen groben Schaltplan wie ich das geplant habe

TANCO Ballenwickler_Steckplatine.pdf (4,3 MB)

Ich bekomme die ZIP leider nicht hochgeladen. Angeblich wird das Format nicht unterstützt.

Es sind drei Näherungsschalter verbaut.
Der erste ist für den Ballenheber arm, der zweite misst die umdrehungen des Tisches beim wickeln über 2 Bleden die am tisch befestigt sind und der dritte stellt fest ob der Tisch so hoch gekippt wurde das ein fertig gewickelter Ballen abgeworfen wurde.

Ich habe mal weiter experimentiert und hänge jetzt an einem ganz speziellen Punkt der mir einfach nicht logisch erscheint, oder ich die Logik falsch verstehe.

Erstmal nur die automatik Funktion. Der rest ist gleich geblieben.

void Automatik() {
   static int Wicklungen_ist = 0; // Variable zur Verfolgung der Anzahl der durchgeführten Wicklungen
   const int Wicklungen_soll = 20;  // Anzahl der zu wickelnden Umdrehungen
   bool letzteUmdrehung = false; // Variable zur Überwachung der letzten Umdrehung
   bool startGedrueckt = false; // Variable zur Überwachung, ob der START-Taster gedrückt wurde
   bool messerGespannt = false; // Variable zur Überwachung, ob das Messer bereits gespannt wurde
   bool messerEntspannt = false; // Variable zur Überprüfung, ob das Messer bereits entspannt wurde
   unsigned long startZeitMS = 0; // Variable zur Speicherung des Startzeitpunkts für das Messer-Spannen
   unsigned long startZeitME = 0; //Variable zur Speicherung des Startzeitpunkts für das Messer-Entspanenn


  if (BHH_Taster()) {  //Wenn Ballenheber heben gedrückt wird, Ballenheber heben
    digitalWrite(BHHR, LOW);
    digitalWrite(HDER, LOW);
  } else {  //Wenn nicht dann Relais nicht ansteuern
    digitalWrite(BHHR, HIGH);
    digitalWrite(HDER, HIGH);
  }

  if (BHR_Taster()) {  //Wenn Ballenheber runter gedückt wird, Ballenheber runter
    digitalWrite(BHRR, LOW);
    digitalWrite(HDER, LOW);
  } else {  //Wenn nicht dann Relais nicht ansteuern
    digitalWrite(BHRR, HIGH);
    digitalWrite(HDER, HIGH);
  }
 
  if (START_Taster()) { // Überprüfe, ob der START-Taster gedrückt wurde
    if (analogRead(SBH) < 250) { // Überprüfe, ob der Ballenheber aus dem Weg ist (Wert über oder gleich 250)
     // Ballenheber ist im Weg, zeige eine entsprechende Meldung an
    lcd.clear();
    lcd.setCursor(0, 1);
    lcd.print("Ballenheber im Weg!");
    delay(2000); // Kurze Verzögerung, um die Meldung anzuzeigen
    startGedrueckt = false; // Setze startGedrueckt auf false
    } else {startGedrueckt = true; 
    }
  // Überprüfe, ob der START-Taster gedrückt wurde und startGedrueckt auf true ist
  if (startGedrueckt) {
     // Aktualisiere die Anzeige der Wicklungen
    lcd.clear();
    lcd.setCursor(5, 1);
    lcd.print("Wicklungen");
    lcd.setCursor(7, 2);
    lcd.print(Wicklungen_ist); // Anzeigen der aktuellen Anzahl der Wicklungen
    lcd.print(" / ");
    lcd.print(Wicklungen_soll); // Anzeigen der Zielanzahl der Wicklungen
  
    digitalWrite(LWRR, LOW); // Relais für langsames Wickeln nach rechts aktivieren
    digitalWrite(HDER, LOW); // Hydraulikdruck erhöhen aktivieren
    
    
    // Warte auf eine Umdrehung des Näherungsschalters
    while (Wicklungen_ist < Wicklungen_soll) {
      // Überwache den Wert des Näherungsschalters (analoger Wert)
      if (analogRead(SDT) < 250) {
        // Näherungsschalter aktiviert, eine Umdrehung wurde erkannt
        Wicklungen_ist++; // Inkrementiere die Anzahl der durchgeführten Wicklungen
        letzteUmdrehung = (Wicklungen_ist == Wicklungen_soll - 1); // Überprüfe, ob es die letzte Umdrehung ist

        // Aktualisiere die Anzeige der Wicklungen
        lcd.clear();
        lcd.setCursor(5, 1);
        lcd.print("Wicklungen");
        lcd.setCursor(7, 2);
        lcd.print(Wicklungen_ist); // Anzeigen der aktuellen Anzahl der Wicklungen
        lcd.print(" / ");
        lcd.print(Wicklungen_soll); // Anzeigen der Zielanzahl der Wicklungen
        Serial.print("Anzahl der Umdrehungen: ");
        Serial.println(Wicklungen_ist);



        // Wenn es die letzte Umdrehung ist, den Hydraulikdruck nicht erhöhen
        if (letzteUmdrehung) {
          digitalWrite(HDER, HIGH);
        }

        // Überprüfe, ob das Messer noch nicht gespannt wurde und eine bestimmte Anzahl von Umdrehungen erreicht wurde
        if (!messerGespannt && Wicklungen_ist >= 3 && !messerEntspannt) {
          // Spanne das Messer
          digitalWrite(MSR, LOW);
          startZeitMS = millis(); // Speichere den Startzeitpunkt für das Messer-Spannen
          Serial.println("Messer wird gespannt...");
        }
        // Überprüfe, ob die 5 Sekunden für das Messer-Spannen vergangen sind
        if (!messerGespannt && millis() - startZeitMS >= 5000) {
          // Schalte das Relais für das Messer-Spannen aus
          digitalWrite(MSR, HIGH);
           messerGespannt = true; // Setze die Variable messerGespannt auf true, um anzuzeigen, dass das Messer bereits gespannt wurde
           Serial.println("Messer ist gespannt.");
        }
        // Überprüfe, ob das Messer gespannt ist 
        if (messerGespannt && !messerEntspannt && millis() - startZeitMS <= 10000) {
           digitalWrite(MER, LOW); // Messer entspannen
           startZeitME = millis(); //Speichere den Startzeitpunkt für das Messer-Entspannen
           Serial.println("Messer wird entspannt...");
        }
        // Überprüfe, ob die 4 Sekunden für das Messer-Entspannen vergangen sind
        if (!messerEntspannt && millis() - startZeitME >= 4000) {
          digitalWrite(MER, HIGH); // Messer entspannt
           messerEntspannt = true; // Setze die Variable messerEntspannt auf true, um anzuzeigen, dass das Messer bereits entspannt wurde.
           Serial.println("Messer ist entspannt.");
        }  

        // Warte bis der Näherungsschalter deaktiviert ist (eine vollständige Umdrehung)
        while (analogRead(SDT) < 250) {
        }
      }
    }
    
    // Nachdem alle Umdrehungen abgeschlossen sind, beide Relais ausschalten
    digitalWrite(LWRR, HIGH);
    digitalWrite(HDER, HIGH);

    // Tisch hochfahren
    digitalWrite(THKR, LOW);
    digitalWrite(HDER, LOW);
    delay(5000); // Anpassen nach Bedarf, je nachdem wie weit der tisch hochgefahren ist
    digitalWrite(THKR, HIGH);
    digitalWrite(HDER, HIGH);    
    
    
    // Setze startGedrueckt auf false, um die Automatik-Funktion zu beenden
    startGedrueckt = false;
      }
    }
}

Jetzt zeigt das Debuging sofort nach der ersten umdrehung dass das Messer gespannt und auch entspannt wurde, obwohl es erst nach der dritten Umdrehung gespannt werden soll und erst wenn es gespannt ist soll es wieder entspannen. Hat ihr zufällig eine Idee woran das liegen könnte?

bau den Ablauf als Finite State Machine auf.
Weiters zeichne dir erst den Ablauf als State Diagram auf - dann setzt du das in der Programmierung um.

Ich frage mich wieso Du einen Arduino MEGA verwenden willst und nicht eine auf Arduino basierende SPS (PLC) wie Controllino oder Portenta.

Grüße Uwe

Ich möchte wenn dieser Prototyp läuft eine Platine entwickeln und bauen die dann alle Bauteile beinhaltet, da der Aufbau so wie er jetzt ist schon recht groß ist. Die Platine soll dann in das Gehäuse der alten Steuerung passen.
Dann muss ich nur noch den Deckel neu machen und fertsch.

Ok. Danke. Ich werde mal versuchen mich in das Thema einzulesen. :sweat_smile:

Ich hätte mich ja fast eingelesen...
Aber was sind das für libs?

Das hört sich sehr danach an, dass da noch was dazugehört...

da hat er was für die Ausgänge gebaut... --> PDF.

Ich habe versucht alles als ZIP zu teilen. Aber ich bekomme die einfach nicht hochgeladen. Ich bekomme immer den Fehler dass das Format nicht zulässig ist.

Und da ist nur der Standard Nonsens zum auslesen der Taster drin um den Sketch übersichtlicher zu halten. Auch wenn es das irgendwie nicht besser macht.

Also gut. Nach langem hin und her lesen hoffe ich das ich mit der FSM auf dem richtigen weg bin. Wie sieht das für euch soweit aus?

#define ENCODER_OPTIMIZE_INTERRUPTS
#include <Wire.h>
#include <Bounce2.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <EEPROM.h>
#include <Encoder.h>

// LCD_I2C Einstellungen
LiquidCrystal_I2C lcd(0x3F, 20, 4);

// Encoder Einstellungen
Encoder knobLeft(3, 2);
#define ENCODER_BUTTON_PIN 9

// Definiere Pins für Relais
#define BHHR 25  // Relais Ballenheber hoch
#define BHRR 27  // Relais Ballenheber runter
#define LWRR 29  // Relais Langsam wickeln rechts rum
#define LWLR 31  // Relais Langsam wickeln links rum
#define MSR 39   // Relais Messer spannen
#define MER 37   // Relais Messer entspannen
#define THKR 33  // Relais Tisch hoch klappen
#define TRKR 35  // Relais Tisch runter klappen
#define HDER 23  // Relais für Hydraulikdruck erhöhen

// Definiere Taster-Pins
#define BHH 26   // Taster Ballenheber heben
#define BHR 28   // Taster Ballenheber runter
#define LWR 30   // Taster langsam wickeln rechts
#define LWL 32   // Taster langsam wickeln links
#define SWR 34   // Taster schnell wickeln rechts
#define MS 36    // Taster Messer spannen
#define ME 38    // Taster Messer entspannen
#define THK 40   // Taster Tisch hoch kippen
#define TRK 42   // Taster Tisch runter kippen
#define START 44 // Taster Start

// Definiere Sensoren-Pins
#define SBH A0   // Sensor Ballenheber
#define SDT A1   // Sensor Tisch umdrehungen
#define STK A2   // Sensor Tisch kippen


// Definiere Zustände der Finite-State-Machine
enum State {
  HOME,
  MANUELL,
  AUTOMATIK,
  ZAEHLER,
  EINSTELLUNGEN,
  WICKLUNGEN,
  TK_z,
  MS_z,
  ME_z,
  MA_z,
  END
};

State currentState = HOME;

// Initialisierungen
int selectedMenuItem = 0;
int selectedEinstellungenItem = 0;
bool encoderStepFlag = false;       // Flag für jeden zweiten Schritt des Encoders
bool menuChanged = false;           // Flag für Änderung der Menüauswahl
static int Wicklungen_ist = 0;      // Variable zur Verfolgung der Anzahl der durchgeführten Wicklungen

// Variable, um den vorherigen Wert von Wicklungen_ist zu speichern
int previousWicklungen_ist = 0;

// Variablen, um den vorherigen Zustand des Näherungsschalters zu speichern
int previousSensorStateSDT = HIGH;  // Annahme: Näherungsschalter ist zu Beginn nicht aktiv
int previousSensorStateSTK = HIGH;  // Annahme: Näherungsschalter ist zu Beginn nicht aktiv
int previousSensorStateSBH = HIGH;  // Annahme: Näherungsschalter ist zu Beginn nicht aktiv

// Einstellungen die im EEPROM abgelegt werden
int t_THK = 3000;          // Zeit zum Tisch hochkippen bis das Messer Packen kann
int t_MS = 3000;           // Zeit zum Spannen des Messers
int t_ME = 2500;           // Zeit zum entspannen des Messers
int t_MA = 500;            // Zeit zum auslösen des Messers
int Wicklungen_soll = 20;  // Anzahl der zu wickelnden Umdrehungen

// Zähler die im EEPROM abgelegt werden
int Ballen_gesamt = 0;     // Anzahl gesamt gewickelter Ballen
int Ballen_heute = 0;      // Anzahl der Aam Tag geickelten Ballen


void setup() {
  // Initialisiere Pins
  pinMode(BHHR, OUTPUT);
  pinMode(BHRR, OUTPUT);
  pinMode(LWRR, OUTPUT);
  pinMode(LWLR, OUTPUT);
  pinMode(MSR, OUTPUT);
  pinMode(MER, OUTPUT);
  pinMode(THKR, OUTPUT);
  pinMode(TRKR, OUTPUT);
  pinMode(HDER, OUTPUT);
  pinMode(BHH, INPUT);
  pinMode(BHR, INPUT);
  pinMode(LWR, INPUT);
  pinMode(LWL, INPUT);
  pinMode(SWR, INPUT);
  pinMode(MS, INPUT);
  pinMode(ME, INPUT);
  pinMode(THK, INPUT);
  pinMode(TRK, INPUT);
  pinMode(START, INPUT);

  // Setze alle Relais zu Beginn auf HIGH
  digitalWrite(BHHR, HIGH);
  digitalWrite(BHRR, HIGH);
  digitalWrite(LWRR, HIGH);
  digitalWrite(LWLR, HIGH);
  digitalWrite(MSR, HIGH);
  digitalWrite(MER, HIGH);
  digitalWrite(THKR, HIGH);
  digitalWrite(TRKR, HIGH);
  digitalWrite(HDER, HIGH);

  // Initialisiere den Pin für den Taster des Rotary Encoders
  pinMode(ENCODER_BUTTON_PIN, INPUT_PULLUP);

  // Initialisiere Serielle Kommunikation
  Serial.begin(9600);

  // Initialisiere die LCD-Anzeige
  lcd.init();
  lcd.backlight();

  // Zeige Boot-Nachrichten auf dem LCD
  lcd.setCursor(3, 0);
  lcd.print("BW-Steuerung");
  lcd.setCursor(3, 1);
  lcd.print("Version 1.00");
  lcd.setCursor(3, 2);
  lcd.print("");
  lcd.setCursor(2, 3);
  lcd.print("");

  // Warte 5 Sekunden
  delay(3000);
  
  //EEPROM Debuging
  //saveToEEPROM();
  debugEEPROMValues();
  loadFromEEPROM();

  // Wechsel zum Zustand HOME
  currentState = HOME;
}

void loop() {
  switch (currentState) {
    case HOME:
      updateMenuDisplay();
      break;
    case MANUELL:
      checkManualControls();
      updateManualModeDisplay();
      readSensorSDT();
      readSensorSTK();
      saveToEEPROM();
      break;
    case AUTOMATIK:
      
      
      break;
    case ZAEHLER:
      loadFromEEPROM();
      updateZaehlerModeDisplay();
      break;
    case EINSTELLUNGEN:
      updateEinstellungenDisplay();
      handleEncoderButtonPressEinstellungen();
      break;
    case WICKLUNGEN:
      //updateWicklungenDisplay();
      //handleEncoderButtonPressWicklungen();
      break;
    case TK_z:
      //updateTK_zDisplay();
      //handleEncoderButtonPressTK_z();
      break;
    case MS_z:
      //updateMS_zDisplay();
      //handleEncoderButtonPressMS_z();
      break;
    case ME_z:
      //updateME_zDisplay();
      //handleEncoderButtonPressME_z();
      break;
    case MA_z:
      //updateMA_zDisplay();
      //handleEncoderButtonPressMA_z();
      break;
      default:
      break;
  }

  // Überprüfe den Rotary Encoder für Menünavigation
  int menuSelection = checkEncoder();
  if (menuSelection != 0) {
    selectedMenuItem += menuSelection;
    if (selectedMenuItem < 1) {
      selectedMenuItem = 4; // Zurück zum letzten Menüpunkt, wenn von 1 aus zurückgedreht wird
    } else if (selectedMenuItem > 4) {
      selectedMenuItem = 1; // Zurück zum ersten Menüpunkt, wenn von 4 aus weitergedreht wird
    }
    menuChanged = true; // Setze das Flag, dass sich das Menü geändert hat
  }
  // Überprüfe, ob der Taster des Rotary Encoders gedrückt wurde, um eine Auswahl zu bestätigen
  if (digitalRead(ENCODER_BUTTON_PIN) == LOW) {
    handleEncoderButtonPress();
  }
}

// Funktion zum Überprüfen des Rotary Encoders
int checkEncoder() {
  static long positionLeft  = -999; // Variable innerhalb der Funktion definieren
  long newLeft = knobLeft.read();
  
  // Überprüfe, ob sich der Encoder gedreht hat
  if (newLeft % 2 == 0) {
    if (newLeft != positionLeft) {
      if (newLeft > positionLeft) {
        // Der Encoder wurde nach rechts gedreht
        positionLeft = newLeft;
        return 1; // Rückgabe für rechte Drehung
      } else {
        // Der Encoder wurde nach links gedreht
        positionLeft = newLeft;
        return -1; // Rückgabe für linke Drehung
      }
    }
  } 
  // Rückgabe, wenn der Encoder nicht gedreht wurde
  return 0;
}

// Behandle den Tastendruck des Rotary Encoders zur Bestätigung von Menüauswahlen
void handleEncoderButtonPress() {
  // Abhängig von der ausgewählten Menüoption handeln
  switch (selectedMenuItem) {
    case 1:
      currentState = AUTOMATIK;
      break;
    case 2:
      currentState = MANUELL;
      break;
    case 3:
      currentState = ZAEHLER;
      break;
    case 4:
      currentState = EINSTELLUNGEN;
      break;
    default:
      break;      
  }

  // Setze das Flag, dass sich das Menü geändert hat
  menuChanged = true;
}

// Funktion zum Aktualisieren der Menüanzeige auf dem LCD
void updateMenuDisplay() {
  if (menuChanged) {
  lcd.clear();
  lcd.setCursor(0, 0);
  if (selectedMenuItem == 1) {
    lcd.print("-> Automatik");
  } else {
    lcd.print("   Automatik");
  }
  lcd.setCursor(0, 1);
  if (selectedMenuItem == 2) {
    lcd.print("-> Manuell");
  } else {
    lcd.print("   Manuell");
  }
  lcd.setCursor(0, 2);
  if (selectedMenuItem == 3) {
    lcd.print("-> Zaehler");
  } else {
    lcd.print("   Zaehler");
  }
  lcd.setCursor(0, 3);
  if (selectedMenuItem == 4) {
    lcd.print("-> Einstellungen");
  } else {
    lcd.print("   Einstellungen");
  }
  menuChanged = false; // Setze das Flag zurück, da das Menü aktualisiert wurde
  }
}

// Funktion um die Taster im manuellen Zustand zu überwachen
void checkManualControls() {
  // Überprüfe den Zustand der manuellen Steuerungstasten
  bool bhh_pressed = digitalRead(BHH) == LOW;
  bool bhr_pressed = digitalRead(BHR) == LOW;
  bool lwr_pressed = digitalRead(LWR) == LOW;
  bool lwl_pressed = digitalRead(LWL) == LOW;
  bool swr_pressed = digitalRead(SWR) == LOW;
  bool ms_pressed = digitalRead(MS) == LOW;
  bool me_pressed = digitalRead(ME) == LOW;
  bool thk_pressed = digitalRead(THK) == LOW;
  bool trk_pressed = digitalRead(TRK) == LOW;

  // Schalte die Relais entsprechend der gedrückten Tasten
  digitalWrite(BHHR, bhh_pressed ? HIGH : LOW);
  digitalWrite(BHRR, bhr_pressed ? HIGH : LOW);
  digitalWrite(LWRR, lwr_pressed ? HIGH : LOW);
  digitalWrite(LWRR, swr_pressed ? HIGH : LOW);
  digitalWrite(LWLR, lwl_pressed ? HIGH : LOW);
  digitalWrite(MSR, ms_pressed ? HIGH : LOW);
  digitalWrite(MER, me_pressed ? HIGH : LOW);
  digitalWrite(THKR, thk_pressed ? HIGH : LOW);
  digitalWrite(TRKR, trk_pressed ? HIGH : LOW);

  // Zusätzliche Logik für spezielle Bedingungen der Relaissteuerung
  digitalWrite(LWRR, swr_pressed ? HIGH : LOW);
  // Steuere das Relais HDER nur bei Betätigung von BHH
  if (bhh_pressed && bhr_pressed && swr_pressed && thk_pressed && trk_pressed) {
    digitalWrite(HDER, HIGH);
  } else {
    digitalWrite(HDER, LOW);
  }
}

// Funktion zum aktualisieren des LCD im manuellen Modus
void updateManualModeDisplay() {  
  // Überprüfe, ob sich der Wert von Wicklungen_ist geändert hat
  if (Wicklungen_ist != previousWicklungen_ist || menuChanged) {
  // Speichere den aktuellen Wert von Wicklungen_ist für den nächsten Vergleich
  previousWicklungen_ist = Wicklungen_ist;    
 
  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.print("MANUELLER MODUS");
  lcd.setCursor(5, 1);
  lcd.print("Wicklungen");
  lcd.setCursor(7, 2);
  lcd.print(Wicklungen_ist);
  lcd.print(" / ");
  lcd.print(Wicklungen_soll);

  // Überprüfe, ob die Ist-Wicklungszahl mit der Soll-Wicklungszahl übereinstimmt
  if (Wicklungen_ist + 1 == Wicklungen_soll) {
  // Setze die Ist-Wicklungszahl zurück auf 0
  Wicklungen_ist = 0;
  }

  menuChanged = false; // Setze das Menüänderungsflag zurück
  }
}

// Funktion zum auslesen der Tischumdrehungen
void readSensorSDT() {
  // Lese den aktuellen Zustand des Näherungsschalters
  int currentSensorStateSDT = analogRead(SDT) < 250 ? LOW : HIGH;

  // Überprüfe, ob sich der Zustand des Näherungsschalters geändert hat
  if (currentSensorStateSDT == LOW && previousSensorStateSDT == HIGH) {
    // Näherungsschalter ist aktiv und war zuvor nicht aktiv, eine Umdrehung wurde erkannt
    Wicklungen_ist++; // Inkrementiere die Anzahl der durchgeführten Wicklungen
  }

  // Aktualisiere den vorherigen Zustand des Näherungsschalters für die nächste Iteration
  previousSensorStateSDT = currentSensorStateSDT;
}

// Funktion zum auslesen des Kippsensors
void readSensorSTK() {
  // Lese den aktuellen Zustand des Näherungsschalters
  int currentSensorStateSTK = analogRead(STK) < 250 ? LOW : HIGH;

  // Überprüfe, ob sich der Zustand des Näherungsschalters geändert hat
  if (currentSensorStateSTK == LOW && previousSensorStateSTK == HIGH) {
    // Näherungsschalter ist aktiv und war zuvor nicht aktiv, ein Ballen wurde abgeworfen
     Ballen_heute++; //Inkrementiere die Anzahl der gewickelten Ballen
     Ballen_gesamt++; //Inkrementiere die Anzahl der gewickelten Ballen
  }

  // Aktualisiere den vorherigen Zustand des Näherungsschalters für die nächste Iteration
  previousSensorStateSTK = currentSensorStateSTK;

}

// Funktion zum Laden der Werte aus dem EEPROM
void loadFromEEPROM() {
  EEPROM.get(0, Ballen_heute);
  EEPROM.get(sizeof(Ballen_heute), Ballen_gesamt);
  EEPROM.get(sizeof(Ballen_heute) + sizeof(Ballen_gesamt), t_THK);
  EEPROM.get(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK), t_MS);
  EEPROM.get(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK) + sizeof(t_MS), t_ME);
  EEPROM.get(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK) + sizeof(t_MS) + sizeof(t_ME), t_MA);
  EEPROM.get(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK) + sizeof(t_MS) + sizeof(t_ME) + sizeof(t_MA), Wicklungen_soll);
}

// Funktion zum Speichern der Werte im EEPROM
void saveToEEPROM() {
  if(Ballen_gesamt != Ballen_gesamt) {
  EEPROM.put(0, Ballen_heute);
  EEPROM.put(sizeof(Ballen_heute), Ballen_gesamt);
  EEPROM.put(sizeof(Ballen_heute) + sizeof(Ballen_gesamt), t_THK);
  EEPROM.put(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK), t_MS);
  EEPROM.put(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK) + sizeof(t_MS), t_ME);
  EEPROM.put(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK) + sizeof(t_MS) + sizeof(t_ME), t_MA);
  EEPROM.put(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK) + sizeof(t_MS) + sizeof(t_ME) + sizeof(t_MA), Wicklungen_soll);

  Serial.println("Saving to EEPROM:");
  Serial.print("Ballen heute: ");
  Serial.println(Ballen_heute);
  Serial.print("Ballen gesamt: ");
  Serial.println(Ballen_gesamt);
  Serial.print("T THK: ");
  Serial.println(t_THK);
  Serial.print("T MS: ");
  Serial.println(t_MS);
  Serial.print("T ME: ");
  Serial.println(t_ME);
  Serial.print("T MA: ");
  Serial.println(t_MA);
  Serial.print("Wicklungen soll: ");
  Serial.println(Wicklungen_soll);

  }
}

// Debuging der gespeicherten werte im EEPROM
void debugEEPROMValues() {
  int debug_Ballen_heute;
  int debug_Ballen_gesamt;
  int debug_t_THK;
  int debug_t_MS;
  int debug_t_ME;
  int debug_t_MA;
  int debug_Wicklungen_soll;
  
  EEPROM.get(0, debug_Ballen_heute);
  EEPROM.get(sizeof(Ballen_heute), debug_Ballen_gesamt);
  EEPROM.get(sizeof(Ballen_heute) + sizeof(Ballen_gesamt), debug_t_THK);
  EEPROM.get(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK), debug_t_MS);
  EEPROM.get(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK) + sizeof(t_MS), debug_t_ME);
  EEPROM.get(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK) + sizeof(t_MS) + sizeof(t_ME), debug_t_MA);
  EEPROM.get(sizeof(Ballen_heute) + sizeof(Ballen_gesamt) + sizeof(t_THK) + sizeof(t_MS) + sizeof(t_ME) + sizeof(t_MA), debug_Wicklungen_soll);
  
  Serial.println("Debugging EEPROM Values:");
  Serial.print("Ballen_heute: ");
  Serial.println(debug_Ballen_heute);
  Serial.print("Ballen_gesamt: ");
  Serial.println(debug_Ballen_gesamt);
  Serial.print("t_THK: ");
  Serial.println(debug_t_THK);
  Serial.print("t_MS: ");
  Serial.println(debug_t_MS);
  Serial.print("t_ME: ");
  Serial.println(debug_t_ME);
  Serial.print("t_MA: ");
  Serial.println(debug_t_MA);
  Serial.print("Wicklungen_soll: ");
  Serial.println(debug_Wicklungen_soll);
}

// Funktion zum aktualisieren des LCD im Einstellungs modus
void updateZaehlerModeDisplay() {
  if (menuChanged) {
    //Initalisieren des LCD
    lcd.clear();
    lcd.setCursor (0,0);
    lcd.print ("Ballen gesamt");
    lcd.setCursor (0,1);
    lcd.print (Ballen_gesamt);
    lcd.setCursor (0,2);
    lcd.print ("Tageszaehler");
    lcd.setCursor (0,3);
    lcd.print (Ballen_heute);
  }
  menuChanged = false;
  delay(1000);
  currentState = HOME;
}

// Funktion zum aktualisieren des LCD in den Einstellung
void updateEinstellungenDisplay() {
  if (menuChanged) {
    lcd.clear();

    // Array mit den Menüpunkten
    String menuItems[] = {"Wicklungen", "Kippzeit", "Messer spannen", "Messer entspannen", "Messer auslösen"};
    int numMenuItems = sizeof(menuItems) / sizeof(menuItems[0]);

    // Berechnen, welcher Bereich des Menüs auf dem Bildschirm angezeigt werden soll
    int startIndex = max(0, selectedEinstellungenItem - 2);
    int endIndex = min(numMenuItems - 1, startIndex + 3);

    // Zeige die Menüpunkte an
    for (int i = startIndex; i <= endIndex; i++) {
      lcd.setCursor(0, i - startIndex);
      if (i == selectedEinstellungenItem - 1) {
        lcd.print("-> ");
      } else {
        lcd.print("   ");
      }
      lcd.print(menuItems[i]);
    }

    menuChanged = false; // Setze das Flag zurück, da das Menü aktualisiert wurde
  }
}

void handleEncoderButtonPressEinstellungen() {
  switch (selectedEinstellungenItem) {
    case 1:
      currentState = WICKLUNGEN;
      break;
    case 2:
      currentState = TK_z;
      break;
    case 3:
      currentState = MS_z;
      break;
    case 4:
      currentState = ME_z;
      break;
    case 5:
      currentState = MA_z;
      break;
    default:
      break;
  }
  menuChanged = false;
}

// Funktionen für die Anzeige und Behandlung der Benutzereingaben für die Wicklungen
void updateWicklungenDisplay() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Wicklungen einstellen:");
  lcd.setCursor(0, 1);
  lcd.print("Wicklungen_ist: ");
  lcd.print(Wicklungen_ist);
  lcd.setCursor(0, 2);
  lcd.print("Wicklungen_soll: ");
  lcd.print(Wicklungen_soll);
}

void handleEncoderButtonPressWicklungen() {
  // Hier die Logik für die Behandlung der Benutzereingaben zum Einstellen der Wicklungen
}

// Funktionen für die Anzeige und Behandlung der Benutzereingaben für TK_z, MS_z, ME_z und MA_z
void updateTK_zDisplay() {
  // Hier die Logik für die Anzeige der Einstellungen für TK_z
}

void handleEncoderButtonPressTK_z() {
  // Hier die Logik für die Behandlung der Benutzereingaben für TK_z
}

void updateMS_zDisplay() {
  // Hier die Logik für die Anzeige der Einstellungen für MS_z
}

void handleEncoderButtonPressMS_z() {
  // Hier die Logik für die Behandlung der Benutzereingaben für MS_z
}

void updateME_zDisplay() {
  // Hier die Logik für die Anzeige der Einstellungen für ME_z
}

void handleEncoderButtonPressME_z() {
  // Hier die Logik für die Behandlung der Benutzereingaben für ME_z
}

void updateMA_zDisplay() {
  // Hier die Logik für die Anzeige der Einstellungen für MA_z
}

void handleEncoderButtonPressMA_z() {
  // Hier die Logik für die Behandlung der Benutzereingaben für MA_z
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.