Seite 3 von 3

Re: Langzeit Messgerät mit Protokollierung der Spannung bei Fehlerbedingten Spannungsänderungen

Verfasst: Fr 20. Feb 2026, 18:32
von Admin
So Stand Heute.
Ich habe noch ein paar Ausgaben angepasst. Das betrifft die Serial.print() Ausgabe zum PC. Wenn ich das Gerät mit gelöschen Speicher starte, dann sieht das so aus:
"I2C Fram gefunden". Das sollte immer kommen, denn wenn nicht, ist das wichtigste nicht aktiv. Der Speicher. Dann:
"Aktueller Protokoll Ablagezeiger = 32204" . Das heißt, dass keine Prokolle im Speicher sind. Dann:
"Speicher gelöscht-> Startadresse = 4". Das heißt auch kein einziger Messprotokoll Eintrag ist noch im Speicher.

Dann habe ich mal ein paar Messaufzeichnungen verursacht, habe also die Überwachte Spannung mal stufenweise erhöht, so dass jede Erhöhung die Schwelle zur Aufzeichnung überschreitet. Da passiert am PC nichts. Dann habe ich die gespeicherten Daten zum PC übertragen. Das sieht dann so aus:
########################################
### Messprotokoll Übertragung Start ###
4.5815;20.2.2026;19:17:49;1
4.6654;20.2.2026;19:18:1;2
4.7726;20.2.2026;19:18:2;3
4.8785;20.2.2026;19:18:2;4
4.9706;20.2.2026;19:18:3;5
5.0765;20.2.2026;19:18:3;6
5.1673;20.2.2026;19:18:3;7
5.2786;20.2.2026;19:18:4;8
### Messprotokoll Übertragung Ende ###
########################################
### Messchwellen - Protokoll Ausgabe ###
100;20.2.2026;19:18:42;1
# Messchwelle Protokoll - Ausgabe Ende #
########################################
Das Messschwellen Protokoll sagt, dass am 20.2.2026 um 19:18:42 Uhr die Hysteresse der Messschwelle Automatisch von 50mV auf 100mV wurde. Da innerhalb einer Zeit von einer Minute 8 Soannungserhöhungen waren, die jeweils über die Messschwelle gingen.

Das wars. Hier noch das komplette Protokoll dieser ganzen Aktionen zusammen:

Code: Alles auswählen

I2C FRAM gefunden
Aktueller Protokoll Ablagezeiger = 32204
########################################
# Speicher gelöscht-> Startadresse = 4 #
########################################
########################################
### Messprotokoll Übertragung Start  ###
4.5815;20.2.2026;19:17:49;1
4.6654;20.2.2026;19:18:1;2
4.7726;20.2.2026;19:18:2;3
4.8785;20.2.2026;19:18:2;4
4.9706;20.2.2026;19:18:3;5
5.0765;20.2.2026;19:18:3;6
5.1673;20.2.2026;19:18:3;7
5.2786;20.2.2026;19:18:4;8
###  Messprotokoll Übertragung Ende  ###
########################################
### Messchwellen - Protokoll Ausgabe ###
100;20.2.2026;19:18:42;1
# Messchwelle Protokoll - Ausgabe Ende #
########################################
OK, der Batterieschalter ist inzwischen auch eingebaut. Die Überwachung der Spannung ist auch schon drin. Also es gefällt mir schon seeeehr gut. :(oo):

Das aktualisierte Programm:

Code: Alles auswählen

/* 
    Abfrage von analogen Werten mit dem ESP32
    am ADS1115 mit Weitergabe per I2C an den I2C - FRAM, 
    wenn die Spannung deutlich abweicht vom letzten Messwert. 
    Taste zum Übertragen auf den PC, Taste zum Löschen, bei 32000 byte ist Schluss.
    Schalter für Hohe Schwelle, Autmatische Schwelle, Niedrige Schwelle.
    Anzeige im OLED angepasst 06.02.2026
    Logeintrag bei Automatischer Schwellen Änderung.
    Logeinträge beim Übertrag zum PC auch ausgeben.
    Die Hysterese ist jetzt deutlich verbessert. Sie geht jetzt nach +/- 50mV Stufen 
    Programm im Moment vom 20.02.2026 / ADC_ADS1115_ESP32_Mini_OLE_FRAM_2x4Byte_V51
*/
#include <WiFi.h>
//#define NTP_SERVER "de.pool.ntp.org"
#define NTP_SERVER "Fritz.Box"
#define TZ_INFO "WEST-1DWEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00"  // Western European Time
//--------------------------------------------------------------------------------------------
#include <Adafruit_ADS1X15.h>  // bindet Wire.h für I2C mit ein
Adafruit_ADS1115 ads;
#define ADS_I2C_ADDR 0x48
//-----------------------------FRAM-----------------------------------------------------------
#include "Adafruit_EEPROM_I2C.h"
#include "Adafruit_FRAM_I2C.h"
Adafruit_FRAM_I2C i2ceeprom;
#define EEPROM_ADDR 0x50  // the default address!
// -------------------OLED Display einrichten-------------------------------------------------
#include <U8g2lib.h>  // als U8g2 im Bibliotheksverwalter zu finden
U8G2_SH1106_128X64_NONAME_F_HW_I2C oled(U8G2_R0);
//------------------------ADS1115 16Bit Analog-Digital Sensor---------------------------------
const float multiplier = 0.125F;  // ADS1115-Multiplikator bei einf. Verstärkung
int A_Value;                      // Messwert per GPIO
int adc0;                         // Messwert an Kanal 0 des ADS1115
int adc1;                         // Messwert an Kanal 1 des ADS1115
int adc2;                         // Messwert an Kanal 2 des ADS1115
int adc3;                         // Messwert an Kanal 3 des ADS1115
float A_mv, ads_mv0, ads_mv1;     // Messwert in Millivolt umgerechnet
//--------------------------------------------------------------------------------------------
//----------------------- Spannungsmessungen Speichern ---------------------------------------
int Spannungneu = 0;
int Spannung2neu = 0;
int Spannung2alt = 0;
byte Batterie = 1;
float Messung = 0;
float f = 0;
int Hysterese = 50;  // Steht für 50mV rauf oder runter
int Hysterese2 = 0;
const int Hysteresemax = 1000;
const int Hysteresemin = 50;
//------------------ Zeitdaten FRAM ----------------------------------------
uint8_t buffer[4];  // floats are 4 bytes!
int Zeitbuffer = 0;
int Speicher = 4;
int Speicher2 = 0;
int Zaehler = 0;
int i = 0;
int UebertragZeiger = 4;
byte DzPja = 0;
int Ausgabezaehler = 0;
int Kontrollzaehler = 0;
byte Reagieren = 0;
int LogZeiger = 32200;
int LogZeiger2 = 32204;
//-----------------------Taster01---------------------------------------
const byte Loeschen = 32;            // Pin 32 wird Constant für Löschen
byte Loeschenstatus = 0;             // Zum Abfragen des Tatsenpins
byte Loeschenmerker = 0;             // Zum Merken des aktuellen Tatsenstatus
unsigned long Sekundenablauf04 = 0;  // Tastenabfrage von Taster02 300ms aussetzen
const unsigned long Pausezeit04 = 300;
//-----------------------Taster02---------------------------------------
const byte Uebertragen = 25;  // Pin 25 wird Constant für übertragung
byte Uebertragstatus = 0;
byte Uebertragmerker = 0;
unsigned long Sekundenablauf05 = 0;  // Tastenabfrage von Taster02 300ms aussetzen
const unsigned long Pausezeit05 = 300;
//--------------------Tonausgabe PIN 27---------------------------------
const byte TonPin = 27;
const int frequenz = 1000;
unsigned long tonZeit = 100;
//--------------------- Umschalter -------------------------------------
const byte USchalter01 = 12;  // Schalter oben
byte Schalter01Status = 0;
const byte USchalter02 = 4;  // Schalter unten
byte Schalter02Status = 0;
byte SchalterMerker = 0;
//------------------------- Minutentakt zur Zeit - Ausgabe -----------------------------------
unsigned long Sekundenablauf01 = 0;  // Zeit für die Ausgabe Aufs Display & Serial
const unsigned long Pausezeit01 = 60000;
unsigned long Zeitablauf = 0;
//------------------------ PLatzverbrauch am FRAM pro 60sec. ---------------------------------
unsigned long Sekundenablauf02 = 0;  // Zeit für die Ausgabe Aufs Display & Serial
const unsigned long Pausezeit02 = 60000;
//------------------------ PLatzverbrauch am FRAM pro 1 Std ----------------------------------
unsigned long Sekundenablauf03 = 0;  // Zeit für die Ausgabe Aufs Display & Serial
const unsigned long Pausezeit03 = (60000 * 60);
//-------------------------------- Zeit Messungen --------------------------------------------
unsigned long Messungstart = 0;
unsigned long Messungende = 0;
unsigned long Laufzeit = 0;

//############################################################################################
// ----------------------------------------------------SETUP----------------------------------
//############################################################################################
void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("Analog-Spannungsueberwachung mit ESP32");
  //-----------------------------------------------------------
  Serial.println(F("NTP Server Abfrage"));
  NTP_Zeit();

  // -------------------FRAM Ereichbar ??----------------------
  if (i2ceeprom.begin(0x50)) {  // Sie können die neue I2C-Adresse hier einfügen, z. B. begin(0x51);
    Serial.println(F("I2C FRAM gefunden"));
  } else {
    Serial.println(F("I2C-FRAM nicht identifiziert ... überprüfen Sie Ihre Verbindungen.?\r\n"));
    while (1) delay(10);
  }
  //-----------------------ADS 1115---------------------------
  ads.begin(ADS_I2C_ADDR, &Wire);
  // Werte 1-fach verstärken (ESP32 liefert  max. 3,3V)
  ads.setGain(GAIN_ONE);
  //-----------Taster einrichten------------------------------
  pinMode(Loeschen, INPUT_PULLUP);     // Pin 13 fuer Taster01 wird intern auf plus gelegt. Mit GND ueber Taste aktivieren
  pinMode(Uebertragen, INPUT_PULLUP);  // Pin 4 fuer Taster02
  //-----------Schalter einrichten----------------------------
  pinMode(USchalter01, INPUT_PULLUP);  // Umschalter Stellung oben
  pinMode(USchalter02, INPUT_PULLUP);  // Umschalter Stellung unten
  //----------------------- Oled Display ---------------------
  oled.begin();
  oled.clearBuffer();  // Textspeicher löschen
  //------- Erste Displayausgabe gleich nach dem Start -------
  Sekundenablauf01 = 50000;
  // Wichtige Startdaten aus dem FRAM holen
  Startdaten_holen();
  Messen();
}
//############################################################################################
// ----------------------------------------------------LOOP-----------------------------------
//############################################################################################
void loop() {
  Messungstart = millis();
  Zeitablauf = millis();
  //-- Wenn der FRAM nicht voll und Betriebsspannung gut --
  if ((Reagieren < 2) && (Batterie == 1)) {
    if (Zeitablauf - Sekundenablauf01 >= Pausezeit01) {  // Eine Minute abgelaufen?
      Displayausgabe();
      Sekundenablauf01 = millis();
    }
    Kontrollen();
    Messen();
    if (Reagieren == 1) {
      SpeicherdatenSchreiben();
      Spannung2alt = Spannung2neu;
      tone(TonPin, 1000, 100);  // Piep wenn sich die Spannung ändert.
      Reagieren = 0;
      // Diese beiden Zeilen unten, werden nur gebraucht,
      // wenn eine Ausgabe auf dem PC, nach Speicherung
      // eines Datensatzes, benötigt wird !!
      //SpeicherdatenLesen();
      //testprint();
    }
  }
  //------------------------------------------------------
  //
  //--------------- Ist der FRAM voll ?? -----------------
  if (Speicher >= 32000) {
    oled.clearBuffer();  // Textspeicher löschen
    oled.setFont(u8g2_font_10x20_mf);
    oled.setCursor(20, (2 * 20));
    oled.print(F("FRAM voll"));
    oled.sendBuffer();
    tone(TonPin, 440, 1000);
    Reagieren = 2;
  }
  //------------------------------------------------------
  //
  //------------ Tasten und Schalter Abfrage -------------
  if (Batterie = 1) {
    Tastenabfrage();
    if (Uebertragmerker == 1) {
      DatenzumPC();
      Uebertragmerker = 0;
    }
    if (Loeschenmerker == 1) {
      FRAM_Loeschen();
      Loeschenmerker = 0;
    }
    //---------------------------------------------------
    Schalterabfrage();
  }
  // Wenn Betriebsspannung zu gering, nur noch diese Prüfen
  if (Batterie == 0) {
    Messen();
    Kontrollen();
  }
  /*
  Messungende = millis();
  Laufzeit = Messungende - Messungstart;
  if (Laufzeit >= 20){
  Serial.println(Laufzeit);
  }
  */
}  //---------------------------------- LOOP ENDE ---------------------------------------------

//############################################################################################
//-------------------------- WIFI Verbindung und Zeit holen ----------------------------------
//############################################################################################
void NTP_Zeit() {
  WiFi.mode(WIFI_STA);
  WiFi.begin("FRITZ!Box Gastzugang", "GastvonFranzKoehler");
  while (WiFi.status() != WL_CONNECTED)  // Ist WLAN Connect?
  {
    delay(500);
  }
  struct tm local;
  configTzTime(TZ_INFO, NTP_SERVER);  // ESP32 Systemzeit mit NTP Synchronisieren
  getLocalTime(&local, 10000);        // Versuche 10 s zu Synchronisieren
  WiFi.mode(WIFI_OFF);
}
//---------------------------WIFI Verbindung und Zeit Ende -----------------------------------
//
//############################################################################################
//---------------------------- Startdaten aus FRAM holen -------------------------------------
//############################################################################################
void Startdaten_holen() {
  //------- Speicherzeiger auslesen (Protokoll)---------------
  i2ceeprom.read(32100, buffer, 4);
  memcpy((void *)&Speicher, buffer, 4);
  //--------Letzten Messwert auslesen (Protokoll)-------------
  i2ceeprom.read(32104, buffer, 4);
  memcpy((void *)&f, buffer, 4);
  //--------Letzte Zeit auslesen (Protokoll)------------------
  i2ceeprom.read(32108, buffer, 4);
  memcpy((void *)&Zeitbuffer, buffer, 4);
  time_t t = Zeitbuffer;
  tm tm;
  //--------Ausgabezähler auslesen (Protokoll)----------------
  i2ceeprom.read(32112, buffer, 4);
  memcpy((void *)&Zaehler, buffer, 4);
  //------- Logzeiger auslesen (Protokoll)--------------------
  i2ceeprom.read(32200, buffer, 4);
  memcpy((void *)&LogZeiger, buffer, 4);
  //------- Logzeiger1 Eintragen wenn nötig ------------------
  if (LogZeiger < 32204) {
    LogZeiger = 32204;
    memcpy(buffer, (void *)&LogZeiger, 4);
    i2ceeprom.write(32200, buffer, 4);
  }
  Serial.print(F("Aktueller Protokoll Ablagezeiger = "));
  Serial.println(LogZeiger);
  //--------Prokolldaten Ausgeben-----------------------------
  if (Speicher <= 4) {
    Speicher = 4;
    Serial.println(F("########################################"));
    Serial.println(F("# Speicher gelöscht-> Startadresse = 4 #"));
    Serial.println(F("########################################"));
  } else {
    testprint();
  }
}
//-------------------------------- Startdaten holen Ende -------------------------------------
//
//############################################################################################
//---------------------------------- Displayausgabe ------------------------------------------
//############################################################################################
void Displayausgabe() {
  tm local;
  getLocalTime(&local);
  oled.clearBuffer();               // Textspeicher löschen
  oled.setFont(u8g2_font_6x12_tr);  // Kleine Schrift 6x12
  oled.setCursor(10, (1 * 10));
  oled.print(&local, " Datum: %d.%m.%y");
  oled.setCursor(10, (2 * 10));
  oled.print(&local, " Zeit : %H:%M");  // 16 Zeichen neue Zeit schreiben
  oled.sendBuffer();

  // Messung auf das Display ausgeben
  oled.setFont(u8g2_font_10x20_mf);
  //ADS Kanal 0 anzeigen
  oled.setCursor(20, (2 * 20));
  oled.print(Messung);
  oled.print(F(" Volt "));
  //ADS Kanal 1 anzeigen
  oled.setCursor(20, (3 * 20));
  // if (ads_mv1 < 0) { ads_mv1 == 0; }
  oled.print(ads_mv0);
  oled.print(F(" Volt "));
  oled.sendBuffer();

  /*
    struct tm enthält diese Atribute:
    ===============================================
    Member   Type  Meaning                   Range
    tm_sec   int   seconds after the minute  0-60*
    tm_min   int   minutes after the hour    0-59
    tm_hour  int   hours since midnight      0-23
    tm_mday  int   day of the month          1-31
    tm_mon   int   months since January      0-11
    tm_year  int   years since 1900
    tm_wday  int   days since Sunday         0-6
    tm_yday  int   days since January 1      0-365
    tm_isdst int   Daylight Saving Time flag
    ==============================================
    */
}
//------------------------------------------------------------------------------------------
//############################################################################################
// ------------------------------------ Messung per ADS1115 ----------------------------------
//############################################################################################
void Messen() {
  // - Kanal 0 messen (single-ended)
  adc0 = ads.readADC_SingleEnded(0);
  ads_mv0 = ads.computeVolts(adc0);
  // - Kanal 1 messen (single-ended)
  adc1 = ads.readADC_SingleEnded(1);
  ads_mv1 = ads.computeVolts(adc1);
  // oder
  // - differenzielle Messung an Kanal 0/1
  //adc0 = ads.readADC_Differential_0_1();
  //ads_mv = (adc0 * multiplier);
  //Serial.printf("; I2C: %4.2f mV\n", ads_mv);
  //===============================================
  //------------------------Ist die Spannung verändert ? Ja, dann speichern !-----------------
  // Hier wird die Messung "float" durch das *100, um zwei Kommas nach hinten geschoben
  // und in einen "int" übergeben. Dadurch sind die Werte hinter dem Komma abgeschnitten.
  // Das heißt, aus den gemessenen z.B. "3,1255768" Volt werden 312,55768
  // und mit int sind die stellen hinterm Komma weg.
  // Für den Vergleich als <-> neu bleibt also nur noch der Wert "312"
  // Die dritte stelle hinterm Komma ändert sich schon rel. oft.
  // -----------------------------------------------------------------------------------------
  ads_mv0 = ads_mv0 * 11;
  Spannung2neu = ads_mv0 * 1000;
  if ((Spannung2alt + Hysterese < Spannung2neu) || (Spannung2alt - Hysterese > Spannung2neu)) {
    Reagieren = 1;
  }
  // Veränderte Spannung anzeigen
  Spannungneu = ads_mv0 * 100;
  if (Spannung2alt == Spannungneu) {
  } else {
    // Messung auf das Display ausgeben
    oled.setFont(u8g2_font_10x20_mf);
    //ADS Kanal 0 anzeigen
    oled.setCursor(20, (3 * 20));
    oled.print(ads_mv0);
    oled.print(F(" Volt "));
    oled.sendBuffer();
  }
}

// ------------------------------- Messen Ende ---------------------------------------------

//##########################################################################################
//------------------------------ FRAM Schreiben --------------------------------------------
//##########################################################################################
void SpeicherdatenSchreiben() {
  Speicher = Speicher + 4;
  Zaehler = Zaehler + 1;
  Kontrollzaehler = Kontrollzaehler + 1;
  // Messwert Schreiben--------------------------------------------------------------------
  f = ads_mv0;
  Messung = ads_mv0;
  memcpy(buffer, (void *)&f, 4);
  i2ceeprom.write(Speicher, buffer, 4);
  // Letzen Messwert schreiben (Protokoll)-------------------------------------------------
  memcpy(buffer, (void *)&f, 4);
  i2ceeprom.write(32104, buffer, 4);
  // Zeit & Datum Schreiben----------------------------------------------------------------
  time_t now;
  time(&now);
  Speicher = Speicher + 4;
  memcpy(buffer, (void *)&now, 4);
  i2ceeprom.write(Speicher, buffer, 4);
  // Zeit vom letzten Messwert Schreiben (Protokoll)---------------------------------------
  memcpy(buffer, (void *)&now, 4);
  i2ceeprom.write(32108, buffer, 4);
  // Speicherzeiger im FRAM schreiben auf 32100 sichern (Protokoll)------------------------
  memcpy(buffer, (void *)&Speicher, 4);
  i2ceeprom.write(32100, buffer, 4);
  // Zähler von letzten Eintrag schreiben (Protokoll)--------------------------------------
  memcpy(buffer, (void *)&Zaehler, 4);
  i2ceeprom.write(32112, buffer, 4);
  // Display aktualisieren-----------------------------------------------------------------
  oled.setCursor(20, (2 * 20));
  oled.print(Messung);
  oled.print(F(" Volt "));
  //ADS Kanal 1 anzeigen
  oled.setCursor(20, (3 * 20));
  oled.print(ads_mv0);
  oled.print(F(" Volt "));
  oled.sendBuffer();
}
//------------------------------ Schreiben Ende ---------------------------------------------
//
//###########################################################################################
//------------------------------ FRAM Auslesen ----------------------------------------------
//###########################################################################################
void SpeicherdatenLesen() {
  // Messwert auslesen-----------------------------------------------------------------------
  Speicher2 = Speicher - 4;
  i2ceeprom.read(Speicher2, buffer, 4);
  memcpy((void *)&f, buffer, 4);
  // Zeit / Datum auslesen-------------------------------------------------------------------
  Speicher2 = Speicher;
  i2ceeprom.read(Speicher2, buffer, 4);
  memcpy((void *)&Zeitbuffer, buffer, 4);
}
//------------------------------ Auslesen Ende ---------------------------------------------
//
//###########################################################################################
//-------------------------- Automatik Logs im FRAM -----------------------------------------
//###########################################################################################
void AutoLogschreiben() {
  //------- Logzeiger auslesen (Protokoll)---------------------------------------------------
  i2ceeprom.read(32200, buffer, 4);
  memcpy((void *)&LogZeiger2, buffer, 4);
  //------- Ist im FRAM noch Platz für Logeinträge ?? ----------------------------------------
  if (LogZeiger2 <= 32690) {
    //------- Schwelle schreiben --------------------------------------------------------------
    memcpy(buffer, (void *)&Hysterese, 4);
    i2ceeprom.write(LogZeiger2, buffer, 4);
    // Log - Zeit & Datum Schreiben------------------------------------------------------------
    time_t now;
    time(&now);
    LogZeiger2 = LogZeiger2 + 4;
    memcpy(buffer, (void *)&now, 4);
    i2ceeprom.write(LogZeiger2, buffer, 4);
    //Neuen Logzeiger in FRAM schreiben -------------------------------------------------------
    LogZeiger2 = LogZeiger2 + 4;
    memcpy(buffer, (void *)&LogZeiger2, 4);
    i2ceeprom.write(32200, buffer, 4);
    //Serial.println(LogZeiger2);
  }
}
//--------------------------- Automatik Logs Ende -------------------------------------------
//
//###########################################################################################
//-------------------------- FRAM zum PC Übertragen -----------------------------------------
//###########################################################################################
void DatenzumPC() {
  // Messwert auslesen-----------------------------------------------------------------------
  Serial.println(F("########################################"));
  Serial.println(F("### Messprotokoll Übertragung Start  ###"));
  oled.setFont(u8g2_font_10x20_mf);
  oled.setCursor(20, (2 * 20));
  oled.println(F("Uebertrag"));
  oled.sendBuffer();
  Ausgabezaehler = 0;
  UebertragZeiger = 8;
  for (int i = UebertragZeiger; i <= Speicher; i = i + 4) {
    i2ceeprom.read(i, buffer, 4);
    memcpy((void *)&f, buffer, 4);
    // Zeit / Datum auslesen-------------------------------------------------------------------
    i = i + 4;
    i2ceeprom.read(i, buffer, 4);
    memcpy((void *)&Zeitbuffer, buffer, 4);
    time_t t = Zeitbuffer;
    tm tm;
    localtime_r(&t, &tm);
    tm.tm_year += 1900;
    tm.tm_mon += 1;
    Ausgabezaehler++;
    Serial.print(f, 4);
    Serial.print(F(";"));
    Serial.print(tm.tm_mday);
    Serial.print(F("."));
    Serial.print(tm.tm_mon);
    Serial.print(F("."));
    Serial.print(tm.tm_year);
    Serial.print(F(";"));
    Serial.print(tm.tm_hour);
    Serial.print(F(":"));
    Serial.print(tm.tm_min);
    Serial.print(F(":"));
    Serial.print(tm.tm_sec);
    Serial.print(";");
    Serial.println(Ausgabezaehler);
  }
  Serial.println(F("###  Messprotokoll Übertragung Ende  ###"));
  Serial.println(F("########################################"));
  Uebertragmerker = 0;
  //------- Logzeiger auslesen (Protokoll)--------------------
  Serial.println(F("### Messchwellen - Protokoll Ausgabe ###"));
  i2ceeprom.read(32200, buffer, 4);
  memcpy((void *)&LogZeiger, buffer, 4);
  if (LogZeiger >= 32204) {
    Ausgabezaehler = 0;
    UebertragZeiger = 32204;
    for (int i = UebertragZeiger; i < LogZeiger; i = i + 4) {
      i2ceeprom.read(i, buffer, 4);
      memcpy((void *)&Hysterese2, buffer, 4);
      // Zeit / Datum auslesen-------------------------------------------------------------------
      i = i + 4;
      i2ceeprom.read(i, buffer, 4);
      memcpy((void *)&Zeitbuffer, buffer, 4);
      time_t t = Zeitbuffer;
      tm tm;
      localtime_r(&t, &tm);
      tm.tm_year += 1900;
      tm.tm_mon += 1;
      Ausgabezaehler++;
      Serial.print(Hysterese2);
      Serial.print(F(";"));
      Serial.print(tm.tm_mday);
      Serial.print(F("."));
      Serial.print(tm.tm_mon);
      Serial.print(F("."));
      Serial.print(tm.tm_year);
      Serial.print(F(";"));
      Serial.print(tm.tm_hour);
      Serial.print(F(":"));
      Serial.print(tm.tm_min);
      Serial.print(F(":"));
      Serial.print(tm.tm_sec);
      Serial.print(";");
      Serial.println(Ausgabezaehler);
    }
  }
  Serial.println(F("# Messchwelle Protokoll - Ausgabe Ende #"));
  Serial.println(F("########################################"));
}
//------------------------------ Auslesen Ende ---------------------------------------------
//##########################################################################################
//-------------------------------- Testprint -----------------------------------------------
//##########################################################################################
void testprint() {
  time_t t = Zeitbuffer;
  tm tm;
  localtime_r(&t, &tm);
  tm.tm_year += 1900;
  tm.tm_mon;
  Serial.print(f, 4);
  Serial.print(F(" Volt ->"));
  Serial.print(&tm, " Datum: %d.%m.%y");
  Serial.print(&tm, " Zeit: %H:%M:%S");
  Serial.print(F(" ADR = "));
  Serial.print(Speicher);
  Serial.print(F(" # "));
  Serial.println(Zaehler);
}
//-------------------------------- Testprint Ende ------------------------------------------
//
//##########################################################################################
//--------------------------------- FRAM löschem -------------------------------------------
//##########################################################################################
void FRAM_Loeschen() {
  Serial.println(F("########################################"));
  Serial.print(F("# FRAM wird gelöscht "));
  oled.setFont(u8g2_font_10x20_mf);
  oled.setCursor(20, (2 * 20));
  oled.println(F("Loeschen! "));
  oled.sendBuffer();
  for (i = 0; i <= 32700; i = i + 4) {
    f = 0;
    memcpy(buffer, (void *)&f, 4);
    i2ceeprom.write(i, buffer, 4);
  }
  //------- Speicherzeiger auf Start---------------
  // Speicherzeiger = 4 im FRAM auf 32100 sichern
  Speicher = 4;
  memcpy(buffer, (void *)&Speicher, 4);
  i2ceeprom.write(32100, buffer, 4);
  Kontrollzaehler = 0;
  Zaehler = 0;
  Serial.println(F("FRAM IST gelöscht #"));
  Serial.println(F("########################################"));
  oled.setFont(u8g2_font_10x20_mf);
  oled.setCursor(20, (2 * 20));
  oled.println(F("Geloescht"));
  oled.sendBuffer();
  //------ Lockfile Zeiger auf Start 32204 setzen --
  //Neuen Logzeiger in FRAM schreiben -------------------------------------------------------
  LogZeiger2 = 32204;
  memcpy(buffer, (void *)&LogZeiger2, 4);
  i2ceeprom.write(32200, buffer, 4);
  //Serial.println(LogZeiger2);
}
//##########################################################################################
//--------------------------------- Taster abfragen ----------------------------------------
//##########################################################################################
void Tastenabfrage() {
  //-----------Loeschen abfragen--------------------------------------------
  if (Zeitablauf - Sekundenablauf04 >= Pausezeit04) {  // 300msec abgelaufen?
    Loeschenstatus = digitalRead(Loeschen);            // Pin von Taster01 abfragen
    if (Loeschenstatus == LOW) {                       // Ist Taster01 gedrueckt?
      Loeschenmerker = !Loeschenmerker;                // Merken dass Taster01 gedrueckt wurde
      Sekundenablauf04 = millis();                     // Die 200ms neu starten
      tone(TonPin, frequenz, tonZeit);                 // Bestätigungston für Tastendruck ausgeben
    }
  }
  //-----------Uebertragen abfragen--------------------------------------------
  if (Zeitablauf - Sekundenablauf05 >= Pausezeit05) {  // 300msec abgelaufen?
    Uebertragstatus = digitalRead(Uebertragen);        // Pin von Taster02 abfragen
    if (Uebertragstatus == LOW) {                      // Ist Taster02 gedrueckt?
      Uebertragmerker = 1;                             // Merken dass Taster02 gedrueckt wurde
      Sekundenablauf05 = millis();                     // Die 200ms neu starten
      tone(TonPin, frequenz, tonZeit);                 // Bestätigungston für Tastendruck ausgeben
    }
  }
}
//##########################################################################################
//-------------------------------- Schalter abfragen ---------------------------------------
//##########################################################################################
void Schalterabfrage() {
  Schalter01Status = digitalRead(USchalter01);
  if (Schalter01Status == LOW) {
    SchalterMerker = 1;
    Hysterese = 50;
  }
  Schalter02Status = digitalRead(USchalter02);
  if (Schalter02Status == LOW) {
    SchalterMerker = 2;
    Hysterese = 1000;
  }
  if ((Schalter01Status == HIGH) && (Schalter02Status == HIGH)) {
    SchalterMerker = 0;
  }
}
//##########################################################################################
//-------------------------- Wichtige Kontrollen -------------------------------------------
//##########################################################################################
void Kontrollen() {
  // Prüfen ob die Schwelle zu niedrig ist
  if (Zeitablauf - Sekundenablauf02 >= Pausezeit02) {  // FRAM Aufzeichungen pro 60sek. messen
    if ((Kontrollzaehler > 3) && (Hysterese < Hysteresemax) && (SchalterMerker == 0)) {
      Hysterese = Hysterese + 50;
      //Serial.print(F("##### Hysterese Automatisch auf -> "));
      //Serial.print(Hysterese);
      //Serial.println(F(" mVolt erhöht #######"));
      Kontrollzaehler = 0;
      AutoLogschreiben();
    }
    Sekundenablauf02 = millis();
    Kontrollzaehler = 0;
  }
  // Prüfen ob die Schwelle wiede abgesenkt werden kann
  if (Zeitablauf - Sekundenablauf03 >= Pausezeit03) {  // FRAM Aufzeichungen pro Stunde messen
    if ((Kontrollzaehler < 2) && (Hysterese > Hysteresemin) && (SchalterMerker == 0)) {
      Hysterese = Hysterese - 50;
      //Serial.print(F("###### Hysterese Automatisch auf -> "));
      //Serial.print(Hysterese);
      //Serial.println(F(" mVolt runtergesetz ######"));
      Kontrollzaehler = 0;
      AutoLogschreiben();
    }
    Sekundenablauf03 = millis();
    Kontrollzaehler = 0;
  }
  // Prüfen, ob Betriebsspannung des Gerätes zu niedrig
  if (ads_mv1 < 3) {
    oled.clearBuffer();  // Textspeicher löschen
    oled.setFont(u8g2_font_10x20_mf);
    oled.setCursor(20, (2 * 20));
    oled.print(F("Fehler 01"));
    oled.sendBuffer();
    Batterie = 0;
  } else {
    Batterie = 1;
  }
  // Prüfen ob die Zeit wieder vom Server geholt werden muss.
  tm local;
  //00:00:XX = 3600(=1 Std) * std = 0 + min = 0 * 60 = 0 + sec = maximal 59 sec
  uint32_t nbSek = 3600ul * local.tm_hour + local.tm_min * 60ul + local.tm_sec;
  if (nbSek <= 2)  // zwischen 00:00:00 Uhr und 00:00:59 Uhr Zeit vom NTP holen
  {
    NTP_Zeit();
  }
}
//------------------------------- Kontrollen Ende -------------------------------------------