Guten Samstag,
ich stehe vor folgender Herausforderung und weiß nicht recht wie ich es
machen soll.
Also ich soll bei aktivieren und deaktivieren einer Funktion die Uhrzeit
und das Datum speichern. Insgesamt sollen immer die letzten 30 ein und
aus gespeichert werden.
Ich dachte mir ich mach das so das ich mir ein Array mit 60 int32_t
anlege und den Timestamp beim einschalten auf die geraden stellen
speichere und beim ausschalten auf die ungeraden.
Nun zu meinem Problem wenn ich meine 60 Einträge habe soll ich den
ältesten überschreiben.
Was wäre ihr die sinnvollste Strategie? Soll ich die Daten des Array
dann so verschieben das das 58 und 59 frei werden und ich dann wieder in
58 und 59 rein schreibe?
Oder wie macht man das am sinnvollsten damit ich auch die Anzeige
richtig geordnet habe?
Hierzu gibt es bestimmt ein paar Tricks
der_Zwerg schrieb:> Was wäre ihr die sinnvollste Strategie?
Die allersinnvollste Strategie für deine Bemühungen wäre zu allererst,
nachzudenken.
Stattdessen fällt dir als Allererstes ein, daß du ein int32_t, also ein
long zu benutzen gedenkst. Wie kommst du darauf, so etwas als
Allererstes anzudenken?
Richtig wäre, wenn du dir als Allererstes Gedanken machen würdest, WAS
für ein Datum + Uhrzeit du speichern sollst. Also beispielsweise die
vergangenen Sekunden ab dem 1.1.1970 0.00 Uhr UTC. Kann aber auch sein,
daß du es in Millisekunden seit dem 1.1.2020 0.00 Uhr abspeichern
willst/sollst. Oder in irgend einer anderen Zeit-Notation - je nach dem
tatsächlich dahinterstehenden Zweck.
Dann käme als nächstes das Aufsetzen eines Structs, der den Zeitstempel
(in der von dir gewählten Notation) sowie einen Merker enthält, der da
aussagt Ein, Aus, undefiniert.
Danach kannst du dir einen Ringpuffer in einem EEPROM anlegen und ihn
mit Records {egal, undefiniert} initialisieren. Anschließend kannst du
dort lustig draufschreiben, indem du den jeweils ältesten Eintrag
überschreibst.
Fertig.
Bei sowas braucht man nicht einmal die 2 üblichen Zeiger eines
Ringpuffers, denn man weiß aus den Zeitstempeln ja bereits, wann was
gewesen ist und wo der Punkt im Ringpuffer ist, wo der Neuerste neben
dem Ältesten steht.
Also: immer zuerst nachdenken und nicht als Erstes mit irgend einem
int32_t hereinpoltern.
W.S.
W.S. schrieb:> Also: immer zuerst nachdenken und nicht als Erstes mit irgend einem> int32_t hereinpoltern.
Also soweit ich weiß wird die Unixzeit in einer 32 Bit variable
gespeichert.
Also habe ich dazu an ein int32 gedacht.
Und die Information des ein und aus kann ich ja mit gerader und
ungeradem Index des Array feststellen.
Also etwas hatte ich ja gedacht.
Das mit dem Ringbuffer war mir nicht klar.
da ich unbedingt auch die aufsteigende Sortierung benötige.
Werde mir den Ringbuffer jetzt ansehen.
der_Zwerg schrieb:> Also soweit ich weiß wird die Unixzeit in einer 32 Bit variable> gespeichert.
Das war mal und ist längst schon 64 Bit, weil es mit 32 Bit 2038 zum
Überlauf kommt. Betroffen davon sind allerdings viele Geräte mit
embedded Linux, welche 32-bittig laufen. Bis 2038 dürften die sich aber
ohnehin erledigt haben.
Nop schrieb:> Das war mal und ist längst schon 64 Bit
Auf einem 8bitter Atmega bleibe ich aber trotzdem bei 32Bit.
Habe mir jetzt den Ring buffer angesehen.
Aber der Ringbuffer birgt einige Fallstricke.
Wenn ich mit dem Ringbuffer arbeite darf ich nur den Schreibe Zeiger
verwenden. Denn wenn ich auch den Lesezeiger verwende kann ich nur
einmal die Daten raus hohlen oder habe ich da was falsch verstanden?
Würdet ihr dann für die Anzeige Das Array sortieren?
Danke für die Hilfe
der_Zwerg schrieb:> da ich unbedingt auch die aufsteigende Sortierung benötige.
Ringpuffer; der Schreibindex i auf das Array[i] zählt eben von 0...59
und weiter mit 0. (i++; if (i>59)i=0;)
Genau so machst du es mit dem Leseindex. Je nach dem, ob du mit den
neuesten beginnen willst oder mit dem ältesten der Ausgabe zählst du
halt vorwärts oder rückwärts.
Unabhängig davon kannst du auch das Feld in jedem Zustand kopieren und
sortieren, denn die Einträge sind ja die Zeit.
W.S. schrieb:> Danach kannst du dir einen Ringpuffer in einem EEPROM anlegen und ihn> mit Records {egal, undefiniert} initialisieren.
AUA.
Das Ding ist je nach Arbeit nach 2 Tagen Schrott. EEPROM halten nach
Aussagen in 1000 Foren nur eine ziemlich eingeschränkte Zeit.
Lass das ganze im Ram arbeiten, oder schreibe es auf eine SD-Karte.
Ganz normale Text-Datei im Append-Modus. Mit einen Zähler kannst du
verhindern das die Datei platzt.
Beim Neustart einfach die letzten X Einträge lesen und neue Datei
aufmachen und die alte Löschen. Das war's.
Wenn du es im Ram machst, brauchst du nur ein Array mit X Einträgen und
einen Zähler.
Sub schreibe
X = x + 1
ich x = 61 then x = 1
arry(x) = Uhrzeit
end sub
Fertig.
der_Zwerg schrieb:> Aber der Ringbuffer birgt einige Fallstricke.> Wenn ich mit dem Ringbuffer arbeite darf ich nur den Schreibe Zeiger> verwenden. Denn wenn ich auch den Lesezeiger verwende kann ich nur> einmal die Daten raus hohlen oder habe ich da was falsch verstanden?
Lies meinen Beitrag noch einmal. Du hast ihn nämlich garnicht
verstanden. In dem Ringpuffer, der hier nur mit einem einzigen Index
auskommt. Im Puffer kannst du nur Structs haben, die als Merker "ein",
"aus" oder "undefiniert" beinhalten. Also kannst du dir einmal nach dem
Einschalten die 60 Einträge anschauen und dir die Stelle des Neuesten
merken. Das ist dein Index, quasi der Zeiger auf den Hotspot, wo der
allerneueste Eintrag steht. Alle weiteren Einträge kommen dahinter, eben
einfach der Reihe nach. Und wenn der Index bei 59 angekommen ist, dann
landet der nächste Eintrag eben bei 0, dann der nächste bei 1 und so
weiter, immer im Kreis herum.
W.S.
Schlaumaier schrieb:> Lass das ganze im Ram arbeiten
Dann ist es weg, wenn der Strom ausfällt oder neu gestartet wird.
> oder schreibe es auf eine SD-Karte.
µC-basierte Lösungen haben selten eine SD-Karte, und bei einem Raspi
würde man nichts von EEPROM schreiben.
Idealerweise vereint man beides, indem man einen Powerdown-Interrupt
hat, der bei Stromausfall die Daten aus dem RAM ins EEPROM schreibt,
sofern die dort gespeicherten Daten nicht identisch zur RAM-Kopie sind.
Während dieser Zeit läuft der Controller noch aus einem passend
dimensionierten Kondensator.
Nop schrieb:> Idealerweise vereint man beides, indem man einen Powerdown-Interrupt> hat, der bei Stromausfall die Daten aus dem RAM ins EEPROM schreibt,> sofern die dort gespeicherten Daten nicht identisch zur RAM-Kopie sind.
Das wäre wirklich ideal. Weil das passiert nicht so häufig und deshalb
wird der EEPROM geschont.
Ich habe mit dem internen EEPROM der AVRs noch kein Problem bekommen,
auch nicht mit einem fortlaufenden Protokoll in einem externen seriellen
EEPROM über nun ca 15 Jahre. Aber es gibt auch persistente FRAMs ähnlich
externen seriellen EEPROMs mit faktisch unbegrenzten Schreibzyklen.
Edit: Das erwähnte externe EEPROM fürs Protokoll arbeitet mit Einträgen
fester Länge als Ringpuffer. Für die Timestamp habe ich das FAT Format
genutzt, das auf 2 Sekunden auflöst:
http://ntfs.com/exfat-time-stamp.htm
hm ok.
Ich habe aber schon gelesen das das EEPROM des Arduino nach 500
Schreibversuchen die Flügel hängen lässt.
Und das kann wenn man alle paar Sekunden was schreibt, dann ziemlich
schnell passieren.
Anders herum ;) meine SSD-Platte würde bei 500 Schreibzyklen es nicht
einmal wagen in die Nähe meines PC zu kommen. ;)
Mal rechnen. Das externe EEPROM ist ein AT24C256, 32KB mit 1 Mio
garantierten Schreibzyklen. Ein Eintrag ist 8 Bytes gross, d.h. auf 4096
Einträge kommt ein EEPROM-Zyklus, insgesamt also 4 Milliarden Einträge.
Wenn jede Sekunde ein Eintrag geschrieben wird, reicht das 130 Jahre.
Schlaumaier schrieb:> meine SSD-Platte würde bei 500 Schreibzyklen es nicht> einmal wagen in die Nähe meines PC zu kommen. ;)
Das heute übliche TLC Flash liegt in dieser Grössenordnung. ;-)