Fehler abfangen/aufzeichnen

Hallo,
ich habe gestern abend einen neuen Sketch auf den Arduino geladen, der zu
bestimmten Zeiten, bestimmte Dinge schalten/überprüfen soll.
Ich habe mich einige Tage damit geplagt Fehler abzufangen um das ganze sicher
zu machen. ICH weiß genau, das dieser Sketch fehlerfrei ist. Und!1??

Heute morgen- Fehler. Der Sketch vagabundiert vor sich hin- und der Arduino
zeigt mir auf seinem Display "Du kannst mich mal- dä, dä, dää…
Was war passiert? Stromausfall, den ich nicht bemerken konnte.

Wie fange ich denn so etwas ab? Ich habe mir folgendes überlegt:
Wenn der Sketch startet, dann wird ein Zeitstempel in einen nichtflüchtigen
Speicher geschrieben. Jetzt fällt der Strom aus- nach einer unbestimmten
Zeit fährt der Sketch wieder hoch, setzt einen zweiten Zeistempel.

Wenn der Sketch hochfährt, müßte er im externen Speicher nach einem zweiten
Zeitstempel schauen. Findet er diesen, müßte eine Abfrage auf dem Display
erscheinen "Fehler Spannungsversorgung" "Programm starten?" "J/N"
Nun müßte er auf "J/N" warten, oder selbstständig nach einer Zeitspanne den
Sketch ausführen.

Was benutze ich denn am besten als externen Speicher?
Ich habe mir gedacht, das man es auf SD-Card ablegen könnte. Das kann ich und
es ist einfach.
Eleganter wäre es aber, einen 24LC128 über I2C zu nutzen.
Nur wie sage ich dem "Stromausfall 10:37h"
oder "Badewanne übergelaufen 20:07h"
das ist doch BitFrimelei, da habe ich keine Ahnung von.
Wie geht denn so etwas. Gibt es da ne´fertige Lib für, so in der leichen Art
wie für SD-Card?
Gruß und Dank
Andreas

Hast du ein RTC Modul dran für einen Zeitstempel?

Speichern kannst du es doch einfach auf dem Eeprom vom Atmega. Da braucht es nichts externes.

Das ganze nur als Pseudo:

void setup()
// eeprom auslesen
eeprom_value[1] = eeprom_value[0]; // Wert 1 an Wert 2 übergeben
eeprom_value[0] = time; // aktueller Wert

Ohne zu extrem zu optimieren kannst du 3 Bytes spendieren:

  1. Byte: Fehler Code
  2. Byte: Stunden
  3. Byte: Minuten

Wenn du nicht allzuoft schreibst kannst du auch das interne EEPROM verwenden. Wenn du nur beim Start und vielleicht im Fehlerfall was schreibst, sollte das problemlos gehen.

Ansonsten gibt es noch FRAM. Das vereint die Geschwindigkeit und Robustheit (> 10 Milliarden Schreibzyklen) von SRAM mit der nicht-Volatilität von EEPROMs:

http://www.reichelt.de/FM-24C16B-G/3/index.html?&ACTION=3&LA=446&ARTICLE=146569&artnr=FM+24C16B-G&SEARCH=FM+24

Hallo,
an den ArduinoSpeicher will ich nicht ran. Kann man machen, muß man aber nicht.
Frag mich mal, gefällt mir nicht…

Das FM24C16 ist aber eine interessante Sache. Und den Fehler als Code zu
hinterlegen erspart viel gefummel.

Ich bräuchte nur Zahlen zu speichern:
6 Ziffern für das Datum
4 oder 6 Ziffern für die Zeit
3 Ziffern für den Fehlercode
Auswerten dann im Sketch.
Das ist kein Problem, das kriege ich hin.
Gruß und Dank
Andreas

Warum wollst du an den Eeprom Speicher nicht ran? Verstehe ich nicht.

Würd ich auch über den EEPROM machen. Dazu ist der schliesslich da-warum sollte der sinnlos auf dem Board rumsitzen?
Er ist mit bezahlt, also kann er auc h genutzt werden. Kompliziert isses auch nicht, und wenn man will, kann man ja die Speicherstelle jedes Mal wechseln, dann macht der das bisschen nen paar hundert Jahre mit.

Hallo,
den kann man später vielleicht mal für etwas zeitkritisches benutzen, oder für etwas wirklich "wichtiges".
Schau´n wir mal...
Gruß und Spaß
Andreas

Naja-wenn du solche Mühen auf dich nimmst, dann scheints wichtig zu sein. :wink:
Ich hab z.B. die Konfiguration meiner Uhr im EEPROM liegen (Alarmmodus, Displaymodus, sowas).
Somit sind die Einstellungen auch noch da, wenn ich mal das Netzteil abgezogen hatte.

Und wegen dem "Verschleiss": rechne mal, wie oft pro Stunde du den neu schreiben müsstest (lesen geht verschleissfrei!), damit der in absehbarer Zeit "kaputtgeht" (in Wirklichkeit geht der nicht schlagartig kaputt, sondern kann dann nur manchmal was "vergessen"). Wahrscheinlich brauchst du nicht mal nen Ringpuffer.

Da kannste über 11 Jahre jede Stunde den Wert überschreiben. Der Atmega hat einen 1024 Byte EEprom Speicher. Sehe überhaupt keinen Sinn, das nicht so zu machen.

Hallo,
Mühe macht es nicht. Ob ich nun den internen Speicher des Mega nutze oder
den I2C-Speicher wird sich vom programmieren nicht viel nehmen.
Bei wenig Schreib-Zugriffen wird der "Mega" schon ewig halten, das ist mir klar.

Mit dem I2C werde ich das schon hinbekommen, beim Mega kenne ich mich noch
nicht aus.
Nein, gefällt mir nicht. Wer weiß wozu ich den noch nutzen könnte.
Gruß und Dank
Andreas

Für sowas :smiley:

Wobei, der Atmega hat sogar 4kB Eeprom onboard. Mit Atmel Studio und ISP ist es auch garkein Problem, solange der Atmega okay ist (gleiches gilt auch für einen externen Speicher), diesen Eeprom auszulesen und auf dem System abzuspeichern.

http://playground.arduino.cc/code/I2CEEPROM
Das schon gesehen? Das Teil kostet knapp 2€

Und wie schauts damit aus, den Status vom Taster ins EEPROM zu speichern?
Man macht zwar nicht jede Stunde das Licht an aber.....

Hallo,
ja- jaa! Ihr ScherzKekse. Macht euch nur lustig. :stuck_out_tongue:
Die Arduino Seite kannte ich noch nicht, habe hier bei mir aber etwas ähnliches.

/*
 * I2C EEPROM sketch
 * this version for 24LC128
 */
#include <Wire.h>

const byte EEPROM_ID = 0x50;      // I2C address for 24LC128 EEPROM

// first visible ASCII character '!' is number 33:
int thisByte = 33;

void setup()
{
  Serial.begin(9600);
  Wire.begin();

  Serial.println("Writing 1024 bytes to EEPROM");
  for (int i=0; i < 1024; i++)
  {
    I2CEEPROM_Write(i, thisByte);
    // go on to the next character
    thisByte++;
    if (thisByte == 126)   // you could also use if (thisByte == '~')
      thisByte = 33;     // start over
  }

  Serial.println("Reading 1024 bytes from EEPROM");
  int thisByte = 33;
  for (int i=0; i < 1024; i++)
  {
    char c = I2CEEPROM_Read(i);
    if( c != thisByte)
    {
      Serial.println("read error");
      break;
    }
    else
    {
      Serial.print(c);
    }
    thisByte++;
    if(thisByte == 126)
    {
      Serial.println();
      thisByte = 33;     // start over on a new line
    }
  }
  Serial.println();
}

void loop()
{

}

// This function is similar to EEPROM.write()
void I2CEEPROM_Write( unsigned int address, byte data )
{
  Wire.beginTransmission(EEPROM_ID);
  Wire.write((int)highByte(address) );
  Wire.write((int)lowByte(address) );
  Wire.write(data);
  Wire.endTransmission();
  delay(5); // wait for the I2C EEPROM to complete the write cycle
}

// This function is similar to EEPROM.read()
byte I2CEEPROM_Read(unsigned int address )
{
  byte data;
  Wire.beginTransmission(EEPROM_ID);
  Wire.write((int)highByte(address) );
  Wire.write((int)lowByte(address) );
  Wire.endTransmission();
  Wire.requestFrom(EEPROM_ID,(byte)1);
  while(Wire.available() == 0) // wait for data
    ;
  data = Wire.read();
  return data;
}

"Taster ins EEPROM zu speichern"
Das wäre eine Möglichkeit, ich könnte dann nachschauen welcher von meinen
fünf das Licht, oder Andere ausschaltet. ]:smiley:
Gruß und Spaß
Andreas

SkobyMobil:
"Taster ins EEPROM zu speichern"
Das wäre eine Möglichkeit, ich könnte dann nachschauen welcher von meinen
fünf das Licht, oder Andere ausschaltet. ]:smiley:

Nach Deinen gestrigen Ausführungen in Zeitschaltuhr mit DCF77 - #8 by SkobyMobil - Deutsch - Arduino Forum verstehe ich allmählich, was für ein Problem Du mit Deinem Sketch eigentlich hast und weshalb Du so auf so merkwürdige Ideen zum "Fehler abfangen/aufzeichnen" kommst.

Du hast bei einer Stromunterbrechung offenbar das Problem, dass
a) die Schaltzeiten Deines Schaltprogramms nirgendwo in einem nichtflüchtigen Speicher hinterlegt sind
b) Dein Schaltprogramm seinen beabsichtigten Schaltstatus nur annimmt, wenn die aktuelle Sekunde über die Schaltzeit läuft

Punkt a) erschlägst Du damit, dass Du die eingestellten Schaltzeiten in einem nichtflüchtigen Speicher wegspeicherst. Wenn die Schaltzeiten nicht fest im Sketch eingetragen werden sein sollen, käme dafür der EEPROM-Speicher des Controllers in Frage. Falls eine DS1307 RTC zum Einsatz kommt, hätte man in der DS1307 auch 56 Bytes batteriegepufferten Speicher zur Verfügung, was zum Beispiel bei einer Tageszeitschaltuhr ausreichen würde, um 28 Integerwerte für minutengenaues Schalten oder 14 long Werte für sekundengenaues Schalten zu hinterlegen. Das EEPROM des Controllers ist viel größer und kann demzufolge viel mehr Schaltzeiten speichern (UNO = 1024 Bytes).

Falls Du wegen der begrenzten Schreibzyklen bei einem EEPROM-Speicher Bedenken hast: Man kann eine Schaltzeiten-Programmierung auch so machen, dass man die Schaltzeiten per Tastendruck zunächst mal nur im RAM-Speicher wegspeichert und ein Flag setzt, dass die Schaltzeit geändert wurde. Und wenn dann 10 Minuten lang nichts an den Schaltzeiten verändert wurde und das Geändert-Flag gesetzt ist und 10 Minuten lang keine Schaltzeit geändert wurde, speichert man die neuen Schaltzeiten im EEPROM. Dann braucht man nicht bei jedem Tastendruck die Änderung ins EEPROM schreiben und spart Schreibzyklen ein.

Punkt b) erschlägst Du mit einer Programmlogik, die das Schaltprogramm sofort mit dem gewünschten Schaltstatus wiederherstellt, wenn der Controller nach einer Stromunterbrechung wieder startet. Beispielcode zum Schalten nach Zeit und Schaltprogramm, ohne dass die Echtzeit über eine programmierte Schaltzeit drüberlaufen muss, siehe in dem oben verlinkten Thread.

Hallo,
Du- schon wieder, das ist immer so anstrengend mit Dir. :wink:
Was bestimmt nichts schlechtest ist, es schafft ja was weg.

Schaltuhr: (Zeit-Quelle, ChronoDot)
Wenn der Arduino hochfährt sind keine Schaltzeiten im Sketch hinterlegt.
Die Schaltzeiten setze ich mit Taster in der Funktion "Schaltuhr", diese
werden dann als String im flüchtigen Speicher gehalten.

Wenn der Controller um 15:23:18h hochgefahren wird, ich aber eine
Einschaltzeit von 10:17:13h bis 18:49:05h habe, so kann ich den bestimmten
Kanal über einen Taster toggeln. Das togglen funktionier vor, während und
nach den Schaltzeiten- eben zu jeder Zeit.

Ich vergleiche die Zeiten nach folgender Regel:

(strcmp(sE1Zeit, GZeit) == 0) // Einschalten, sE1Zeit = Einschaltzeit, GZeit = RTC-Zeit
(strcmp(sA1Zeit, GZeit) == 0) // Ausschalten, sA1Zeit = Ausschaltzeit, GZeit = RTC-Zeit

wo wir wieder bei "Deiner" fehlenden Sekunde sind. Das Problem haben wir ja "gelöst"

Startet der Controller nach einem Fehler/Reset neu- sind alle Schaltzeiten verloren und alle
Pin´s auf "aus". Kein Strom, oder Störung- Still ruht der See, bis ich eingreife. Alles gut...

Nun zu der Fehlerabfrage:
Diesen Stromausfall habe ich nur durch Zufall mitbekommen. Wäre dem nicht so gewesen, würde ich
jetzt wahrscheinlich noch nach einem Fehler im Sketch suchen.

Durch diesen Fehler bin ich überhaupt erst drauf gekommen, das hier nichts hinterlegt ist. Wenn die
Kiste läuft ist ja alles i.O.!
Ich habe ja noch andere Routinen, die Fehler abfangen sollen. Aber was nützt mir das, wenn der
Strom ausfällt oder der Controller neu hochfährt? Über den SystemZustand VOR oder während der Störung
habe ich keine Informationen- nichts.

Ich halte es also bestimmt nicht für eine merkwürdige Idee Fehler abfangen oder aufzeichnen.

Mal´n Beispiel: Hier gibt es ne´ Menge Leute, die den Wasseraustausch ihrer Aquarien über den Arduino
steuern. Ich habe hier noch nicht von einem gehört, das er einen Feuchtigkeitssensor unter dem
Aquarien zur "Notabschaltung" installiert hat. Und wenn das Ding mal überläuft und der Nachbar
begrüßt ihn mit "Gummistiefel"- dann weiß er, das etwas nicht funktioniert hat- das ist aber auch
alles.

Nun zu dem internen/externen Speicher:
Gestern wollte ich nur den "Stromausfall" protokollieren, dann kam Deine "Sekunde" dazu, dann die
Idee mit dem Fehlercode- und Morgen? Auch daher wollte ich gerne externen Speicher.

Ich will hier nicht von Sicherheit sprechen, aber bei der Einen oder Anderen Sache sollte man schon
zweimal hinschauen.
Nach dem Motto: Schalte bei 72% Feuchtigkeit den Lüfter ein. Ob der Lüfter läuft, wird nicht geprüft!
Gruß und Spaß
Andreas

Hallo Andreas,

was hälts du von folgender Idee:

Deinen Arduino mit einer Batterie zu puffern. Wenn die Versorgungsspannung ausfällt, muss dieses erkannt werden. Dann sollten die Werte in das EEPROM geschrieben werden. Zeitgleich am besten Hintergrundbeleuchtung abschalten.