#include <Arduino.h>
#include <EEPROM.h> // EEPROM Bibliothek
#include <OneButton.h> // OneButton Bibliothek
#include <Wire.h> // Library allows to communicate with I2C / TWiI devices.
#include <Adafruit_SSD1306.h> // Oled Bibliothek
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_I2CDevice.h> // I2CDevice Library only for Platform IO
#define SCREEN_WIDTH 128 // Display Anzeigebreite in Pixel
#define SCREEN_HEIGHT 64 // Display Anzeigehöhe in Pixel
#define SCREEN_ADDRESS 0x3C // Oled Display Adresse Festlegung
#define display_RESET -1 // Oled Display Reset uber Ardoino Reset
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, display_RESET);
// Pins festlegen-----------------------------------------------
// Oled Pins SCL = 22 SDA = 21
#define sensorleft 13 // Pin Sensor Links
#define sensorright 12 // Pin Sensor Rechts
#define sensorcilinder 25 // Pin Sensor Cilinder
#define ventilPin 32 // Pin Cilinder Valve
#define SSbutton 19 // Pin Start Stop
#define upPin 4 // Pin Plus Button
#define downPin 5 // Pin Minus Button
#define selectPin 2 // Pin Select Button
#define emergencyPin 15 // Pin Emergency Button
// Pins festlegen H-Brucke--------------------------------------
#define MOTOR_IN1 27 // Pin INA H-Bridge
#define MOTOR_IN2 26 // Pin INB H-Bridge
#define PWMPIN 14 // Pin PWM H-Bridge
// PWM-Eigenschaften und Instanzen-----------------------------
#define Frequency 40000
#define Resolutionbit 8
unsigned long acc_currentTime; // Variable aktuelle Acc-Zeit
unsigned long acc_prevTime = 0; // Variable Vorherige Acc-Zeit
const unsigned long acc_Interval = 10; // Variable zum steuern de Beschleunigung
int acc = 0; // Variable Acc-Wert
// Foerderband Schrittkette Festlegung und Instanzen-----------
enum { warten,
ein,
cilinderrechts,
zeitcilinderrechts,
rechts1,
rechts2,
haltrechts,
cilinderlinks,
zeitcilinderlinks,
links1,
links2,
haltlinks,
aus,
zyklusstoppen,
watchdogstoppen,
};
byte schritt = warten;
byte watchdog;
unsigned long zyklusSave = 0;
unsigned long zyklus = 0;
unsigned long maxzyklus;
// Oled Dunkel Festlegung und Instanzen------------------------
unsigned long dunkelzeit;
unsigned long dunkelzeitoff = 300000; // 5 Minutes
// Definition der Texte legt die Anzahl fest-------------------
const char* Vartext[]{
"Prog:",
"Cycles:",
"TimeLeft:",
"TimeRight:",
"TimeCil.:",
"TimeOut:",
"AccStart: ",
"AccTime: ",
};
// Anzahl berechnen--------------------------------------------
const byte maxAnz = sizeof(Vartext) / sizeof(Vartext[0]);
unsigned long mindata[maxAnz]{
0,
0,
0,
0,
0,
0,
0,
0,
};
unsigned long maxdata[maxAnz]{
2,
80000,
12000,
12000,
5000,
20000,
255,
10000,
};
uint32_t longstart;
byte Varindex;
byte Seite = 0;
bool eingabe; // Modus Eingabe der Werte
bool changed; // Display geändert neu schreiben
bool datachanged; // Daten wurden geändert -> auf Epprom
// Daten in Struct um sie auf EEprom zu speichern--------------
struct mydaten {
unsigned long VarData[maxAnz]; // Menu Daten
unsigned long zyklus; // Zyklen Daten
} daten;
// Instanzen One Button----------------------------------------
OneButton Btnsel(selectPin, true);
OneButton Btnup(upPin, true);
OneButton Btndown(downPin, true);
// Instanzen StartStop Button-----------------------------------
byte SSbuttonState = 0;
byte lastSSbuttonState = HIGH;
byte SSbuttonCounter = 0;
bool SSFlag = false;
void StartStopButton();
void selClick();
void selDblClick();
void selResetPress();
void plusClick();
void minusClick();
void plusDurPress();
void minusDurPress();
void LongStart();
void click(int inc);
void longclick(int richtung);
void checkminmax();
void saveEEprom();
void ScreenNavigation();
void ScreenSaver();
void AnzeigeEingabe();
void EmergencyInfo();
void WatchDogInfo();
void Anzeige(byte seite);
void Foerderband();
void anhalten();
void nachrechts1();
void nachrechts2();
void nachlinks1();
void nachlinks2();
//-----------------------------------------------------------------
// StartStop Button Auswerten--------------------------------------
//-----------------------------------------------------------------
void StartStopButton() {
SSbuttonState = digitalRead(SSbutton);
if (lastSSbuttonState != SSbuttonState) {
lastSSbuttonState = SSbuttonState;
if (SSbuttonState == HIGH) {
SSbuttonCounter++;
if (SSbuttonCounter == 1) {
SSFlag = true;
}
}
}
}
//-----------------------------------------------------------------
// One Button Ereignisse Auswerten---------------------------------
//-----------------------------------------------------------------
void selClick() {
changed = true;
if (eingabe) { // Variable wechseln
Varindex++;
if (Varindex >= maxAnz) Varindex = 0;
} else { // Seite wechseln
Seite++;
if (Seite >= 5) Seite = 0;
}
watchdog = 0;
}
//-----------------------------------------------------------------
// Void SelDblClick------------------------------------------------
//-----------------------------------------------------------------
void selDblClick() {
if (eingabe) saveEEprom(); // Eingabe ist beendet
eingabe = !eingabe; // Toggle Mode
changed = true;
#ifdef debug
for (byte i = 0; i < maxAnz; i++)
#endif
}
//-----------------------------------------------------------------
// Void Reset Zyklen-----------------------------------------------
//-----------------------------------------------------------------
void selResetPress() {
if (Seite == 2) {
changed = true;
daten.zyklus = 0;
saveEEprom(); // Zyklen auf 0 stellen "Reset" in Epromm schreiben
Seite = 1;
}
}
//-----------------------------------------------------------------
// Voids Buttons---------------------------------------------------
//-----------------------------------------------------------------
void plusClick() {
dunkelzeit = millis();
if (Varindex == 0 || Varindex == 6) {
click(1);
}
if (Varindex == 1 || Varindex == 2 || Varindex == 3 || Varindex == 4 || Varindex == 5 || Varindex == 7) {
click(500);
}
}
//----------------------------------
void minusClick() {
dunkelzeit = millis();
if (Varindex == 0 || Varindex == 6) {
click(-1);
}
if (Varindex == 1 || Varindex == 2 || Varindex == 3 || Varindex == 4 || Varindex == 5 || Varindex == 7) {
click(-500);
}
}
//----------------------------------
void plusDurPress() {
if (Varindex == 0 || Varindex == 6) {
longclick(1);
}
if (Varindex == 1 || Varindex == 2 || Varindex == 3 || Varindex == 4 || Varindex == 5 || Varindex == 7) {
longclick(-500);
}
}
//----------------------------------
void minusDurPress() {
if (Varindex == 0 || Varindex == 6) {
longclick(1);
}
if (Varindex == 1 || Varindex == 2 || Varindex == 3 || Varindex == 4 || Varindex == 5 || Varindex == 7) {
longclick(-500);
}
}
//----------------------------------
void LongStart() {
longstart = millis();
}
//----------------------------------
void click(int inc) {
if (eingabe) {
changed = true;
datachanged = true;
daten.VarData[Varindex] += inc;
checkminmax();
}
}
//----------------------------------
void longclick(int richtung) {
static uint32_t altzeit;
int inc = 10;
if (millis() - longstart > 4000) inc = 100;
if (millis() - longstart > 8000) inc = 500;
if (millis() - altzeit >= 100 && eingabe) {
altzeit = millis();
changed = true;
datachanged = true;
daten.VarData[Varindex] += inc * richtung;
checkminmax();
}
}
//----------------------------------------------------
// Void Checkminmax-----------------------------------
//----------------------------------------------------
void checkminmax() {
if (daten.VarData[Varindex] < mindata[Varindex]) {
daten.VarData[Varindex] = mindata[Varindex];
}
if (daten.VarData[Varindex] > maxdata[Varindex]) {
daten.VarData[Varindex] = maxdata[Varindex];
}
}
//------------------------------------------------------
// Void SaveEEprom--------------------------------------
//------------------------------------------------------
void saveEEprom() {
if (datachanged) {
datachanged = false;
#ifdef debug
Serial.println(F("Save in EEprom"));
#endif
EEPROM.put(0, daten);
}
EEPROM.commit();
}
//------------------------------------------------------
// Void ScreenNavigation--------------------------------
//------------------------------------------------------
void ScreenNavigation() {
if (eingabe) AnzeigeEingabe();
else
Anzeige(Seite);
}
//------------------------------------------------------
// Void ScreenSaver------------------------------------
//------------------------------------------------------
void ScreenSaver() {
if (watchdog == 1) {
WatchDogInfo();
} else {
if (millis() - dunkelzeit > dunkelzeitoff) {
display.clearDisplay();
Seite = 0;
}
if (!digitalRead(selectPin)) dunkelzeit = millis();
{
display.display();
}
}
}
//---------------------------------------------------
// Void AnzeigeEingabe-------------------------------
//---------------------------------------------------
void AnzeigeEingabe() { // Anzeige bei Eingabe
if (changed) {
changed = false;
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println(F("(CHANGE VALUE)"));
display.setTextSize(2);
display.setCursor(2, 20);
display.println(Vartext[Varindex]);
display.setTextSize(2);
display.setCursor(60, 42);
display.println(daten.VarData[Varindex]);
}
}
//---------------------------------------------------------
// Void EmergencyInfo--------------------------------------
//---------------------------------------------------------
void EmergencyInfo() {
while (digitalRead(emergencyPin)) {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(10, 0);
display.println(F("EMERGENCY"));
display.setTextSize(1);
display.setCursor(30, 25);
display.println(F("!!!!!!!!!"));
display.setTextSize(2);
display.setCursor(20, 40);
display.println(F("Active!"));
display.display();
dunkelzeit = millis();
if (!digitalRead(selectPin))
;
{
Seite = 0;
}
}
}
//--------------------------------------------------------
// Void WatchDogInfo--------------------------------------
//--------------------------------------------------------
void WatchDogInfo() {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(30, 0);
display.println(F("ANOMALY"));
display.setTextSize(1);
display.setCursor(40, 25);
display.println(F("TimeOut!"));
display.setTextSize(2);
display.setCursor(30, 40);
display.println(F("Active!"));
display.display();
dunkelzeit = millis();
if (!digitalRead(selectPin))
;
{
Seite = 0;
}
}
//------------------------------------------------------
// Void Anzeige-----------------------------------------
//------------------------------------------------------
void Anzeige(byte seite) { // Anzeige Seiten
//if (changed) { // Wenn sich werte geändert haben
changed = false;
display.clearDisplay();
if (seite == 0) { // Anzeige Liste der Werte
for (byte i = 0; i < maxAnz; i++) {
display.setTextSize(3);
display.setCursor(10, 20);
display.println(F(":MENU:"));
}
} else if (seite == 1) { // 1 Seite Menue: Ist/Soll Anzeige
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println(F("Cycle.Soll:"));
display.setCursor(70, 0);
display.print(daten.VarData[1]);
display.setTextSize(2);
display.setCursor(0, 20);
display.println(F("Cycle.Ist:"));
display.setTextSize(3);
display.setCursor(0, 40);
display.println(daten.zyklus);
}
else if (seite == 2) { // 2 Seite Menue: Reset Zyklen mit Select
display.clearDisplay();
display.setTextSize(2);
display.setCursor(30, 0);
display.println(F("Cycles"));
display.setTextSize(2);
display.setCursor(30, 20);
display.println(F("Reset!"));
display.setTextSize(1);
display.setCursor(10, 50);
display.println(F("Press Long -SELECT-"));
} else if (seite == 3) { // 3 Seite Info der Variablen
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
display.println(F(":::Info:::"));
display.setTextSize(1);
display.setCursor(0, 15);
display.println(F("....................."));
display.setCursor(0, 30);
display.print(Vartext[0]); // Program Info
display.setCursor(70, 30);
display.print(daten.VarData[0]);
display.setCursor(0, 40);
display.print(Vartext[1]); // Zyklen Info
display.setCursor(70, 40);
display.print(daten.VarData[1]);
display.setCursor(0, 50);
display.print(Vartext[2]); // Wartezeit Links Info
display.setCursor(70, 50);
display.print(daten.VarData[2]);
}
else if (seite == 4) { //4 Seite Info der Variablen
display.setCursor(0, 0);
display.print(Vartext[3]); // Wartezeit Retchs Info
display.setCursor(70, 0);
display.print(daten.VarData[3]);
display.setCursor(0, 10);
display.print(Vartext[4]); // Wartezeit Cilinder Info
display.setCursor(70, 10);
display.print(daten.VarData[4]);
display.setCursor(0, 20);
display.print(Vartext[5]); // WatchDogzeit Info
display.setCursor(70, 20);
display.print(daten.VarData[5]);
display.setCursor(0, 30);
display.print(Vartext[6]); // Motor Beschleinigungswert bei Anlauf
display.setCursor(70, 30);
display.print(daten.VarData[6]);
display.setCursor(0, 40);
display.print(Vartext[7]); // Motor Zeitverzogerung der Beschleunigung
display.setCursor(70, 40);
display.print(daten.VarData[7]);
display.display();
}
}
//-------------------------------------------------------
// Void Schritkette Foederband---------------------------
//-------------------------------------------------------
void Foerderband() {
static unsigned long waitingmillis;
static unsigned long watchdogmillis;
if (digitalRead(emergencyPin)) {
schritt = aus;
EmergencyInfo();
}
StartStopButton();
if ((SSFlag == true && SSbuttonCounter == 1)) {
schritt = aus;
SSFlag = false;
}
switch (schritt) {
// Case Warten
case warten: // Überwachung von Anlage Warten
Serial.println(F("Anlage Warten auf Start()"));
if ((SSbuttonCounter == 2)) {
maxzyklus = daten.VarData[1];
schritt = ein;
SSbuttonCounter = 0;
}
anhalten();
break;
// Case Ein
case ein: // Überwachung von Anlage An
Serial.println(F("Anlage Ein()"));
schritt = cilinderrechts;
break;
// Case Cilinderrechts
case cilinderrechts: // Überwachung von Cilinder Rechts wenn Programm 1 ausgewählt
Serial.println(F("CilinderRechts()"));
if (daten.VarData[0] == 1) {
digitalWrite(ventilPin, HIGH);
waitingmillis = millis();
schritt = zeitcilinderrechts;
} else {
waitingmillis = millis();
schritt = rechts1;
}
break;
// Case Zeitcilinderrechts
case zeitcilinderrechts: // Wartezeit Cilinder Rechts wenn Programm 1 ausgewählt
Serial.println(F("ZeitCilinderRechts()"));
if (millis() - waitingmillis > daten.VarData[4]) {
digitalWrite(ventilPin, LOW);
if (digitalRead(sensorcilinder)) {
schritt = rechts1;
watchdogmillis = millis();
}
}
break;
// Case Rechts1
case rechts1: // Überwachung von Ersten Rechts Anlauf
Serial.println(F("RechtsLauf1()"));
nachrechts1();
schritt = rechts2;
watchdogmillis = millis();
break;
// Case Rechts2
case rechts2: // Überwachung von Zweiten Rechts Anlauf
Serial.println(F("RechtsLauf2()"));
if ((millis() - waitingmillis) >= daten.VarData[7]) {
nachrechts2();
}
if (!digitalRead(sensorright)) {
schritt = haltrechts;
waitingmillis = millis();
}
if (millis() - watchdogmillis > daten.VarData[5]) {
schritt = watchdogstoppen;
}
break;
// Case Haltrechts
case haltrechts: // Überwachung von Haltrechts
Serial.println(F("HaltRechts()"));
anhalten();
if (millis() - waitingmillis > daten.VarData[3]) {
schritt = cilinderlinks;
waitingmillis = millis();
acc = daten.VarData[6]; // Setzt die Beschleunigung zum Wert der am Dispaly eingegeben
}
break;
// Case Cilinderlinks
case cilinderlinks: // Überwachung von Cilinder Links wenn Programm 2 ausgewählt
Serial.println(F("CilinderLinks()"));
if (daten.VarData[0] == 2) {
digitalWrite(ventilPin, HIGH);
waitingmillis = millis();
schritt = zeitcilinderlinks;
} else {
waitingmillis = millis();
schritt = links1;
}
break;
// Case Zeitcilinderlinks
case zeitcilinderlinks: // Wartezeit Cilinder Links wenn Programm 1 ausgewählt
Serial.println(F("ZeitCilinderLinks()"));
if (millis() - waitingmillis > daten.VarData[4]) {
digitalWrite(ventilPin, LOW);
if (digitalRead(sensorcilinder)) {
schritt = links1;
watchdogmillis = millis();
}
}
break;
// Case Links1
case links1: // Überwachung von Ersten Links Anlauf
Serial.println(F("LinksLauf1()"));
nachlinks1();
schritt = links2;
watchdogmillis = millis();
break;
//Case Links2
case links2: // Überwachung von Zweiten Links Anlauf
Serial.println(F("LinksLauf2()"));
if ((millis() - waitingmillis) >= daten.VarData[7]) {
nachlinks2();
}
if (!digitalRead(sensorleft)) {
schritt = haltlinks;
waitingmillis = millis();
}
if (millis() - watchdogmillis > daten.VarData[5]) {
schritt = watchdogstoppen;
}
break;
// Case Haltlinks
case haltlinks: // Überwachung von Haltlinks
Serial.println(F("HaltLinks()"));
anhalten();
{
acc = daten.VarData[6]; // Setzt die Beschleunigung zum Wert der am Dispaly eingegeben
if (millis() - waitingmillis > daten.VarData[2]) {
if (daten.zyklus == maxzyklus) {
schritt = zyklusstoppen;
Seite = 2; // Ruft die 2 Seite im Menue auf wenn maximum Zyklen erreicht
changed = true;
} else {
daten.zyklus++;
zyklusSave++;
if (zyklusSave == 100) { // Nach 100 abgelaufenden Zyklen wird in die Eeprom geschrieben
datachanged = true; // Damit auch gespeichert wird
saveEEprom();
zyklusSave = 0;
}
changed = true; // Anzeige aktualisieren
schritt = cilinderrechts;
waitingmillis = millis();
}
}
}
break;
// Case Aus
case aus: // Anlage ausgeschaltet
Serial.println(F("Aus()"));
anhalten();
schritt = warten;
break;
// Case Zyklusstoppen
case zyklusstoppen: // Überwachung von Maximun Zyklen
Serial.println(F("ZyklusStoppen()"));
anhalten();
{
schritt = aus;
}
break;
// Case Watchdogstoppen
case watchdogstoppen: // Überwachung vom Watchdog
Serial.println(F("WatchDogStoppen()"));
anhalten();
{
schritt = aus;
watchdog = 1;
WatchDogInfo();
}
break;
}
}
//-------------------------------------------------------------
// Void Motoren Anhalten---------------------------------------
//-------------------------------------------------------------
void anhalten() {
digitalWrite(MOTOR_IN1, LOW);
digitalWrite(MOTOR_IN2, LOW);
ledcWrite(0, 0);
}
//-------------------------------------------------------------
// Void Motoren Rechts Erster Anlauf Kontrolliert--------------
//-------------------------------------------------------------
void nachrechts1() {
digitalWrite(MOTOR_IN1, HIGH);
digitalWrite(MOTOR_IN2, LOW);
ledcWrite(0, daten.VarData[6]);
}
//-------------------------------------------------------------
// Void Motoren Rechts mit Schwelle Maximum Geschwindigkeit----
//-------------------------------------------------------------
void nachrechts2() {
unsigned long acc_currentTime = millis();
if ((acc_currentTime - acc_prevTime >= acc_Interval)) {
digitalWrite(MOTOR_IN1, HIGH);
digitalWrite(MOTOR_IN2, LOW);
acc++;
if (acc <= 255) {
ledcWrite(0, acc);
}
acc_prevTime = acc_currentTime;
}
}
//--------------------------------------------------------------
// Void Motoren Links Erster Anlauf Kontrolliert----------------
//--------------------------------------------------------------
void nachlinks1() {
digitalWrite(MOTOR_IN1, LOW);
digitalWrite(MOTOR_IN2, HIGH);
ledcWrite(0, daten.VarData[6]);
}
//--------------------------------------------------------------
// Void Motoren Links mit Schwelle Maximum Geschwindigkeit------
//--------------------------------------------------------------
void nachlinks2() {
unsigned long acc_currentTime = millis();
if ((acc_currentTime - acc_prevTime >= acc_Interval)) {
digitalWrite(MOTOR_IN1, LOW);
digitalWrite(MOTOR_IN2, HIGH);
acc++;
if (acc <= 255) {
ledcWrite(0, acc);
}
acc_prevTime = acc_currentTime;
}
}
//-------------------------------------------------------------
// Void Setup--------------------------------------------------
//-------------------------------------------------------------
void setup() {
Serial.begin(115200);
delay(1000);
// Daten aus Eprom lesen
EEPROM.begin(2048);
EEPROM.get(0, daten);
for (byte i = 0; i < maxAnz; i++) {
checkminmax();
}
changed = true;
// Button Ereignisse festlegen
Btnsel.attachClick(selClick);
Btnsel.attachDoubleClick(selDblClick);
Btnsel.attachLongPressStop(selResetPress);
Btnup.attachClick(plusClick);
Btnup.attachDuringLongPress(plusDurPress);
Btnup.attachLongPressStart(LongStart);
Btndown.attachClick(minusClick);
Btndown.attachDuringLongPress(minusDurPress);
Btndown.attachLongPressStart(LongStart);
// Pin Festlegung
pinMode(SSbutton, INPUT_PULLUP);
pinMode(sensorleft, INPUT_PULLUP);
pinMode(sensorright, INPUT_PULLUP);
pinMode(sensorcilinder, INPUT_PULLUP);
pinMode(emergencyPin, INPUT_PULLUP);
pinMode(ventilPin, OUTPUT);
digitalWrite(ventilPin, LOW);
// Pin Festlegung H-Brucke
pinMode(MOTOR_IN1, OUTPUT);
digitalWrite(MOTOR_IN1, LOW);
pinMode(MOTOR_IN2, OUTPUT);
digitalWrite(MOTOR_IN2, LOW);
ledcAttachPin(PWMPIN, 0); // PWM-Pin einem Kanal zuweissen
ledcSetup(0, Frequency, Resolutionbit);
// Bildschirm Info
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(15, 20);
display.println(F("Welcome!"));
display.display();
delay(2000);
}
//----------------------------------------------------------------
// Void Loop------------------------------------------------------
//----------------------------------------------------------------
void loop() {
Foerderband();
ScreenNavigation();
ScreenSaver();
// One Button Voids-----------------------
Btnsel.tick(); // One Button Select Tick
Btnup.tick(); // One Button Up Tick
Btndown.tick(); // One Button Down Tick
}