Hallo zusammen,
ich überwache derzeit ein Pumpsystem via Arduino Mega Board(ATmega
2560). Bei einer Warnmeldung erhöhe ich einen Counter. Bei 13
detektierten Meldungen soll eine LED leuchten.
Die Sache ist jetzt nur: Wenn ich mein Board mal vom Gerät entferne oder
es zu einem Stromausfall kommt, sollten mein gezählten Alarmmeldungen
nicht einfach verschwunden sein.
Allerdings kann ein EEPROM nur begrenzt beschrieben werden und das Ganze
soll lange, sehr lange funktionieren. Eine direkte Speicherung in den
EEPROM kommt daher wohl nicht in Frage.
Wie kann ich einen bevorstehenden Spannungsabbruch softwaretechnisch
detektieren und wie muss ich meine zuvor in den SRAM gespeicherten
Variablen modifizieren, sodass ich diese in den EEPROM speichern kann
und bei wieder vorhandener Spannung wieder aufrufen kann.
ICH HAB NULL PLAN und würde mich freuen, wenn mir jemand weiterhelfen
könnte.
Grüße,
Klaus
Prinzipiell:
Spannung für uC muss gepuffert werden (Akku oder Goldcap), denn du
brauchst ja noch Zeit, wenn der Strom weg ist.
Der uC muss erkennen, wenn der Strom weg ist, und dann die Werte ins
Eeprom schreiben. Geeignet sind hierfür AD Wandler oder Comparator, die
an der ungepufferten Spannung "lauschen".
Du kannst ja mal im Code der diversen Uhren hier stöbern, da haben viele
eine Gangreserve nach diesem Prinzip.
Viele Grüsse,
egberto
Der Grundwiderspruch ist, das einerseits eine Aktion erfolgen soll, wenn
der Strom abgeschaltet wird, aber andererseits für die diese Aktion auch
Strom benötigt wird.
Je nach den Umständen kann dieser Widerspruch wie folgt aufgelöst
werden.
Es gibt dabei zwie Ansätze denen folgender Gedanke zugrunde liegt: Die
Stromquelle wird in eine "eigentliche" und eine "uneigentliche"
aufgeteilt.
Die eigentliche Stromquelle kann bzw. wird hart abgeschaltet. Wenn Strom
weg, dann weg.
Die "uneigentliche" Stromquelle liefert aber noch eine Zeitlang Strom
wenn die eigentliche Quelle abgeschaltet ist.
Im einfachsten Falle ist die uneigentliche Quelle ein grosser
Kondensator. Es kann sich auch um einen Akku oder eine Batterie handeln.
Die Schaltung wird nun neben der "uneigentlichen" Quelle um einen Teil
erweitert, der detektiert das die eigentliche Quelle abgeschaltet wurde.
Mit einem Kondensator oder eine Batterie bleibt dann noch Zeit um die
Daten in das EEPROM abzuspeichern.
Die RAM-Variablen brauchen dafür nicht verändert zu werden.
Je nachdem ob sehr viele oder sehr weniger Daten gespeichert werden
müssen ist entweder die kondensatorlösung ausreichend oder es muss die
Batter/Akku-Lösung genommen werden.
---
Was die Frage betrifft wie oft im EEPROM geschrieben werden kann und wie
man damit umgeht, so gibt es dazu Application Notes von Atmel.
Grundsätzlich sollte man erstmal feststellen wie oft der Stromausfall
(absichtlich/gewollt) auftritt bzw. wie oft er wahrscheinlich
(unabsichtlich) auftritt .
Im Datenblatt steht die Anzahl der zulässigen Schreibzyklen (ich weiss
sie jetzt nicht auswendig). Diese beiden Zahlen setzt man in Relation zu
den oben ermittelten Häufigkeiten und kann daraus die Laufzeit errechnen
wie lange das EEPROM speichern klappt. Falls das so nicht ausreicht gibt
es eine Reihe von Strategien von denen eine in der genannte Application
Note beschrieben ist. Falls diese nicht passt, frag hier bitte nochmal
und beschreibe das Problem dabei.
Zuerst muss man aber mal feststellen wieviele Daten gespeichert werden
sollen. Es lohnt sich oft auch einmal festzustellen welche Bits der in
Frage kommenden Variablen sich überhaupt verändern. Läuft z.B. ein Index
ohnehin nur von 0 bis 15, dann kann man diese geschickt umverteilen oder
mit anderen Werten kombinieren.
>Allerdings kann ein EEPROM nur begrenzt beschrieben werden und das Ganze>soll lange, sehr lange funktionieren. Eine direkte Speicherung in den>EEPROM kommt daher wohl nicht in Frage.
Auch dafür gibt es Lösungen. Ein externes SPI FRAM ist unbegrenzt
schreibbar. Das geht verdammt schnell. Eine frühzeitige Erkennung
das die Stromversorgung ausfällt muss man da aber auch implementieren.
Mit wie vielen Fehlern rechnest du denn pro Tag in etwa?
Grund meiner Frage: Im Datenblatt werden die Schreibzyklen des EEPROMs
mit 100.000 angegeben. Bei 10 Fehlern am Tag würde es mehr als 13 Jahre
dauern bis du 50.000 Mal ins EEPROM geschrieben hast, falls du jedes Mal
direkt schreiben würdest und nicht erst bei Wegfall der Spannung.
Falls dir das nicht reicht und du genügend EEPROM zur Verfügung hast,
nimmst du einfach mehrere Adressen. Du schreibst deinen Fehler ins
EEPROM und speicherst dir wie oft du diese Stelle schon beschrieben
hast. Bei einem bestimmten Wert fängst du an, an eine andere
EEPROM-Adresse zu schreiben. Dadurch kannst du das ganze noch länger
hinauszögern.
Prinzipiell würde ich einen interrupt-fähigen GPIO nehmen und diesen
(ggf. über Spannungsteiler, Schutzbeschaltung etc.) an den
Versorgungsspannungseingang hängen. Nach diesem Abgriff kann man z.B.
eine Diode hängen, welche nachfolgende Pufferkondensatoren vom Eingang
entkoppelt (bei Ausfall der Versorgung).
In der SW musst du dann nur noch beim Auftreten eines externen
Interrupts die Daten in den EEPROM schreiben. Natürlich solltest du die
Gesamtkapazität der Kondensatoren so auslegen, dass sie für die hierfür
benötigte Zeit dein System noch versorgen können.
Beste Grüße...
Hallo,
zunächst einmal vielen Dank für die Antworten!
Mein Hauptproblem bei der ganzen Sache ist eigentlich das
softwaretechnische detektieren des Spannunsabbruchs und das Schreiben
und Holen der Variable in bzw. aus den EEPROM.
Wenn die Spannung wieder vorhanden will ich wieder mit dem zuvor
gespeicherten Wert weiter arbeiten, ohne sie dabei immer wieder in den
EEPROM schrieben zu müssen.
Spannungsabbruch -> Detektieren -> Speichern in EEPROM --> Spannung
wieder da -> gespeicherter Wert aus EEPROM holen und wieder in SRAM
speichern
Gibt es hierzu Codebeispiele in C? Ich stelle mir das nicht so einfach
vor.
VG
Nochmal die Frage von Thorsten:
Thorsten schrieb:> Mit wie vielen Fehlern rechnest du denn pro Tag in etwa?
Bei 4 kByte EEPROM kannst du, falls nicht tausende von Warnmeldungen pro
Tag auflaufen, ausreichend Schreibzugriffe "frei", um über dutzende von
Jahren deine Warnungen sofort im EEPROM zu verewigen. Bei passendem
Wear-out Management sollte das normalerweise kein Problem sein.
Warum also der Aufwand mit "Notstromversorgung" für's Schreiben. Oder
möchtest du das aus "sprotlichem Ehrgeizt" über NSV lösen? Wieviele
Warnungen kommen denn bei deinere Anlage und wieviel EEPROM hättest du
für die Warnungen frei.
MfG
Das selbe Problem habe ich bei einem Alarmanlagenprojekt auch gehabt.
Weil die Sensoren und ein Teil der Schaltung mit 12 funktionieren, habe
ich die Speisung auf 12V ausgelegt.
Über eine Diode wird ein Elko geladen, welcher den Controller nach einem
Stromausfall noch ein Weilchen am Leben hält. Der Rest der Schaltung ist
aber sofort ausser Betrieb.
Über einen Optokoppler (kann auch ein Spannungsteiler sein) werden die
"direkten" 12V aus dem Netzgerät überwacht und bei deren Ausfall
schreibe ich die Zählerwere und Statusbits ins EEPROM.
Beim nächsten Start lese ich die Daten ins RAM und arbeite damit weiter
bis zum nächsten Stromausfall...
Wenn Du einiges an EEPROM-Speicher verfügbar hast (nicht für andere
Zwecke brauchst) dann wäre vielleicht folgendes eine Lösung.
Ich weiss nicht wie hoch Dein Zählerstand werden kann, sollten 32768
reichen, dann kannst Du die Daten in Words ins EEPROM ablegen.
Wenn Du z.B. 80 Bytes frei hast, kannst Du also 40 Words ablegen => bei
40 ändernden Zählerständen wäre jede Speicherzelle einmal beschrieben
worden.
Bei mir läuft es folgendermassen. Ist bei der ersten Word-Speicherstelle
das 16.Bit = 0 so fahre ich weiter bis an die erste Adresse mit einem
gesetzten Bit.
Tritt ein Ereigniss ein, so lege ich dort den inkrementierten
Zählerstand mit GELÖSCHTEM Bit ab. dies geschieht, bis die letzte
Adresse ebenfalls mit einem gelöschten Bit versehen ist.
Bei erneut eintretendem Ereignis wird dann der aktuelle Zählerstand mit
gelöschtem Bit an der ersten Stelle abgelegt und das ganze beginnt von
vorne.
So kannst Du die Anzahl der Schreibzyklen runterbrechen, wenn genügen
EEPROM-Speicher verfügbar ist.
Ich weiss nicht, wie die atmels das lösen, aber bei den zilogs
gibt es ein "Voltage brown out". Das ist ein hochpriorer Interrupt,
der ausgelöst wird, sobald die Spannung unter eine Schwelle rutscht.
Wenn die Spannung entsprechend gepuffert ist und langsam genug
abfällt (gold-cap), kann man in der irq-Routine noch gemütlich alles
aufräumen.
Wenn Dein Problem nur das Detektieren eines Stromausfalles ist, dann
würde ich wie folgt vorgehen.
Die ungepufferte Spannung über einen Spannungsteiler oder Optokoppler
auf einen Eingang verbinden.
Wenn Du nicht sinnlos lange Routinen programmiert hast und die
Programmzyklen einigermassen kurz sind, kannst Du den Eingang zyklisch
abfragen und bei je nach Beschaltung bei einer 1 oder einer 0 die Daten
ins EEPROM schreiben und auf den Spannungsausfall warten.
Sollte dies nicht der Fall sein, könnstest Du das ganze auf einen
Eingang mit Interrupt schalten.
Dann würde ich nach dem Initialisieren der Controller Hardware (im
ersten Zyklus => beim Hohfahren) kurz die gewünschten Daten aus dem
EEPROM ins RAM laden und dann kannst Du weiterarbeiten.
Hallo,
danke für die Antworten.
Es hat sich nun noch zusätzlich was ergeben: Ich muss noch weitere Daten
untersuchen und speichern.
Sprich, ich muss den Counter-Wert und ein ca. 34 Zeichen ,langer String
speichern.
Nach dem Spannungsabbruch sollen die letzten empfangen Daten und der
Counter-Wert noch vorhanden sein.
Ich verwende den ATmega 2560 mit 4 kBytes EEPROM. Die Daten empfange ich
mit 9600 bps und je nach Situation kann an es an einem Tag gut zu 100
Alarmmeldungen kommen. Allerdings soll nach 13 detektieren Ereignissen
der Counter wieder auf Null gesetzt werden und von vorne gezählt werden.
Gibt es da schon fertige Baugruppen mit der ich einen Offsetwert
einstellen kann und mir eine log 1 oder 0 an meinen Eingang sendet und
ich die Daten in den EEPROM speichern.
Mit dem Speichern in den EEPROM hab ich noch Null Ahnung...
Das speichern in den EEPROM erfolgt das nach den Bsp. im Datenblatt,
also so?
void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
/* Wait for completion of previous write */
while(EECR & (1<<EEPE))
;
/* Set up address and Data Registers */
EEAR = uiAddress;
EEDR = ucData;
/* Write logical one to EEMPE */
EECR |= (1<<EEMPE);
/* Start eeprom write by setting EEPE */
EECR |= (1<<EEPE);
}
Was muss ich aber als uiAddress angeben?
Ich weiß nicht, warum Du Dir so viel Stress machst.
Wenn Du nicht in ein EEPROM schreiben willst, dann nimm doch einfach ein
batteriegepuffertes RAM: Microchip 23K640. Kapazität 8k. Ansteuerung
über SPI, Pinout wie ein SPI-EEPROM.
Das Ding hat einen Standby-Verbrauch von 1 uA gemäß Datenblatt. Wenn Du
eine normale CR2032 Knopfzelle als Backup nimmst, hat diese
üblicherweise eine Kapazität von etwa 200 mAh. Das heißt, diese
Knopfzelle könnte 200h lang 1 mA liefern, oder eben 200000h lang 1uA.
200000h sind über 20 Jahre. Selbst wenn es nur die Hälfte ist
(Selbstentladung), dürfte das für Dich gut ausreichen.
Zur Versorgung des Speicherbausteins hängst Du deine normale
Stromversorgung und die Knopfzelle über eine BAT54C Doppeldiode an VCC
vom Speicher. Einmal 100n gegen Masse und Pullups an alle Eingänge
(damit der Chip wirklich passiv ist, wenn er über die Batterie versorgt
wird), und das wars dann.
Es gibt ansonsten auch FRAMs. Die werden wie EEPROMs verwendet, aber das
Schreiben geht so schnell wie bei RAM, und die Schreibzyklen sind fast
unbegrenzt, aber der Speicherinhalt bleibt auch ohne Strom erhalten.
fchk
Der EEPROM des ATmega 2560 hat 4KB.
Ein 13 Zeichen String hat 13 Byte, dazu ein 8 Bit Zähler sind wir bei 14
Byte.
Dem fügen wir noch ein 2 Byte Counter für ein Wear-Level-Managing hinzu,
umsetzen dann folgendermaßen:
Der 4KB Speicher wird logisch in 256 Zellen geteilt (4KB / 16Byte =
256), in die die genannten Werte passen.
Nun speicherst du bei jedem Alarm deinen String und deinen Counter in:
a) eine freie Speicherzelle (16 Bit Counter = 0)
b) in eine Speicherzelle mit dem kleinsten Wear-Level-Counter
Auf den größten Counter-Wert (65535) folgt als nächstes die 1, da die 0
für ungenutzte Stellen steht (noch nie beschrieben).
Dies hat den Vorteil, dass du beim Schreiben von neuen Daten nicht die
alten Daten löschen musst (weitere Schreiboperation) sondern diese
automatisch ungültig werden, wenn es einen Eintrag mit einem höheren
Wear-Level-Counter gibt.
Hast du nun also den Strom verloren, sind alle Daten trotzdem immer
persistent im EEPROM (ohne Zusatzschaltung für die Stromsicherung),
bekommt dein Mikrocontroller nun wieder Strom suchst du einfach linear
in den 256 Zellen nach dem Eintrag mit dem höchsten Wear-Level-Counter
und du hast deine Daten wieder.
Zusätzlich hast du auch noch alle 255 älteren Eintrage, ist das nicht
wunderbar ;)
Die Lebenszeit davon ist auch gigantisch, du hast 256 Zellen mal 100.000
Schreibzyklen, dies entspricht 25.600.000 Alarmmeldungen die du
speichern kannst ;)
Damit du den EEPROM in der Produktlebenszeit (10 Jahre) kaputt bekommst,
müssten es 7.013 Alarmmeldungen sein, also alle 12 Sekunden ein Alarm,
unmöglich :)
Ich habe eben gerade noch festgestellt, dass der Ansatz nicht ganz
reibungslos funktioniert:
Bei einem Überlauf haben die neuen Werte natürlich einen kleineren
Wear-LEvel-Counter und würden somit ignoriert, also vereinfach den
Ansatz und nimm ein 4 Byte unsigned Counter, der EEPROM ist viel
schneller kaputt als dass der Counter die 4,2 Milliarden Grenze
erreicht.
Zusätzlich lässt sich das finden der Speicherzelle vereinfachen indem
nur nach dem kleinsten Counter gesucht werden muss, denn die Methode b)
implimiziert bereits die Methode a) da 0 die kleinste unsigned Zahl ist.