// Deklarationen

// Timer DS3231 einrichten
#include "Wire.h"
#define DS3231_ADDRESSE 0x68
unsigned long Sekundenablauf05 = 0; // Zeitausgabe alle 1000ms 1 Sekunde einrichten
const unsigned long Pausezeit05 = 1000;

// LCD Display I2C 4 Zeilen je 20 Zeichen einrichten
#include <LiquidCrystal_I2C.h> // LCD Display
// Displayadresse ist 0x27 oder 0x3F
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// Baudrate fuer Serial Schnittstelle
const int baudSerial = 9600;
//-----------------------Taster01----------------------------------------
// const byte ist im Programm Constant und byte ist fuer Werte 0-255
const byte Taster01 = 15;           // Pin 15 wird Constant als Taster01 bezeichnet
byte Tasterstatus01 = 0;            // Zum Abfragen des Tatsenpins
byte Tastenmerker01 = 0;            // Zum Merken des aktuellen Tatsenstatus
unsigned long Sekundenablauf01 = 0; // Tastenabfrage von Taster02 300ms aussetzen
const unsigned long Pausezeit01 = 200;
//-----------------------Taster02---------------------------------------
const byte Taster02 = 16;           // Pin16 wird Constant als Taster02 bezeichnet
byte Tasterstatus02 = 0;
byte Tastenmerker02 = 0;
unsigned long Sekundenablauf02 = 0; // Tastenabfrage von Taster02 300ms aussetzen
const unsigned long Pausezeit02 = 200;
//-----------------------Analoger Eingang A0------------------------------
const byte ANALOG_PIN = A0; // Hier wird der Name fuer den Steuereingang festgelegt
int a0 = 0;      // Der Speicher fuer den Analogwert
int a0alt = 0;   // Der Speicher fuer den alten Analogwert

//-----------------------PWM Pins festlegen am Mega-----------------------
/* Timer und zugehörige Pinns:
   timer 0 (controls pin 13, 4);
   timer 1 (controls pin 12, 11);
   timer 2 (controls pin 10, 9);
   timer 3 (controls pin 5, 3, 2);
   timer 4 (controls pin 8, 7, 6);
   Wenn ich den Pin10 als PWM_PIN3 deklariere, dann bekomme ich Probleme bei der Tonausgabe
   auf Pin 17. Also wenn ich Pin 10 anstelle von Pin 9 als PWM Ausgang benutze, dann wird
   die Tonfrequenz von Pin17 liniar mit dem eingestellten PWM Signal verändert. Wenn ich
   wie jetzt im Programm für Pin10 den Pin9 verwende ist da kein Problem mehr. Der Pin10
   ist genauso wie Pin9 nicht beschalten. Was ja bei einem OUTPUT Pin kein Problem ist.
*/
int PWM_PIN2 = 13;  // PWM Ausgabepin 13 festlegen auf 490Hz, Timer0
int PWM_PIN1 = 11;  // PWM Ausgabepin 11 festlegen auf 31300Hz, Timer1
int PWM_PIN3 = 9;  // PWM Ausgabepin 9 festlegen auf 980Hz, Timer2
//-----------------------AusgangPIN31-------------------------------------
const byte Ausgang01 = 6;          // Pin 31 ist für das Relais01
byte Ausgangsstatus01 = 0;
unsigned long Sekundenablauf03 = 0; // Ausgang Schaltzeit auf 3000ms 3 Sekunden einrichten
const unsigned long Pausezeit03 = 3000;
//-----------------------AusgangPIN32-------------------------------------
const byte Ausgang02 = 7;          // Pin 32 ist für das Relais02
byte Ausgangsstatus02 = 0;
unsigned long Sekundenablauf04 = 0; // Ausgang Schaltzeit auf 1000ms 1 Sekunde einrichten
const unsigned long Pausezeit04 = 1000;
//-------------------------Tonausgabe PIN 17-----------------------------
const byte tonPin = 17;
const int frequenz = 1000;
unsigned long tonZeit = 100;
//=============================================================================================================
void setup() {

  //I2C für DS3231 aktivieren
  Wire.begin();
  // Wenn die I2C Leitung länger ist, kann man den Tackt für den I2C Bus langsammer machen!!
  Wire.setClock(32000);

  // Serial Schnittstelle starten
  Serial.begin(baudSerial);

  // Wenn die Zeit gestellt werden muß
  // aktuelle Zeit        sek min std wt tag monat jahr
  // einstellenDS3231zeit(00, 40, 17, 3, 01,  03,  20);

  // ----------PWM Tackt für Pin 11&12 auf 31300Hz ändern---------------
  TCCR1B = TCCR1B & 0b11111000 | 0x01;

  //-----------LCD Display Start----------------------------------------
  lcd.begin(20, 4);
  lcd.backlight();
  lcd.clear();
  lcd.setCursor (0, 3);
  lcd.print (F("PWM Wert "));
  //-----------Taster einrichten----------------------------------------
  pinMode(Taster01, INPUT_PULLUP); // Pin 11 fuer Taster01 wird intern auf plus gelegt. Mit GND ueber Taste aktivieren
  pinMode(Taster02, INPUT_PULLUP); // Pin 12 fuer Taster02
  //-----------Ausgang einrichten---------------------------------------
  pinMode(Ausgang01, OUTPUT);      // Pin 31 (Ausgang01) ist als Ausgang aktiviert
  pinMode(Ausgang02, OUTPUT);      // Pin 32 (Ausgang01) ist als Ausgang aktiviert
  //-----------Input und Output Pin für PWM bestimmen-------------------
  pinMode(ANALOG_PIN, INPUT);      // Eingang für Poti
  pinMode(PWM_PIN1, OUTPUT);
  pinMode(PWM_PIN2, OUTPUT);
  pinMode(PWM_PIN3, OUTPUT);
  //--------------Ton Ausgabepin einrichten----------------------------
  pinMode(tonPin, OUTPUT);
}
//=============================================================================================================
void loop() {
  //-----------Zeit ausgeben von DS3231-----------------------------------
  if (millis() - Sekundenablauf05 >= Pausezeit05) { // 300msec abgelaufen?
    zeigeZeit(); // Zeit ausgeben
    Sekundenablauf05 = millis();
    lcd.setCursor (11, 3);
    lcd.print (F("    "));
    lcd.setCursor (11, 3);
    lcd.print (a0);
  }
  //----------Analogen Eingang auslesen-----------------------------------
  a0 = analogRead (ANALOG_PIN);
  a0 = map(a0, 0, 1023, 25, 254);
  if ((a0 > a0alt + 2) || (a0 < a0alt - 2)) {
    //------Potiwert auf PWM Ausgang ausgeben-----------------------------
    analogWrite (PWM_PIN1, a0);                       // Analogwert Ausgabe an PWM Pin.11
    analogWrite (PWM_PIN2, a0);                       // Analogwert Ausgabe an PWM Pin.13
    analogWrite (PWM_PIN3, a0);                       // Analogwert Ausgabe an PWM Pin.9
  }
  //-----------Taster01 abfragen--------------------------------------------
  if (millis() - Sekundenablauf01 >= Pausezeit01) { // 300msec abgelaufen?
    Tasterstatus01 = digitalRead(Taster01);         // Pin von Taster01 abfragen
    if (Tasterstatus01 == LOW) {                    // Ist Taster01 gedrueckt?
      Tastenmerker01 = !Tastenmerker01;             // Merken dass Taster01 gedrueckt wurde
      lcd.setCursor (0, 1);
      lcd.print (F("Taste 01  "));
      lcd.print (Tastenmerker01);
      Sekundenablauf01 = millis();
      tone(tonPin, frequenz, tonZeit);
    }
  }

  //-----------Taster02 abfragen--------------------------------------------
  if (millis() - Sekundenablauf02 >= Pausezeit02) { // 300msec abgelaufen?
    Tasterstatus02 = digitalRead(Taster02);         // Pin von Taster02 abfragen
    if (Tasterstatus02 == LOW) {                    // Ist Taster02 gedrueckt?
      Tastenmerker02 = !Tastenmerker02;             // Merken dass Taster02 gedrueckt wurde
      lcd.setCursor (15, 1);
      lcd.print (F("02  "));
      lcd.print (Tastenmerker02);
      Sekundenablauf02 = millis();
      tone(tonPin, frequenz, tonZeit);
    }
  }

  //-------------Ausgang01 schalten-------------------------------------------
  if (millis() - Sekundenablauf03 >= Pausezeit03) { // 3000msec abgelaufen?
    Ausgangsstatus01 = ! Ausgangsstatus01;          // Status wechseln
    digitalWrite (Ausgang01, Ausgangsstatus01);     // Ausgang01 Relais umschalten
    lcd.setCursor (0, 2);
    lcd.print (F("Ausg. 01  "));
    lcd.print (Ausgangsstatus01);
    Sekundenablauf03 = millis();
  }

  //-------------Ausgang02 schalten-------------------------------------------
  if (millis() - Sekundenablauf04 >= Pausezeit04) { // 1000msec abgelaufen?
    Ausgangsstatus02 = ! Ausgangsstatus02;          // Status wechseln
    digitalWrite (Ausgang02, Ausgangsstatus02);     // Ausgang02 Relais umschalten
    lcd.setCursor (15, 2);
    lcd.print (F("02  "));
    lcd.print (Ausgangsstatus02);
    Sekundenablauf04 = millis();
  }


}
//=======================Loop Ende==============================================================================
//---------------Erweiterung für die DS3132---------------------------------------------------------------------
void einstellenDS3231zeit(byte sekunde, byte minute, byte stunde, byte wochentag, byte tag, byte monat, byte jahr)
{
  // Datum und Uhrzeit einstellen
  Wire.beginTransmission(DS3231_ADDRESSE);
  Wire.write(0);
  Wire.write(decToBcd(sekunde)); // Sekunden einstellen
  Wire.write(decToBcd(minute)); // Minuten einstellen
  Wire.write(decToBcd(stunde));
  Wire.write(decToBcd(wochentag)); // 1=Sonntag ... 7=Samstag
  Wire.write(decToBcd(tag));
  Wire.write(decToBcd(monat));
  Wire.write(decToBcd(jahr)); // 0...99
  Wire.endTransmission();
}
//-----------------------------------------------------------------------------------------------------------
void leseDS3231zeit(byte *sekunde, byte *minute, byte *stunde, byte *wochentag, byte *tag, byte *monat, byte *jahr)
{
  Wire.beginTransmission(DS3231_ADDRESSE);
  Wire.write(0); // DS3231 Register zu 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_ADDRESSE, 7); // 7 Byte Daten vom DS3231 holen
  *sekunde = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *stunde = bcdToDec(Wire.read() & 0x3f);
  *wochentag = bcdToDec(Wire.read());
  *tag = bcdToDec(Wire.read());
  *monat = bcdToDec(Wire.read());
  *jahr = bcdToDec(Wire.read());
}
//-----------------------------------------------------------------------------------------------------------
void zeigeZeit() {
  byte sekunde, minute, stunde, wochentag, tag, monat, jahr, minuteAlt;
  leseDS3231zeit(&sekunde, &minute, &stunde, &wochentag, &tag, &monat, &jahr);   // Daten vom DS3231 holen
  if ((minute > minuteAlt) || (minute == 0)) {
    switch (wochentag) {
      case 1:
        lcd.setCursor(0, 0);
        lcd.print(F("Mo "));
        break;
      case 2:
        lcd.setCursor(0, 0);
        lcd.print(F("Di "));
        break;
      case 3:
        lcd.setCursor(0, 0);
        lcd.print(F("Mi "));
        break;
      case 4:
        lcd.setCursor(0, 0);
        lcd.print(F("Do "));
        break;
      case 5:
        lcd.setCursor(0, 0);
        lcd.print(F("Fr "));
        break;
      case 6:
        lcd.setCursor(0, 0);
        lcd.print(F("Sa "));
        break;
      case 7:
        lcd.setCursor(0, 0);
        lcd.print(F("So "));
        break;
      default:
        break;
    }
    if (tag < 10) {
      lcd.print(F("0"));
    }
    lcd.print(tag); // ausgeben T.M.J H:M:S
    lcd.print(F("."));
    if (monat < 10) {
      lcd.print(F("0"));
    }
    lcd.print(monat);
    lcd.print(F("."));
    lcd.print(jahr);
    lcd.print(F(" um "));
    if (stunde < 10) {
      lcd.print(F("0"));
    }
    lcd.print(stunde, DEC); // byte in Dezimal zur Ausgabe
    lcd.print(F(":"));
    if (minute < 10) {
      lcd.print("0");
    }
    lcd.print(minute, DEC);
    minuteAlt = minute;
  }
}
byte decToBcd(byte val) {
  // Dezimal Zahl zu binary coded decimal (BCD) umwandeln
  return ((val / 10 * 16) + (val % 10));
}
byte bcdToDec(byte val) {
  // BCD (binary coded decimal) in Dezimal Zahl umwandeln
  return ((val / 16 * 10) + (val % 16));
}