/*

  Sonnenstandberechnung und Solartracking,

  jetzt mit Arduino-Motor-Shield Rev3.

  und Nextion 5.0-Zoll-touch-Display.

  Läuft nicht auf dem Arduino-UNO.

  Wg. erhöhtem Speicherbedarf ist ein Arduino Mega erforderlich.

  Positionsangaben für Ort: Rönkhausen.

  Version 2.4, M. Schulte, 09. April 2022.

  Achtung: Vin max. 7.5 Volt.

  Änderung: Servo map-Funktion entfällt.

*/

 

 

#include <TimeLib.h>

#include <DTutils.h>

#include <Time.h>

#include <Servo.h>

#include <Stepper.h>                               // Include the Stepper library

#include <Wire.h>

#include <DS3231.h>

 

#define RTC_I2C_ADDRESS 0x68                       // I2C Adresse des RTC DS3231

#define pwmA 3                                     // Give the motor control pins names:

#define pwmB 11

#define dirA 12

#define dirB 13

 

const int stepsPerRevolution = 200;                // Define number of steps per revolution

 

RTCDateTime dt;

DS3231 clock;

Servo servo2;                                      // Servomotor für Elevation

Stepper myStepper = Stepper(stepsPerRevolution, dirA, dirB);    // Initialize the stepper library on the motor shield

 

 

void setup() {

 

  Serial2.begin(9600);

  pinMode(pwmA, OUTPUT);                           // Set the PWM and brake pins so that the direction pins can be used to control the motor:

  pinMode(pwmB, OUTPUT);

  digitalWrite(pwmA, HIGH);

  digitalWrite(pwmB, HIGH);

  myStepper.setSpeed(80);                          // Set the motor speed (RPMs)

 

  pinMode(A2, INPUT);                              // Hall-Sensor

  pinMode(A15, INPUT);                             // PV-Panel

  pinMode(4, OUTPUT);                              // grüne LED, Anschluss an D4

  pinMode(6, OUTPUT);                              // blaue LED, Anschluss an D6

  pinMode(7, OUTPUT);                              // rote LED,  Anschluss an D7

 

  servo2.attach(5);

  servo2.write(3);                                 // Servo senkrechte Grundstellung

 

  clock.begin();                                   // Starte RTC Uhr

 

  // clock.setDateTime(2022, 03, 18, 9, 32, 30);    // Hier Datum und aktuelle Uhrzeit (MEZ) setzen, danach auskommentieren und sketch neu laden

 

  // Alle Daten des Displays leeren (refresh)

 

  Serial2.print("ref=page0.t0.txt");  // refresh Seite 0 Textfeld 0

  endNextionCommand();

  Serial2.print("ref=page0.t1.txt");  // refresh Seite 0 Textfeld 1

  endNextionCommand();

  Serial2.print("ref=page0.t2.txt");  // refresh Seite 0 Textfeld 2

  endNextionCommand();

  Serial2.print("ref=page0.t3.txt");  // refresh Seite 0 Textfeld 3

  endNextionCommand();

  Serial2.print("ref=page0.t4.txt");  // refresh Seite 0 Textfeld 4

  endNextionCommand();

 

  Serial2.print("ref=page1.t0.txt");  // refresh Seite 1 Textfeld 0

  endNextionCommand();

  Serial2.print("ref=page1.t1.txt");  // refresh Seite 1 Textfeld 1

  endNextionCommand();

  Serial2.print("ref=page1.t2.txt");  // refresh Seite 1 Textfeld 2

  endNextionCommand();

  Serial2.print("ref=page1.t3.txt");  // refresh Seite 1 Textfeld 3

  endNextionCommand();

  Serial2.print("ref=page1.t4.txt");  // refresh Seite 1 Textfeld 4

  endNextionCommand();

  Serial2.print("ref=page1.t5.txt");  // refresh Seite 1 Textfeld 5

  endNextionCommand();

  Serial2.print("ref=page1.t6.txt");  // refresh Seite 1 Textfeld 6

  endNextionCommand();

 

  Serial2.print("ref=page2.t0.txt");  // refresh Seite 2 Textfeld 0

  endNextionCommand();

  Serial2.print("ref=page2.t1.txt");  // refresh Seite 2 Textfeld 1

  endNextionCommand();

  Serial2.print("ref=page2.t2.txt");  // refresh Seite 2 Textfeld 2

  endNextionCommand();

  Serial2.print("ref=page2.t3.txt");  // refresh Seite 2 Textfeld 3

  endNextionCommand();

  Serial2.print("ref=page2.t4.txt");  // refresh Seite 2 Textfeld 4

  endNextionCommand();

  Serial2.print("ref=page2.t5.txt");  // refresh Seite 2 Textfeld 5

  endNextionCommand();

  Serial2.print("ref=page2.t6.txt");  // refresh Seite 2 Textfeld 6

  endNextionCommand();

 

  Serial2.print("ref=page3.t0.txt");  // refresh Seite 3 Textfeld 0

  endNextionCommand();

  Serial2.print("ref=page3.t1.txt");  // refresh Seite 3 Textfeld 1

  endNextionCommand();

  Serial2.print("ref=page3.t2.txt");  // refresh Seite 3 Textfeld 2

  endNextionCommand();

}

 

 

// Beginn der Schleife

 

void loop() {

 

  const int stepsV = 16;                           // Anzahl steps Vorwärtslauf

  const int stepsR = -16;                          // Anzahl steps Rückwärtslauf

  const int stepsSR = -100;                        // Anzahl steps schneller Rücklauf

 

  dt = clock.getDateTime();                        // Zeitwert holen von RTC Echtzeituhr

 

  String hour = clock.dateFormat("H", dt);

  String minute = clock.dateFormat("i", dt);

  String year = clock.dateFormat("z", dt);

  String second = clock.dateFormat("s", dt);

 

  int Jahr = (dt.year);

  int Monat = (dt.month);

  int Tag = (dt.day);

  float Stunde = hour.toInt();

  float Minute = minute.toInt();

  float Sekunde = second.toInt();

 

  int yearday = DayOfYear(Jahr, Monat, Tag);

 

  float Elevation;

  float elevation;

  float Aufgang;

  float Untergang;

  float Deklination;

  float Azimut;

  float Zeitgleichung;

  float Zeitdifferenz;

  float AufgangOrtszeit;

  float UntergangOrtszeit;

  float Tageslaenge;

  float Refraktion;

  float MEZ;                                                                               // Mitteleuropäische Zeit

  float MOZ;                                                                               // Mittlere Ortszeit

  float WOZ;                                                                               // Wahre Ortszeit

  float ZeitSeitMittag;

 

  const float pi = 3.14159265;

  const float kwert = pi / 180;

  const float latitude = 51.222191;

  const float longitude = 7.954169;

  const float B = latitude * kwert;                                                        // geogr. Breite in Radians

  const float h = -(50.0 / 60.0) * kwert;                                                  // Höhe des Sonnenmittelpunkts bei Aufgang

  const int Zeitzone = 1;                                                                  // Zeitzone Greenwich + 1 (z.B. Berlin)

 

  int Grenzwert;

  int sensorValue;                                                                         // Analoger Ist-Wert (Hall-Sensor)

  int azimutHall;                                                                          // Gradwert Ist-Azimutwert (Hall-Sensor)

  int i2;

 

  MEZ = Stunde + Minute / 60 + Sekunde / 3600;                                             // Mitteleuropäische Zeit

 

  Zeitgleichung = BerechneZeitgleichung (yearday);                                         // Aufruf der Funktion: BerechneZeitgleichung

  ZeitSeitMittag = MEZ + longitude / 15.0 - Zeitzone - 12 + Zeitgleichung;                 // Berechne ZeitSeitMittag

  Deklination = BerechneDeklination (yearday);                                             // Aufruf der Funktion: BerechneDeklination

  Zeitdifferenz = BerechneZeitdifferenz (h, pi, latitude, kwert, Deklination);             // Aufruf der Funktion: BerechneZeitdifferenz

  Azimut = SunAngles(Deklination, B, kwert, pi, ZeitSeitMittag, Elevation);                // Aufruf der Funktion: SunAngles

  Tageslaenge = BerechneTageslaenge (Zeitdifferenz, Zeitgleichung, longitude, Zeitzone, Aufgang, Untergang);   // Aufruf der Funktion: BerechneTageslaenge

 

  Elevation  = Elevation / kwert;

  Deklination = Deklination / kwert;

 

  int AziH = (int)azimutHall;

  int AziB = (int)Azimut;

 

  MOZ = MEZ - (-longitude / 15) - 1;                                                       // Berechne Mittlere Ortszeit aus MEZ

  WOZ = MOZ + Zeitgleichung;                                                               // Berechne Wahre Ortszeit

 

  int WOZdez = (int)WOZ;

  int WOZmin = (WOZ - WOZdez) * 60;

 

  int MOZdez = (int)MOZ;

  int MOZmin = (MOZ - MOZdez) * 60;

 

  int StdL = (int)Tageslaenge;

  int MinL = (int)((Tageslaenge - StdL) * 60);

 

  int StdA = (int)Aufgang;

  int MinA = (int)((Aufgang - StdA) * 60);

 

  int StdU = (int)Untergang;

  int MinU = (int)((Untergang - StdU) * 60);

 

  if (StdL >= 7 && StdL < 9) {

    Grenzwert = 135;

  };                                                          // Grenzwerte für Rücklaufposition

  if (StdL >= 9 && StdL < 10) {

    Grenzwert = 120;

  };                                                          // abhängig von der Tageslänge (nur Stunde)

  if (StdL >= 10 && StdL < 11) {

    Grenzwert = 104;

  };

  if (StdL >= 11 && StdL < 13) {

    Grenzwert = 90;

  };

  if (StdL >= 13 && StdL < 14) {

    Grenzwert = 75;

  };

  if (StdL >= 14 && StdL < 15) {

    Grenzwert = 60;

  };

  if (StdL >= 15 && StdL < 17) {

    Grenzwert = 45;

  };

 

  sensorValue = analogRead(A2);                              // Auslesen Hall-Sensor an Pin A2

 

  azimutHall = MotorenSteuerung (Azimut, Elevation, sensorValue, AziH, AziB, Grenzwert, stepsV, stepsR, stepsSR);  // Aufruf der Funktion: MotorenSteuerung

 

 

  // Für Anzeige Windrichtung, abhängig von der Position des Drehtellers

 

  const char* windrichtung[16] = {"Nord", "NNO", "NO", "ONO", "Ost", "OSO", "SO", "SSO", "Sued", "SSW", "SW", "WSW", "West", "WNW", "NW", "NNW"};

 

  int i1 = Windrichtung(azimutHall, Azimut, i2);             // Aufruf Funktion: Windrichtung

  String wr1 = windrichtung[i1];

  String wr2 = windrichtung[i2];

 

  // 5-Volt-Solarpanel

 

  const int analogPin = A15;

  float pvmod = analogRead(analogPin);

  float Volt = Solarspannung (pvmod);                        // Aufruf Funktion: Solarspannung

  float Prozent = Volt / 4.75 * 100;

 

  // für Anzeige: Stunden, Minuten, Deklination

 

  int Std = (int)Tageslaenge;

  int Min = (int)((Tageslaenge - Std) * 60);

 

 

  // Ausgabe auf Nextion-Display 5.0""

 

  // Seite 0: Home

 

  Serial2.print("page0.t0.txt=\"");

  Serial2.print("Nextion-Solartracker-Projekt");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page0.t0.txt");

  endNextionCommand();

 

  Serial2.print("page0.t1.txt=\"");

  Serial2.print("Version 2.4 vom 09.04.2022");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page0.t1.txt");

  endNextionCommand();

 

  Serial2.print("page0.t2.txt=\"");

  Serial2.print("Dr. Michael Schulte");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page0.t2.txt");

  endNextionCommand();

 

  Serial2.print("page0.t3.txt=\"");

  Serial2.print("http://wetterstation.mi-schu.de");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page0.t5.txt");

  endNextionCommand();

 

  Serial2.print("page0.t4.txt=\"");

  Serial2.print("E-Mail: wetter.roenkhausen@gmx.de");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page0.t4.txt");

  endNextionCommand();

 

  // Seite 1: Time

 

  Serial2.print("page1.t0.txt=\"");

  Serial2.print(clock.dateFormat("    d. M. Y              H:i:s", dt));

  Serial2.print(" MEZ");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page1.t0.txt");

  endNextionCommand();

 

  Serial2.print("page1.t1.txt=\"");

  if (WOZmin >= 0 && WOZmin < 10)  {

    Serial2.print("   Wahre Ortszeit:           " + String (WOZdez) + ":" + "0" + String (WOZmin) + " h");

  }

  else

  { Serial2.print("   Wahre Ortszeit:           " + String (WOZdez) + ":" + String (WOZmin) + " h");

  }

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page1.t1.txt");

  endNextionCommand();

 

  Serial2.print("page1.t2.txt=\"");

  if (MOZmin >= 0 && MOZmin < 10)  {

    Serial2.print("   Mittlere Ortszeit:         " + String (MOZdez) + ":" + "0" + String (MOZmin) + " h");

  }

  else

  { Serial2.print("   Mittlere Ortszeit:         " + String (MOZdez) + ":" + String (MOZmin) + " h");

  }

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page1.t2.txt");

  endNextionCommand();

 

  Serial2.print("page1.t3.txt=\"");

  Serial2.print("   Tag im Jahr:                 " + String(yearday));

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page0.t3.txt");

  endNextionCommand();

 

  Serial2.print("page1.t4.txt=\"");

  if (MinA >= 0 && MinA < 10)  {

    Serial2.print("   Sonnenaufgang:           " + String (StdA) + ":" + "0" + String (MinA) + " h");

  }

  else

  { Serial2.print("   Sonnenaufgang:           " + String (StdA) + ":" + String (MinA) + " h");

  }

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page1.t4.txt");

  endNextionCommand();

 

  Serial2.print("page1.t5.txt=\"");

  if (MinU >= 0 && MinU < 10)  {

    Serial2.println("   Sonnenuntergang:     " + String (StdU) + ":" + "0" + String (MinU) + " h");

  }

  else

  { Serial2.println("   Sonnenuntergang:     " + String (StdU) + ":" + String (MinU) + " h");

  }

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page1.t5.txt");

  endNextionCommand();

 

  Serial2.print("page1.t6.txt=\"");

  if (MinL >= 0 && MinL < 10)  {

    Serial2.print("   Tageslaenge:              " + String (StdL) + ":" + "0" + String (MinL) + " h");

  }

  else

  { Serial2.print("   Tageslaenge:              " + String (StdL) + ":" + String (MinL) + " h");

  }

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page1.t6.txt");

  endNextionCommand();

 

  // Seite 2: Data

 

  Serial2.print("page2.t0.txt=\"");

  Serial2.print(clock.dateFormat("    d. M. Y                H:i:s", dt));

  Serial2.print(" MEZ");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page2.t0.txt");

  endNextionCommand();

 

  Serial2.print("page2.t1.txt=\"");

  Serial2.print("    Azimut-Soll:                " + String(Azimut) + " Grd " + "(" + String(wr2) + ")");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page2.t1.txt");

  endNextionCommand();

 

  Serial2.print("page2.t2.txt=\"");

  Serial2.print("    Azimut-Ist:                  " + String(azimutHall) + ".00 Grd " + "(" + String(wr1) + ")");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page2.t2.txt");

  endNextionCommand();

 

  Serial2.print("page2.t3.txt=\"");

  Serial2.print("    Elevation:                      " + String(Elevation) + " Grd");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref = page2.t3.txt");

  endNextionCommand();

 

  Serial2.print("page2.t4.txt=\"");

  Serial2.print("    Deklination:                   " + String(Deklination) + " Grd");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page2.t4.txt");

  endNextionCommand();

 

  Serial2.print("page2.t5.txt=\"");

  Serial2.print("    Zeitgleichung:               " + String(Zeitgleichung * 60) + " min");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page2.t5.txt");

  endNextionCommand();

 

  Serial2.print("page2.t6.txt=\"");

  Serial2.print("    Solarspannung:     " + String(Volt) + " V " + "(" + String (int (Prozent)) + "% Vmax" + ")");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page2.t6.txt");

  endNextionCommand();

 

  // Seite 3: Sun

 

  Serial2.print("page3.t0.txt=\"");

  Serial2.print(" Azimut-Soll: " + String(Azimut) + " Grd");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref = page3.t5.txt");

  endNextionCommand();

 

  Serial2.print("page3.t1.txt=\"");

  Serial2.print(" Azimut-Ist:   " + String(azimutHall) + ".00 Grd");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page2.t2.txt");

  endNextionCommand();

 

  Serial2.print("page3.t2.txt=\"");

  Serial2.print(" Elevation:     " + String(Elevation) + " Grd");

  Serial2.write('"');

  endNextionCommand();

  Serial2.print("ref=page2.t5.txt");

  endNextionCommand();

}

 

 

void endNextionCommand()

{

  Serial2.write(0xff);

  Serial2.write(0xff);

  Serial2.write(0xff);

}

 

 

// Funktion: Windrichtung

 

int Windrichtung (float azimutHall, float Azimut, int &i2) {

  int i1;

  if (azimutHall >= 0 &&    azimutHall < 11)  {

    i1 = 0;

  }

  if (Azimut >= 0 &&    Azimut < 11)  {

    i2 = 0;

  }

  if (azimutHall >= 11 &&   azimutHall < 34)  {

    i1 = 1;

  }

  if (Azimut >= 11 &&   Azimut < 34)  {

    i2 = 1;

  }

  if (azimutHall >= 34 &&   azimutHall < 56)  {

    i1 = 2;

  }

  if (Azimut >= 34 &&   Azimut < 56)  {

    i2 = 2;

  }

  if (azimutHall >= 56 &&   azimutHall < 79)  {

    i1 = 3;

  }

  if (Azimut >= 56 &&   Azimut < 79)  {

    i2 = 3;

  }

  if (azimutHall >= 79 &&  azimutHall < 101)  {

    i1 = 4;

  }

  if (Azimut >= 79 &&  Azimut < 101)  {

    i2 = 4;

  }

  if (azimutHall >= 101 && azimutHall < 124)  {

    i1 = 5;

  }

  if (Azimut >= 101 && Azimut < 124)  {

    i2 = 5;

  }

  if (azimutHall >= 124 && azimutHall < 146)  {

    i1 = 6;

  }

  if (Azimut >= 124 && Azimut < 146)  {

    i2 = 6;

  }

  if (azimutHall >= 146 && azimutHall < 169)  {

    i1 = 7;

  }

  if (Azimut >= 146 && Azimut < 169)  {

    i2 = 7;

  }

  if (azimutHall >= 169 && azimutHall < 191)  {

    i1 = 8;

  }

  if (Azimut >= 169 && Azimut < 191)  {

    i2 = 8;

  }

  if (azimutHall >= 191 && azimutHall < 214)  {

    i1 = 9;

  }

  if (Azimut >= 191 && Azimut < 214)  {

    i2 = 9;

  }

  if (azimutHall >= 214 && azimutHall < 236)  {

    i1 = 10;

  }

  if (Azimut >= 214 && Azimut < 236)  {

    i2 = 10;

  }

  if (azimutHall >= 236 && azimutHall < 259)  {

    i1 = 11;

  }

  if (Azimut >= 236 && Azimut < 259)  {

    i2 = 11;

  }

  if (azimutHall >= 259 && azimutHall < 281)  {

    i1 = 12;

  }

  if (Azimut >= 259 && Azimut < 281)  {

    i2 = 12;

  }

  if (azimutHall >= 281 && azimutHall < 304)  {

    i1 = 13;

  }

  if (Azimut >= 281 && Azimut < 304)  {

    i2 = 13;

  }

  if (azimutHall >= 304 && azimutHall < 326)  {

    i1 = 14;

  }

  if (Azimut >= 304 && Azimut < 326)  {

    i2 = 14;

  }

  if (azimutHall >= 326 && azimutHall < 349)  {

    i1 = 15;

  }

  if (Azimut >= 326 && Azimut < 349)  {

    i2 = 15;

  }

  return i1;

}

 

 

// Funktion: SunAngles für die Berechnung von Azimut und Elevation

 

float SunAngles (float Deklination, float B, float kwert, float pi, float ZeitSeitMittag, float & Elevation) {

  float DK = Deklination;

  float cosdec = cos(DK);

  float sindec = sin(DK);

  float lha = ZeitSeitMittag * (1.0027379 - 1 / 365.25) * 15 * kwert;

  float coslha = cos(lha);

  float sinlha = sin(lha);

  float coslat = cos(B);

  float sinlat = sin(B);

  float N = -cosdec * sinlha;

  float D = sindec * coslat - cosdec * coslha * sinlat;

  Elevation = asin(sindec * sinlat + cosdec * coslha * coslat);      // Höhe des Sonnenmittelpunktes über dem Horizont

  float Azimut = atan2(N, D);

  if (Azimut < 0) {

    Azimut += 2 * pi;

  }

  return (Azimut / kwert);

}

 

 

// Funktion: BerechneZeitgleichung

 

float BerechneZeitgleichung (int yearday) {

  float Zeitgleichung = -0.170869921174742 * sin(0.0336997028793971 * yearday + 0.465419984181394) - 0.129890681040717 * sin(0.0178674832556871 * yearday - 0.167936777524864);

  return Zeitgleichung;

}

 

 

// Funktion: BerechneDeklination

 

float BerechneDeklination(int yearday) {

  float Deklination = 0.409526325277017 * sin(0.0169060504029192 * (yearday - 80.0856919827619));

  return Deklination;

}

 

 

// Funktion: BerechneZeitdifferenz

 

float BerechneZeitdifferenz(float h, float pi, float latitude, float kwert, float Deklination) {

  float Zeitdifferenz;

  Zeitdifferenz = 12 * acos((sin(h) - sin(latitude * kwert) * sin(Deklination)) / (cos(latitude * kwert) * cos(Deklination))) / pi;

  return Zeitdifferenz;

}

 

 

// Funktion: BerechneTageslaenge

 

float BerechneTageslaenge (float Zeitdifferenz, float Zeitgleichung, float longitude, int Zeitzone, float & Aufgang, float & Untergang)  {

  float AufgangOrtszeit = 12 - Zeitdifferenz - Zeitgleichung;

  float UntergangOrtszeit = 12 + Zeitdifferenz - Zeitgleichung;

  Aufgang = AufgangOrtszeit - longitude / 15 + Zeitzone;

  Untergang = UntergangOrtszeit - longitude / 15 + Zeitzone;

  float Tageslaenge = Untergang - Aufgang;

  return Tageslaenge;

}

 

 

// Funktion: MotorenSteuerung, Ansteuerung von Steppermotor und Servo

 

int MotorenSteuerung (float Azimut, float Elevation, int sensorValue, int AziH, int AziB, int Grenzwert, const int stepsV, const int stepsR, const int stepsSR)

{

  int azimutHall;

  constrain(Elevation, 0, 120);                              // Begrenzung des Servo-Wertebereichs

  Elevation = Elevation - 3;                                 // Kalibrierung der Servo-Position

  if (sensorValue >= 0 && sensorValue < 510)  {

    azimutHall = map(sensorValue, 251, 510, 90, 180);        // Skalierung der Hall-Sensorwerte in Gradwerte 90-180 Grad

  }

  if (sensorValue >= 510 && sensorValue <= 900)  {

    azimutHall = map(sensorValue, 510, 770, 180, 270);       // Skalierung der Hall-Sensorwerte in Gradwerte 180-270 Grad

  }

  constrain(azimutHall, 45, 315);                            // Begrenzung des Azimut-Soll-Wertebereichs

  if (Elevation > 0) {                                       // Solange Elevation > 0 --> Sonne steht über dem Horizont

    servo2.write(Elevation);                                 // Schreiben der Servoposition (Nachführung)

    if ((int)azimutHall < (int)Azimut) {                     // Azimut-Nachführung: Wenn Hall-Sensorwert kleiner als Azimut, dann:

      digitalWrite(pwmA, HIGH);                              // Stepper Strom an

      digitalWrite(pwmB, HIGH);                              // Stepper Strom an

      digitalWrite(4, HIGH);                                 // LED grün an

      myStepper.step(stepsV);                                // Step one revolution in one direction

      delay (500);

      digitalWrite(4, LOW);                                  // LED grün aus

      digitalWrite(7, LOW);                                  // LED rot aus

      digitalWrite(pwmA, LOW);                               // Stepper stromlos schalten

      digitalWrite(pwmB, LOW);                               // Stepper stromlos schalten

    }

    if ((int)azimutHall > (int)Azimut) {                     // Azimut-Nachführung: Wenn Hall-Sensorwert grösser als Azimut, dann:

      digitalWrite(pwmA, HIGH);                              // Stepper Strom an

      digitalWrite(pwmB, HIGH);                              // Stepper Strom an

      servo2.write(Elevation);                               // Schreiben der Servoposition (Nachführung)

      digitalWrite(7, HIGH);                                 // LED rot an

      myStepper.step(stepsR);                                // Step one revolution in one direction

      delay (500);

      digitalWrite(7, LOW);                                  // LED rot aus

      digitalWrite(4, LOW);                                  // LED grün aus

      digitalWrite(pwmA, LOW);                               // Stepper stromlos schalten

      digitalWrite(pwmB, LOW);                               // Stepper stromlos schalten

    }

  }

  else  {                                                    // Sonne ist untergegangen --> Rückführung auf Anfangsposition

    if (Elevation < 0 && (azimutHall - 1) >= Grenzwert)  {   // Azimut-Rückführung: Wenn Elevation < -1 (Sonne ist untergegangen), dann:

      delay(500);

      digitalWrite(pwmA, HIGH);

      digitalWrite(pwmB, HIGH);

      digitalWrite(6, HIGH);                                 // LED blau an

      myStepper.step(stepsSR);                               // Step one revolution in one direction

      delay (500);

      digitalWrite(6, LOW);                                  // LED blau aus

      digitalWrite(pwmA, LOW);                               // Stepper stromlos schalten

      digitalWrite(pwmB, LOW);                               // Stepper stromlos schalten

      delay(500);

    }

  }

  if (AziH = AziB) {                                         // Damit Stepper und alle LEDs aus sind beim Erreichen der Zielposition (azimutHall = Azimut)

    digitalWrite(4, LOW);

    digitalWrite(7, LOW);

    digitalWrite(pwmA, LOW);                                 // Stepper stromlos schalten

    digitalWrite(pwmB, LOW);                                 // Stepper stromlos schalten

  }

  return azimutHall;                                         // Rückgabewert: azimutHall

}

 

 

// Funktion: Solarspannung

 

float Solarspannung(float pvmod)                             // Funktion: Solarspannung

{

  float Volt;

  Volt = pvmod / 1023 * 4.75;                                // Umrechnung Analogwert in Spannungswert (Volt)

  return Volt;

}