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
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. |
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.
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.
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
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
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
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.
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?
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.
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.
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. :)
Gibt es nen Grund warum hier alle die standard libs so sehr hassen? Warum nicht einfach ganz normal tm/mktime aus <ctime>?
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.
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.
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...
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.
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.
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.
Was fuer eine schwache Idee auf einem Logger ein File und eine Datenbank zu verwenden, wenn man doch gleich ein Array verwenden kann.
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.
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.
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} |
Korrektur, muss nach ganz oben vor die Schleife
1 | DateTime temp= rtc.now() - TimeSpan( 0, 11, 0, 0 ); //zieht 11 Stunden ab |
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!
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
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.
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.
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.
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.
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 ©) 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) .......
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.