Ich hänge immer noch in meinem Programm, bei der Ablage als 4 Byte Zahl dieser UTC Zeit (Sekunden seit 1970) im FRAM. Kann mir jemand erst mal nur zeigen, was ich da bei FRAM Schreiben → Zeit und Datum schreiben machen muss, dass ich an dieser Stelle diesen Zeitstempel ins FRAM Schreibe ??
Ich schreiben den Messwert in die ersten 4 Byte, das funktioniert und möchte den Zeitstempel in den zweiten 4 Byte ablegen. Was ich immer noch nicht schaffe.
FRAM Auslesen ist dann die nächste Baustelle, da wird bis jetzt auch nur der Messwert ausgelesen, was auch funktioniert. Aber das ist jetzt erst mal uninteressant. Mir würde der Schritt reichen, dass der UTC Zeitstempel im FRAM steht. Ich tappe da rum wie ein Blinder, weil ich keine Ahnung habe, wie ich den Wert aufbereiten muss, dass ich in in den 4 Byte ablegen kann.
Hier das derzeitige Programm.
```cpp
/*
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.
Programm im Moment vom 18.01.2026
*/
#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 Spannung2neu = 0;
int Spannung2alt = 0;
float f = 0;
uint8_t buffer[4]; // floats are 4 bytes!
int Speicher = 4;
int Speicher2 = 0;
int Zaehler = 0;
int Zaehlerkontrolle = 0;
byte LSpin = 27;
byte Messtiefe = 10;
byte Reagieren = 0;
//------------------------- Minuten Tackt zur 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 Std. -----------------------------------
unsigned long Sekundenablauf02 = 0; // Zeit für die Ausgabe Aufs Display & Serial
const unsigned long Pausezeit02 = 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-Test ESP32");
//-----------------------------------------------------------
Serial.println(F("NTP Server Abfrage"));
NTP_Zeit();
// ------------------EPROM 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);
//----------------------- Oled Display ---------------------
oled.begin();
oled.clearBuffer(); // Textspeicher löschen
//------- Erste Displayausgabe gleich nach dem Start -------
Sekundenablauf01 = 60000;
}
//############################################################################################
// ----------------------------------------------------LOOP-----------------------------------
//############################################################################################
void loop() {
Messungstart = millis();
Zeitablauf = millis();
if (Zeitablauf - Sekundenablauf01 >= Pausezeit01) { // Eine Minute abgelaufen?
Displayausgabe();
Sekundenablauf01 = millis();
}
Kontrollen();
Messen();
if (Reagieren == 1) {
SpeicherdatenSchreiben();
Spannung2alt = Spannung2neu;
SpeicherdatenLesen();
Reagieren = 0;
}
/*
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);
}
//############################################################################################
//---------------------------------- 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");
// Hier das Problem. Die Zeitausgabe
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.println(F("ADR "));
oled.print(Speicher);
//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.
// -----------------------------------------------------------------------------------------
Spannung2neu = ads_mv0 * Messtiefe;
if (Spannung2alt == Spannung2neu) {
} else {
// Messung auf das Display ausgeben
oled.setFont(u8g2_font_10x20_mf);
//ADS Kanal 0 anzeigen
oled.setCursor(20, (2 * 20));
oled.println(F("ADR "));
oled.print(Speicher + 4);
//ADS Kanal 1 anzeigen
oled.setCursor(20, (3 * 20));
oled.print(ads_mv0);
oled.print(F(" Volt "));
oled.sendBuffer();
Reagieren = 1;
tone(LSpin, 1000, 100); // Piep wenn sich die Spannung ändert.
}
}
// ------------------------------- Messen Ende ---------------------------------------------
//##########################################################################################
//------------------------------ FRAM Schreiben --------------------------------------------
//##########################################################################################
void SpeicherdatenSchreiben() {
Speicher = Speicher + 4;
Zaehler = Zaehler + 1;
Zaehlerkontrolle = Zaehlerkontrolle + 1;
// Messwert Schreiben--------------------------------------------------------------------
f = ads_mv0;
//memcpy(buffer, (void *)&f, 4);
memcpy(buffer, (void *)&f, 4);
i2ceeprom.write(Speicher, buffer, 4);
// Zeit & Datum Schreiben----------------------------------------------------------------
tm local;
getLocalTime(&local);
//Serial.print(&local);
Speicher = Speicher + 4;
memcpy(buffer, (void *)&local, 4);
i2ceeprom.write(Speicher, buffer, 4);
}
//------------------------------ Schreiben Ende ---------------------------------------------
//
//###########################################################################################
//------------------------------ FRAM Auslesen ----------------------------------------------
//###########################################################################################
void SpeicherdatenLesen() {
Speicher2 = Speicher - 4;
//Speicher2 = Speicher;
i2ceeprom.read(Speicher2, buffer, 4);
memcpy((void *)&f, buffer, 4);
Serial.print(F("Rücklese Wert: "));
Serial.print(f, 8);
Serial.print(F(" -> Speicherstelle = "));
Serial.print(Speicher);
Serial.print(F(" -> Wie viele Werte = "));
Serial.println(Zaehler);
}
//------------------------------ Auslesen Ende ---------------------------------------------
//
//##########################################################################################
//-------------------------- Wichtige Kontrollen -------------------------------------------
//##########################################################################################
void Kontrollen() {
if (Zeitablauf - Sekundenablauf02 >= Pausezeit02) { // FRAM Aufzeichungen pro Stunde messen
if (Zaehlerkontrolle >= 50) {
Messtiefe = Messtiefe / 10;
Zaehlerkontrolle = 0;
}
Sekundenablauf02 = millis();
}
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 -------------------------------------------
```
