Forum: Mikrocontroller und Digitale Elektronik Uhrzeitrechner


von Eva T. (Firma: ASch) (evatonna)


Lesenswert?

Hallo zusammen,
ich versuchen zurzeit einen Datalogger zu programmieren. Dieser soll 
alle werte der letzten 10 h abspeichern.
Dafür verwende ich ein RTC Modul. Wenn ich jetzt zum Beispiel um 19:00 
Uhr die Daten anschauen will sollen alle werte bis 09:00 sichtbar sein.
Um 08:00 Uhr alle Daten bis 22:00 Uhr.
Habt ihr eine Idee wie man das macht?

: Verschoben durch Moderator
von RTC (Gast)


Lesenswert?

Ja!

von N. M. (mani)


Lesenswert?

1
Hier könnt ihr Projekte, Schaltungen oder Codeschnipsel vorstellen. Projekte bitte nur mit Code oder Schaltplan posten (falls ihr nur Fotos vorstellen möchtet, bitte in "Zeigt her eure Kunstwerke"). Bitte hier keine Fragen posten.

von A. S. (Gast)


Lesenswert?

Geht es Dir darum, Uhrzeiten zu vergleichen?

Das einfachste: Rechne in Sekunden (oder ms) um. Wenn es nur um < 24h 
geht:

Sekunden ab Mitternacht (h*3600 + m * 60 + s).

Für "heute" einen ganzen Tag addieren (24*3600), für gestern nicht, 
vorgestern und älter sind eh raus.

Dann Vergleichen ob der Zeitstempel < Zeit(jetzt)-10*3600 ist.

--> bitte mit 32 bit rechnen
--> Race-Conditions beim Auslesen Uhrzeit/Datum beachten. Wenn Du nicht 
weißt, was das bedeutet, Deinen Code posten.

Wenn es allgemein ist, Sekunden seit z.B. 1.1.2020 nehmen.

von Hermann Kokoschka (Gast)


Lesenswert?

Wenn alle Werte hintereinander gespeichert werden,
UND Du weisst WIE-OFT PRO ZEITEINHEIT Du gesampelt/gespeichert hast:
Dann reicht einfaches zählen.

Ansonsten genau wie "(achs)" schrub.

von Eva T. (Firma: ASch) (evatonna)


Angehängte Dateien:

Lesenswert?

A. S. schrieb:
> Race-Conditions beim Auslesen Uhrzeit/Datum beachten. Wenn Du nicht
> weißt, was das bedeutet, Deinen Code posten.

Datei ist angehängt
Es geht eigentlich nur um die if Bedingung am ende

von Harald W. (wilhelms)


Lesenswert?

A. S. schrieb:

> Wenn es allgemein ist, Sekunden seit z.B. 1.1.2020 nehmen.

Oder man nimmt gleich die Unixzeit.
Dann ist es wirklich allgemeingültig.
https://de.wikipedia.org/wiki/Unixzeit

: Bearbeitet durch User
von Georg (Gast)


Lesenswert?

Eva T. schrieb:
> Uhr die Daten anschauen will sollen alle werte bis 09:00 sichtbar sein.

Sichtbar wo? Lokal oder Handy-App oder PC?

Wenn du immer die letzten 10 Datensätze abspeicherst musst du eigentlich 
nicht mal die Zeit mit abspeichern - wenn du abrufst sind das ja immer 
die letzten 10 Stunden.

Es gibt Umrechnungssoftware für Daten in alles denkbare bis hin zum 
Maya-Kalender. Die gehört in das Anzeigeprogramm und nicht in den 
Datenlogger.

Georg

von PittyJ (Gast)


Lesenswert?

Ich würde eine SQL Datenbank nehmen.
Alle Werte darin abspeichern mit insert.
Bei der Abfrage dann nur die letzten 10 Stunden durch den select 
auswählen.
Dabei dann alle älteren durch einen delete löschen.

Da ja keine Aussagen zu Rechner, OS etc gemacht wurden, durfte ich mir 
das frei wählen.

von Wolle G. (wolleg)


Lesenswert?

Eva T. schrieb:
> ich versuchen zurzeit einen Datalogger zu programmieren. Dieser soll
> alle werte der letzten 10 h abspeichern.

etwas unklar
z.B.
a) in welchen Zeitabständen werden die Daten erfasst?
b) wo werden die Daten abgespeichert?

von W.S. (Gast)


Lesenswert?

Harald W. schrieb:
>> Wenn es allgemein ist, Sekunden seit z.B. 1.1.2020 nehmen.
>
> Oder man nimmt gleich die Unixzeit.
> Dann ist es wirklich allgemeingültig.
> https://de.wikipedia.org/wiki/Unixzeit

Nix davon ist allgemeingültig. Wann z.B. haben die Neandertaler gelebt? 
In Sekunden nach dem 1.1.1970?

Zeit ist für uns quasi unendlich in beide Richtungen. Da reichen auch 
keine 32 Bit. Also ist es völlig legitim für eine bestimmte Anwendung, 
nur einen bestimmten Ausschnitt der Zeit überstreichen zu können.

Für Evas Anwendung wäre es ausreichend, wenn die zu zählende Zeit 
rückwärts vom jeweiligen Jetzt gezählt würde, allerdings hat es dabei 
den Haken, daß das Jetzt voranschreitet und folglich alle zuvorigen 
Ereigniszeiten nach jeder Sekunde aktualisiert werden müßten. Ist ne 
recht ungünstige, da rechenintensive Weise.

Also kann man sich einen relativ beliebigen Zeitpunkt hernehmen und den 
als Startpunkt wählen. Man muß bloß dann einen neuen Zeitpunkt 0 wählen 
und die Zeiten aktualisieren, wenn die Zeitspanne so groß geworden ist, 
daß die Zählvariablen überzulaufen drohen.

Eine völlig andere Herangehensweise wäre, zu jedem Ereignis die 
Zeitspanne zum vorherigen Ereignis zu merken. Wenn die Ereignisse nicht 
allzuweit zeitlich auseinanderliegen, reicht dafür dann auch eine 
kleinere Zählvariable. Allerdings müßte man dann, wenn man den Zeitpunkt 
des tausendsten Ereignisses vor Jetzt haben will, tausend Additionen 
machen.

Es kommt da also auf das an, was mit den gespeicherten Ereignissen 
gemacht werden soll.

W.S.

von N. M. (mani)


Lesenswert?

Wolle G. schrieb:
> etwas unklar
> z.B.
> a) in welchen Zeitabständen werden die Daten erfasst?
1
if (ts.totalseconds() >= 6)

Wolle G. schrieb:
> wo werden die Daten abgespeichert?
1
dataFile_IN = SD.open("inputfile.txt", O_WRITE | O_APPEND);

PittyJ schrieb:
> Ich würde eine SQL Datenbank nehmen.
1
// Pin 10 auf Arduino Uno

Ich rate Mal nur ins Blaue, die Beschreibung des Problems ist wirklich 
schlecht.

Dem Code nach handelt es sich um einen Arduino Uno der alle 6 Sekunden 
auf eine SD Karte speichert.
Auf Anforderung sollen alle Daten von (now - 10h) zur Verfügung gestellt 
werden.

Das sind grob überschlagen 10 Werte pro Minute  60 Minuten  10 Stunden 
* mindestens 40 Byte pro Eintrag (da alles als String). Also 240kB+. 
Also nichts was man bei dem uC im RAM hält.

Es wird also darauf raus laufen z.B. eine Datei pro Stunde anzulegen.
Zum Beispiel mit Datum/Uhrzeit im Dateinamen. Immer wenn es 11 Dateien 
sind, löschst du die älteste Weg.

von M.A. S. (mse2)


Lesenswert?

W.S. schrieb:
> Nix davon ist allgemeingültig. Wann z.B. haben die Neandertaler gelebt?
> In Sekunden nach dem 1.1.1970?
Genau! Am besten definiert man die Zeit in Sekunden nach dem Urknall. :)

von PiffPoff (Gast)


Lesenswert?

Gibt es nen Grund warum hier alle die standard libs so sehr hassen?
Warum nicht einfach ganz normal tm/mktime aus <ctime>?

von Wolle G. (wolleg)


Lesenswert?

N. M. schrieb:
> der alle 6 Sekunden
> auf eine SD Karte speichert.

Aha, es werden Werte auf einer SD-Karte im Abstand von 6s abgespeichert.

Man kann die Daten sammeln und wenn 512Byt erreicht sind, sektorenweise 
in einer Datei, welche auf der SD-Karte angelegt wurde, schreiben.
Diese Datei kann im Nachgang beliebig analysiert werden.
Läuft bei mir mit einem MSP430F1611 schon über 10 Jahre, wobei die Datei 
jährlich überschrieben wird.

von Wolfgang (Gast)


Lesenswert?

Eva T. schrieb:
> Dieser soll alle werte der letzten 10 h abspeichern.

Dann brauchst du einen Zwischenspeicher, in dem du dir die Werte der 
letzten 10h merken kannst, bevor du sie abspeicherst.

von N. M. (mani)


Lesenswert?

Wolle G. schrieb:
> Aha, es werden Werte auf einer SD-Karte im Abstand von 6s abgespeichert.

Ja werden sie. Lese doch ihren Code von oben:
https://www.mikrocontroller.net/attachment/highlight/578383

Wolle G. schrieb:
> Man kann die Daten sammeln und wenn 512Byt erreicht sind, sektorenweise
> in einer Datei, welche auf der SD-Karte angelegt wurde, schreiben.

Ja, kann und sollte man. Sie macht aber nach jedem Schreibzugriff ein 
close der Datei. In der Doku steht dazu:
1
SD - close()
2
Close the file, and ensure that any data written to it is physically saved to the SD card.

https://www.arduino.cc/reference/en/libraries/sd/close/

Dann verballert sie halt für die 40-50 Byte Nutzdaten momentan immer 
einen kompletten Sektor...

von Manfred (Gast)


Lesenswert?

Wolle G. schrieb:
> N. M. schrieb:
>> der alle 6 Sekunden
>> auf eine SD Karte speichert.
> Aha, es werden Werte auf einer SD-Karte im Abstand von 6s abgespeichert.

Na und? Ich habe einen Spannungslogger gebaut, wo ich sogar jede Sekunde 
auf die Karte schreibe. In anderen Anwendungen schreibe ich alle 15 
Sekunden.

Die Idee, alles älter 10 Stunden zu löschen, sehe ich problematisch - 
dafür müsste er die komplette Datei einlesen und bearbeiten können. Mit 
einem EEPROM könnte man einen Ringspeicher bauen, das sehe ich aber mit 
einer SD-Karte nicht als machbar an.

von N. M. (mani)


Lesenswert?

Manfred schrieb:
> Die Idee, alles älter 10 Stunden zu löschen, sehe ich problematisch

Sehe ich nicht.

Manfred schrieb:
> dafür müsste er

Sie

Manfred schrieb:
> die komplette Datei einlesen und bearbeiten können

Ne müsste sie nicht, wenn sie einfach pro Stunde eine Datei anlegt und 
sobald es 11 Dateien gibt die älteste löscht.
Dann bleiben 10 Dateien für 10h übrig.

von N. M. (mani)


Lesenswert?

Manfred schrieb:
> Na und? Ich habe einen Spannungslogger gebaut, wo ich sogar jede Sekunde
> auf die Karte schreibe.

Das kann man machen. Im obigen Fall ist Wolles Einwand aber 
gerechtfertigt, da es sehr ineffektiv ist.
Es wäre effektiver die Datei nicht ständig zu schließen damit die 
Sektoren besser ausgenutzt werden.

von Purzel H. (hacky)


Lesenswert?

Was fuer eine schwache Idee auf einem Logger ein File und eine Datenbank 
zu verwenden, wenn man doch gleich ein Array verwenden kann.

von TotoMitHarry (Gast)


Lesenswert?

im Prinzip schon falsch/ungünstig abgespeichert..

ich würd eimemr ein Format nehmen wie CSV, das auch Excel lesen kann.

man könnte die X Zeilen aus "11Stunden/Intervall", ein Array in der 
Größe schaffen und einfach beschreiben, somit hat man am Ende nur die 
letzten X Intervalle.(Array muss wenn voll von Vorne anfangen 
(Ringbuffer))

an kann aber auch alles rechenintensiv mit strptime überprüfen und jede 
Zeile mit einem datumsvergleich mit difftime analysieren.. somit könnte 
man sich auch beliebige zeitbereiche aussuchen.

Bei einem eSP32 oder ähnlichem bräuchte man nichtmal eine SD. wenn man 
in unixtime rechnen würde, hätte man sogar weniger Daten zu speichern.

von TotoMitHarry (Gast)


Lesenswert?

TotoMitHarry schrieb:
> rechenintensiv mit strptime

Sorry, das geht nicht beim arduino..

von Manfred (Gast)


Lesenswert?

Purzel H. schrieb:
> Was fuer eine schwache Idee auf einem Logger ein File und eine Datenbank
> zu verwenden,

Wenn man genug Rechenleistung und Speicher hat, ist eine Datenbank nicht 
wirklich dumm. Im Gegenteil, die bietet die Basis, ältere Einträge zu 
löschen.

Aber wir wissen nicht, was geloggt werden soll und wie die Hardware 
aussieht.

TotoMitHarry schrieb:
> ich würd eimemr ein Format nehmen wie CSV, das auch Excel lesen kann.

Mache ich so, wenn ich auf SD-Karte schreibe. Da muß man, zumindest in 
Arduino, Klimmzüge machen, Dezimalpunkt gegen zu Komma tauschen.

> man könnte die X Zeilen aus "11Stunden/Intervall", ein Array in der
> Größe schaffen und einfach beschreiben, somit hat man am Ende nur die
> letzten X Intervalle.(Array muss wenn voll von Vorne anfangen
> (Ringbuffer))

Ringpuffer hatte ich erwähnt und dabei den Beitrag von N. M. übersehen:
N. M. schrieb:
> Es wird also darauf raus laufen z.B. eine Datei pro Stunde anzulegen.
> Zum Beispiel mit Datum/Uhrzeit im Dateinamen. Immer wenn es 11 Dateien
> sind, löschst du die älteste Weg.

Der Ring mit 10 Dateien scheint doch der sinnvollste Ansatz zu sein.

von TotoMitHarry (Gast)


Lesenswert?

oder die rtclib eigenen Funktionen nutzen..

wobei der Ringbuffer bei nem Arduino Uno und 6Sekunden Intervall nen 
bisschen zu groß wird ;)

Pseudocode aus der RTCLIB Referenz (ungeprüft zusammengewurschtelt):
1
  String zeit = rtc.now().timestamp(); //("2020-06-25T15:29:37")
2
  //Lesen mit
3
    String input="2020-06-25T15:29:37|37";
4
  int index = input.indexOf('|');
5
    const String check = input.substring(0,index);
6
    DateTime test(&check);//"2020-06-25T15:29:37"
7
    DateTime temp= test - TimeSpan(  0,    11,    0,    0  );
8
    if(test>temp)
9
    {true}

von TotoMitHarry (Gast)


Lesenswert?

Korrektur, muss nach ganz oben vor die Schleife
1
DateTime temp= rtc.now() - TimeSpan(  0,    11,    0,    0  ); //zieht 11 Stunden ab

von Schnarch (Gast)


Lesenswert?

Du brauchst eine Zeitbasis und Speicherplatz, für die Daten der letzten 
10 Stunden:
10 Werte für jede Stunde, 600 Werte für jede Minute. 36000 Werte für 
jede Sekunde. Am besten, als Ringspeicher in passender Größe!

Liest man jetzt die Daten vom letzten Eintrag rückwärts aus dem 
Speicher, ist dein Problem gelöst. FERTIG!

von N. M. (mani)


Lesenswert?

Schnarch schrieb:
> 10 Werte für jede Stunde, 600 Werte für jede Minute. 36000 Werte für
> jede Sekunde.

Gerade andersrum! Wäre etwas merkwürdig wenn man für einen längeren 
Zeitraum weniger Werte hat, oder?

10 Werte pro Minute, 600 Werte pro Stunde, 6000 Werte pro 10h.
Bis dahin sieht es noch garnicht so viel aus. Aber man sieht bereits 
jetzt, dass das so mit ihrem Arduino Uno (2kB SRAM) nichts geben wird 
mit dem Ringpuffer. Egal ob sie die Temperatur als String, als Rohwerte 
(int) oder auch nur als einzelnes Byte abspeichert.

Außerdem spricht sie von Wetterdaten, was zwangsläufig nicht nur die 
Temperatur sein wird.

Es kommen also bei jedem weiteren Messwert 6000 Werte dazu.
Zusätzlich wird man ab und zu eine richtige Uhrzeit abspeichern müssen. 
Der interne Quartz wird bei 10h weglaufen.

Wenn wir also mit 2 Byte pro Wert rechnen und pro Stunde einen richtigen 
Zeitstempel von RTC, dann sind wir ungefähr bei 12kB pro 10h und Wert 
plus 40 Byte für die Uhrzeiten.

Alles im RAM zu halten hat auch einen Nachteil. Wenn innerhalb der 10h 
die Spannung einmal ausfällt, sind alle Daten futsch.

Ein Mittelweg wäre es, nur so viele Daten im RAM zu halten bis ein 
voller Sektor geschrieben werden kann (z.B. 512Byte). Dann braucht man 
weder viel RAM noch muss man Angst haben dass einem alle Daten flöten 
gehen.

P.S. der oben gezeigte Code von ihr ist zu 99% von der SD Lib (Arduino) 
Beispiel Datenlogger:
https://docs.arduino.cc/learn/programming/sd-guide

: Bearbeitet durch User
von Wolle G. (wolleg)


Lesenswert?

N. M. schrieb:
> Außerdem spricht sie von Wetterdaten, was zwangsläufig nicht nur die
> Temperatur sein wird.
> Zusätzlich wird man ab und zu eine richtige Uhrzeit abspeichern müssen.
> Der interne Quartz wird bei 10h weglaufen.
Bei Wetterdaten wird es wohl kaum auf Millisekunden oder Sekunden 
ankommen, sodass es reichen sollte, die Startzeit zu erfassen.

von N. M. (mani)


Lesenswert?

Wolle G. schrieb:
> Bei Wetterdaten wird es wohl kaum auf Millisekunden oder Sekunden
> ankommen, sodass es reichen sollte, die Startzeit zu erfassen.

Der Uno hat scheinbar ein Keramik Resonator mit drauf. 0,5% weicht der 
angeblich ab. Also 3 min / 10h. Da hast du also Recht.
Hatte ich übersehen.

Der interne RC Oszillator wird nämlich mit 7,3-8,1MHz angegeben. Anstatt 
10h können es also auch gerne Mal 10,875h sein. Fast eine Stunde mehr 
ist dann schon eine andere Hausnummer.

von Totomitharry (Gast)


Lesenswert?

Im Endeffekt steht alles im Datecalc beispiel in der library.

Man kann auch mit substring oder was auch immer den gespeicherten Text 
wie im geposteten Sketch auseinandernehmen und daraus ein Datetime 
Objekt erstellen.

Darauf ein timespan anwenden.

Ich denke das liegt der programmiertechnischen Lösung am nächsten.

Die billigen ds1307 sind auch nicht viel genauer wie die interne etc 
wenn man den Quarz nicht gegen einen Markenquarz tauscht der mehr wie 
das breakout Board kostet.

Mit dem ds3231 hat man 1 Minute pro Jahr Maximum.

von Totomitharry (Gast)


Lesenswert?

Außerdem kann es vorkommen das die rtc durch die vermehrten i2c abfragen 
Ticks verliert, also sollte man die interne rtc alle 15-20 Minuten mit 
der externen Uhr synchronisieren und diese nutzen.

Wenn es nur ein Lehrbeispiel/Aufgabe ist macht der Aufwand aber keinen 
Sinn.

von TotoMitHarry (Gast)


Lesenswert?

Adafruit RTClib (es gibt 4 verschiedene RTClib in verschiedenen 
Versionen, der Vergleich von Datetime Objekten ist ziemlich neu, in 
meiner Lib auf dem Rechner war es vor der aktualisierung nicht möglich.)

Erstellung eines DateTime Objektes mit gespeichertetr Zeit.

DateTime (uint32_t t=SECONDS_FROM_1970_TO_2000)
DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour=0, 
uint8_t min=0, uint8_t sec=0)
DateTime (const DateTime &copy)
DateTime (const char *date, const char *time)
DateTime (const __FlashStringHelper *date, const __FlashStringHelper 
*time)
DateTime (const char *iso8601date)(datumTzeit)

Danach geht der vergleich if(DateTime < > DateTime)

man kann aber auch mit der Klasse Timespan Zeit von einem DateTime 
Objekt  mit +- addieren oder hinzufügen.

also wäre logisch:
Datetime jetztbis = rtc.now() - TimeSpan(0,0,11,0)

Datetime LineFromFile("iso8160date"); // siehe oben

und dann:
if(LineFromFile>jetztbis)
.......

von DenkenMachtSpaß (Gast)


Lesenswert?

M.A. S. schrieb:

> Genau! Am besten definiert man die Zeit in Sekunden nach dem Urknall. :)

YMMD! :-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.