Ich schreibe gerade ein Arduino-Programm (Nano) für eine Füllstandsanzeige für eine Zisterne. Der Füllstand (in Liter und %) wird in der Garage an einem LCD-Display angezeigt.
Das ganze funktioniert auch bereits, ich würde nun noch gerne einen weiteren Punkt realisieren, und zwar einen zusätzlichen Anzeigewert : "Zulauf/Ablauf in den letzten 12 Stunden"
Ich denke das ganze könnte über einen FIFO-Puffer zu realisieren sein, ich weiß nur nicht, was ich dazu in der Arduino-IDE verwenden muss.
Ich denke es würde reichen, alle 5 Minuten den Füllstand (in Liter) einzulesen und dann in einen FIFO-Puffer zu schreiben.
Der Puffer müsste dazu also 144 Stellen haben.
Wenn der Puffer dann mit Werten gefüllt ist, würde das ja dann so aussehen:
Schau mal nach, wieviel RAM Dein Nano hat, und wieviel der Puffer belegt. Der Compiler sagt Dir auch, wieviel RAM noch frei ist.
Wenn Dein Puffer genau die letzten 12 Stunden enthält, dann ist der Anfangsstand (von vor 12 Stunden) genau in der nächsten Speicherzelle gespeichert. Welche zuletzt beschrieben wurde, das weiß Deine Schreibfunktion.
Hallo,
das hängt ein bisschen davon ab was Du überhaupt haben willst.
Man kann sich ja auch eine Lösung vorstellen bei der man nach 12 Stunde wieder bei Null anfängt Dann kann man einfach die Differenzen nach Zulauf / Ablauf trennen und die Summen bilden. Irgendwann muss man dann allerdings mal wieder von vorne starten.
Zulauf und Ablauf der letzten 12 Stunden stetig zu erfassen , da ist dann ein Ringpuffer schon eine gute Lösung. Dazu werden dann die Messwerte im Kreis herum in ein Array geschrieben. Damit man weiß wo man gerade ist nutzt man dazu einen Schreibzeiger der einem die nächste zu schreibende Position angibt. Bei 143 angekommen fängt man wieder bei 0 an. Beim Auslesen nutzt man eine Lesezeiger ab der letzten beschriebenen Position rückwärts beginnend. Rückwärts deshalb weil der letzte ja auf n-1 und der vorletzte auf n-2 steht. Eventuell sind ja auch noch nicht alle 144 Eintrag erfolgt. Zudem macht es Sinn das Array mit Werten zu initialisieren die eigentlich nicht sein können, z.B -16000, damit kann man dann bei der Auswertung erkennen das an der Position noch kein Eintrag erfolgt ist.
Über die Differenzen zwischen zwei Einträgen kommst Du an Zulauf oder Ablauf und über je die Summen dann an Dein Ergebniß. Aber das hast Du ja schon richtig erfasst.
wie man sowas in einem Sketch realisiert dafür wirst Du was im Netz finden.
Such mal nach Ringpuffer es gibt auch eine LIb dafür , aber das ist auch selbst gemacht kein Hexenwerk.
Noch ein Tipp wenn der Speicher knapp wird kannst Du ja auch alle 15 Minuten nutzen das ist sicher auch noch genau genug.
Nachtrag .
ich war jetzt davon ausgegangen das Du Zulauf und Ablauf getrennt haben wolltest.
Ja.
Ich sehe folgende Varianten als möglich an:
a) ohne Uhr
Du bekommst nur eine Schätzung, wann die Messung erfolgte. damit kannst Du aber auch nur schätzen, ob die Messreihe in Deine Vorauswahl reinpasst.
Der Grund ist, das millis() nicht unbedingt die tatsächlich vergangene Zeit in ms zurückgibt, sondern abhängig ist. (Quarz/Resonator, Timer/Interrupt ...)
b) mit Uhr
Du bekommst die Werte zeitgenau in wiederholbaren Intervallen
Allen gemein ist, das Dein Puffer so klein als möglich sein sollte um Speicher zu sparen, bei gleichzeitig größtmöglicher Aufnahmefähigkeit für die maximale Anzahl an Werten.
Wie hoch könnte denn die maximale Entnahme/Befüllung zwischen zwei Messpunkten sein?
Und dann ist noch die Frage, wie genau Deine Füllstadsangabe tatsächlich ist.
Geht das wirklich Litergenau?
Wenn Du den als Ringspeicher "die letzten 12 Stunden" nimmst, kannst Du anhand der Position im Array ermitteln, wo Du Dich gerade befindest und daraus auch einen Zwischenwert berechnen.
Die Ausgabe kann dann zum einen Ausgabe über alles sein, oder zurück für xxx Zeit, bis die Gesamtaufnahmezeit erfüllt ist.
Alternativ ginge auch einen Startpunkt zu setzen, z.B. Mitternacht, umd ab da aufzunehmen, darüber auch die Auswertung laufen zu lassen und wenn alle Elemente gefüllt sind, gehts los von vorn.
Die größte Schwierigkeit bleibt immer die Syncronisation mit der Realzeit.
Wenn man die denn real braucht. Hier wird oft mehr an Notwendigkeit rein "gewünscht", als notwendig ist.
Innerhalb von 12 Stunden sollte die Abweichung nicht zu groß werden.
Wie gesagt, wenn keine Bindung an die Realzeit ein Muss ist.
Dann würde ich eher den Weg über eine Datenbank mit NTP-synchronisierter Zeit gehen.
Im Prinzip brauchts da keine keine Uhrzeit im Hintergrund.
Wenn ich zB. morgens um 08:00Uhr auf das Display schaue, sehe ich wieviel der Regen über Nacht in die Zisterne nachgefüllt hat.
Oder schau ich zB. um 18:00Uhr abends aufs Display, kann ich sehen wieviel Wasser die Gartenbewässerung (die letzten 12 stunden über) benötigt hat.
deshalb die 12Stunden,... ich denke damit kann man Verbräuche bzw. zugewinne ganz gut sehen.
Eine "Nullung" nachts um 12Uhr will ich also definitiv damit nicht erreichen!
Deshalb war die Idee mit dem Fist-in-first-out. Alles was älter ist als die 12 Stunden fällt hinten raus.
Die Zisterne hat 12.000Liter, die Liter-genauigkeit ist mir relativ egal, auch wenn's um 150l daneben geht ist das relativ egal.
Ich will halt sehen, wieviel Wasser ich noch (grob) habe, ohne jedes Mal den Schachtdeckel im Hof öffnen zu müssen.
Die Füllstände sind eingeteacht (teachung bei leer (bzw. Min-Stand) und teachung bei Max-Level),
alles dazwischen mache ich mit der map-Anweisung.
Der Sensor gibt 0-5V raus und hat einen Messbereich von 0-5m. Natürlich hat der auch ne Toleranz, aber als grobe Hausnummer sicher nicht verkehrt.
Die LCD-Anzeige zeigt mir im Moment abwechselnd die berechnete Literzahl und einen Prozentwert (0Liter = 0%, 12.000l = 100%) an.
Ok.
Kannst Du mal ein paar Eckwerte geben?
Ich bräuchte den analogwert für leer und voll.
Vielleicht noch einen, von dem Du ungefähr weisst, das er bei 1/4 ode 3/4 ist.
Und ich brauche Dein Messintervall.
Ich würd dann versuchen, Dir was kurzes zusammenstellen.
Ich weiß nicht für was du die Werte brauchst, aber ich geb dir gerne die Info.
Der Behälter ist zylindrisch, also verläuft der Messwert auch linear zum tatsächlichen Füllstand.
Ich habe ca. 30 Inkremente wenn der Behälter leer ist, und ca 830 wenn er ganz voll ist.
Rest berechnet der Arduino bereits über die Map-Anweisung.
Für dich aber gerne noch: Halb voll wären dann= 430; viertel voll wären 230 ; dreiviertel voll wären 630.
Messen dann alle 15Minuten, also 4x pro Stunde. Wären dann nur 48 Messwerte. Sollte aber trotzdem passen.
Nochmal bezüglich der Zeit:
Im Prinzip ist mirs wurst, ob die programmierten 12 stunden nur 11std:55min sind oder 12std:20min. Der millis() ist da denke ich genau genug.
Au, die ist ja schon fertig. Ich kenn die Monoblock-Zylinder nur ohne Innenleben und ein paar 100er Löchern drin.
Ich hatte nur Ringe zum Versickern eingebuddelt. Von drinnen geschippt, bis der Ring gesackt ist (in der Brandenburger Sandbüchse kein Problem), nächsten Ring drauf usw. dann Dom und selber Löcher gebohrt....
das habe ich mir mal genommen und mir Gedanken gemacht.
Vom Prinzip her ist das nur ein Ringspeicher, bei dem Du ausgehend von der aktuellen Position einfach zurück rechnest.
Das ist soweit kein Problem. Die Logik kommt erst, wenn der Index des aktuellen Element kleiner als die Anzahl der aufzulistenden Elemente ist, weil dann vom "Ende" des vorhergehenden Ringes rückwärts die Startposition ermittelt werden muss, damit die Zu-/Abflüsse zeitlich zueinander passen.
Sehe ich aber auch nicht als Problem. Ist nur Mathe
Das was mir Fragezeichen ins Gesicht stellt, ist dein map()
Ich verstehe noch nicht ganz, wozu Du das brauchst und es birgt die Gefahr, das es zu einem Überlauf kommt, wenn nicht künstlich begrenzt.
Aber das klären wir heute abend - ich glaub eine bessere Variante bauen zu können, die darauf verzichtet
Ich weiß nicht warum du dich an dem Map so aufhängst?
Mit dem Map-Befehl rechne ich den Analogwert nur in den tatsächlichen Liter-Stand um.
Das geht ja bereits!
Mit dem eigentlichen Problem eine Historie der letzten 12 Stunden anzulegen hat das ja nichts zu tun!
AnalogMin und AnalogMax werden bei einteachen ermittelt und im Eeprom gespeichert.
int Fuellstand = analogRead(LevelSensor); // Analogeingang einlesen
Fuellstand = map(Fuellstand, AnalogMin, AnalogMax, 0, 12000); // Füllstand in Liter