Uhrzeit sinnvoll im EEprom speichern

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Uhrzeit sinnvoll im EEprom speichern

      Ich bin auf der Suche nach einer Idee für einen schonenden Algoritmus, um die aktuelle Minute des Tages abzuspeichern.

      Hintergrund:
      Es soll eine Analog-Uhr mit Stunden-und Minutenzeiger angesteuert werden.
      Jede Minute gibt es einen Impuls an das Uhrwerk und der Minutenzeiger rückt vor.
      Die Uhr zeigt die Zeit mittels DCF77 Empfang an.

      Problem1:
      Die Uhr wird erstmals eingeschaltet.
      Dazu wird die Zeit auf 12:00 gestellt und der AVR eingeschaltet.
      Beim Einschalten wird eine Taste gedrückt, damit der AVR weiß, dass die Uhr auf 12:00 steht.
      Nach der Synchronisation weiß der AVR, dass er entsprechend Takte an die Uhr senden muss, bis diese mit DCF77 übereinstimmt.

      Problem2:
      Stromausfall.
      Die Uhr bleibt stehen.
      Nach dem Wiedereinschalten (Taster ist diesmal nicht gedrückt) und der Synchronisation mit DCF77 taktet die Uhr minütlich weiter.
      Es gibt eine Differenz, die der Stromausfallzeit entspricht.

      Die Idee ist nun, den internen EEprom jede Minute mit der aktuellen Uhrzeit zu beschreiben. Die kann er sich nach dem Stromausfall holen und feststellen, welche Differenz seitdem besteht und entsprechend nachtakten.
      Der Tag hat 1440 Minuten, bei max 100000 Schreibzyklen ist so eine EEprom-Variable nach 70 Tagen tot.
      Ich habe 512 Byte EEprom, bei Word-Variablen hätte ich 256 Speicherplätze, mich interessiert ja nur die Minute des Tages.

      Frage: Wie bekomme ich die Schreibzyklen gleichmäßig auf, sagen wir, 200 EEprom-Zellen (jeweils Word) verteilt?
    • Genau so eine Mutteruhr hab' ich schon vor längerem gebaut. Ich mach das mit einer Netzausfallserkennung. Das mit dem inizialisierten Start der Uhr (auf 12 Uhr stellen) hab' ich auch so erweitert, dass nach dem Zurückschalten ein Puls ausgegeben wird. Schnappt der Zeiger weiter, dann ist das Uhrwerk falsch gepolt, bleibt die Zeit auf 12 Uhr, passt alles.
      Nach einem Stromausfall läuft die Uhr vom letzten Stand aus weiter und wenn eine Sync erfolgt, tickert sie im 'Schnelllauf' zur aktuellen Zeit.

      BASCOM Source Code

      1. 'Mutter Uhr atomgesteuert V1.14
      2. 'Platine=Mutter_AtomUhr_V1.0_ATtiny2313
      3. 'Platine=Mutter_AtomUhr_V2.1_ATtiny2313
      4. 'fallende Flanke am int0 speichert Anzeige
      5. $regfile = "ATtiny2313.DAT"
      6. $crystal = 20000000
      7. $hwstack = 40
      8. $swstack = 2
      9. $framesize = 30
      10. '$prog &HFF , &HCF , &HDF , &HFF ' generated. Take care that the chip supports all fuse bytes.
      11. Config Portb.4 = Input 'DCF Tackt
      12. Config Portb.0 = Output 'Relais und LED
      13. Config Portb.1 = Output
      14. Config Portb.2 = Output
      15. Gerademinute Alias Portb.0
      16. Ungerademinute Alias Portb.1
      17. Syncled Alias Portb.2
      18. Config Portb.3 = Input 'Schalter für "0 Stellung"
      19. Schalter Alias Pinb.3 '0 wenn gedrückt
      20. Portb.3 = 1 'Pullup einschalten
      21. Config Portd.2 = Input 'Netzausfall Interrupt
      22. Config Dcf77 = Pinb.4 , Timer = 1 , Update = 0 , Inverted = 0 , Check = 2 , Gosub = Sectic
      23. Portb.4 = 1
      24. Config Int0 = Falling
      25. On Int0 Anzeige_speichen 'Netzausfall- Zeigerstellung speichern
      26. Dim Dummy As Eram Word 'Anfangsbytes mit dummy belegen
      27. Dim Anzeige_rom As Eram Word 'im Rom gespeicherte Anzeige
      28. Dim Anzeige As Word 'Anzeige auf dem Ziffernblatt 0Uhr =0, 6.30 = (6*60)+30=390, 11.59=(11*60)+59=719
      29. Dim Zeit As Word 'Zeit als Zahl zusammengesetzt wie "Anzeige"
      30. Dim An As Word 'Impulslaenge in msec
      31. Dim Aus As Word 'Pause zwischen Impulse in msec
      32. An = 500
      33. Aus = 500
      34. Dim Sync As Byte
      35. Dim Synczaehler As Word
      36. Dim Stellen As Bit
      37. Dim N As Byte
      38. 'Initialisieren
      39. Synczaehler = 0
      40. Gerademinute = 0 'Relais für gerade Minuten
      41. Ungerademinute = 0 'Relais für ungerade Minuten
      42. Stellen = 0
      43. Syncled = 1
      44. Wait 2
      45. Syncled = 0
      46. Enable Interrupts
      47. Enable Int0
      48. Gosub Stellunglesen 'Zeigerstellung aus Rom lesen
      49. Wait 1
      50. Reset Dcf_status.7
      51. 'Hauptschleife
      52. Do
      53. Debounce Schalter , 0 , Aufnullsetzen , Sub
      54. If Dcf_status.7 = 1 Then
      55. Synczaehler = 0 'bei erfolgreichem Zeitempfang der Zaehler zurückgesetzt
      56. Reset Dcf_status.7
      57. Sync = 0 'Zeit ist synchron
      58. End If
      59. If Synczaehler > 3600 Then 'wenn 60 Minuten keim erfolgreicher Empfang >Blinken
      60. Synczaehler = 3600
      61. Sync = 1
      62. End If
      63. Zeit = _hour * 60
      64. Zeit = Zeit + _min
      65. Zeit = Zeit Mod 720 'Betrag zwischen 0 und 719
      66. If Anzeige <> Zeit Then
      67. Gosub Impuls 'Uhrwerk auf Zeit stellen
      68. End If
      69. Loop
      70. End
      71. '***
      72. Sectic:
      73. If Stellen = 1 Then
      74. Toggle Syncled
      75. Else
      76. Syncled = Sync 'status 'Sync-Anzeige
      77. End If
      78. Synczaehler = Synczaehler + 1
      79. Return
      80. '***
      81. Anzeige_speichen:
      82. Anzeige_rom = Anzeige
      83. Disable Interrupts
      84. Stop
      85. Return
      86. '***
      87. Impuls:
      88. Anzeige = Anzeige + 1
      89. N = Anzeige Mod 2
      90. If N = 0 Then
      91. Gerademinute = 1
      92. Else
      93. Ungerademinute = 1
      94. End If
      95. Waitms An
      96. Anzeige = Anzeige Mod 720
      97. Gerademinute = 0
      98. Ungerademinute = 0
      99. Waitms Aus
      100. Return
      101. '***
      102. Aufnullsetzen:
      103. Stellen = 1 'Stellen signalisieren
      104. Waitms 1000
      105. Gerademinute = 0
      106. Ungerademinute = 0
      107. Bitwait Schalter , Set 'warten bis Schalter geöffnet
      108. Gerademinute = 1 'Test auf richtige Polung des Uhrwerks, Zeiger darf nicht weiterrücken
      109. Waitms An
      110. Gerademinute = 0
      111. Anzeige = 0
      112. _hour = 0
      113. _min = 0
      114. _sec = 0
      115. Stellen = 0
      116. Sync = 1 'nicht synchron
      117. Return
      118. '***
      119. Stellunglesen:
      120. Anzeige = Anzeige_rom
      121. _hour = Anzeige / 60
      122. _min = Anzeige Mod 60
      123. _sec = 0
      124. Return
      Display All
      Mutter_Atom_uhr_V2.1.PNG
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • Ich beschreibe nur bei Stromausfall. Musst du gucken, der int0 wird dazu verwendet.
      Dein gesuchter Weg mag bisschen Elektronik vermeiden, braucht halt dafür anderen Aufwand. Wie wäre es mit einer RTC mit gepufferten Rom, die ds3231 hat doch sowas, dann kannst du auch die Zeit bis zum Sync ordentliche Zeit anzeigen lassen.
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • in der Appnote AVR101 wird EEPROM wear leveling beschrieben, hier ist meine Implementation: mat.midlight.eu/index.php?title=EEPROM_Wear_Leveling_(AVR101)

      In deinem Fall könnte man das so konfigurieren:

      BASCOM Source Code

      1. 'Const Wearlevel_count = 3 ' number of parameters to store in eeprom (default: 1)
      2. ' ring buffer size (estimated life time: 100.000 cell write cycles * wearlevel depth)
      3. Const Wearlevel_depth = 170 ' uncomment to define the buffer sizes (default: 8)
      4. Const Wearlevel_start = 0 ' uncomment to set EEPROM start address (default: 1)
      5. $include "wear_leveling.inc"
      6. ' define the parameters
      7. Dim Time_minute As Word
      8. Wearlevel_pointer(1) = Varptr(Time_minute) ' address of variable in SRAM
      9. Wearlevel_size(1) = 2 ' byte size of the variable data type
      Display All


      Lesen/Schreiben:

      BASCOM Source Code

      1. ' load all parameter values stored in EEPROM (ID = 0), called usually during the initialisation
      2. Wearlevel_read 0
      3. ' save value from variable (Time_minute) in eeprom
      4. Wearlevel_write 0

      edit: Statt als Zeiteinheit für die Aktualisierung des EEPROMS eine Minute zu nehmen, könnte man stattdessen nur alle 337,5 sek (24*60*60/256) aktualisieren. Damit passt ein Tag genau in ein Byte und die Buffergröße erhöht sich von 170 auf 256.

      The post was edited 2 times, last by zaubara ().

    • Du nimmst dir ein Byte im EERam als Pointer auf die aktuelle Speicherzelle. Am Anfang steht da 1 drin. In der EEram Position 0 ist ja unser Zeiger.
      Wenn du einen neuen Wert in die Position, welche im EERAM 0 steht, schreibst, liest du sofort danach wieder aus.
      Unterscheidet sich der Wert, ist die Speicherzelle defekt und du erhöst EERAM(0) um eins und schreibst den Wert in die neue Zelle.

      Dadurch hast du bei 255 EERAM Zellen: 255 * 100.000 Schreibzyklen GARANTIERT! wobei die locker das doppelte oder mehr hergeben.
      Code first, think later - Natural programmer :D
    • tschoeatsch wrote:

      Dein gesuchter Weg mag bisschen Elektronik vermeiden
      Ist leider nicht meine Elektronik. ich bin hier nur der Programmierer im Projekt.

      Schraubbaer wrote:

      wenn du eine DSxxxx uhr dran has
      Nein, auch das geht leider nicht. Mit so einer RTC könnte man auch gleich die Sync-Zeit überbrücken.

      @zaubara
      in deinem Link sehe ich die Beschreibung:
      To achieve this, there are two ring buffers for each parameter: a status buffer, which keeps track of the last written index and the parameter buffer itself.Because the write cycles are distributed over several EEPROM cells, the life time is increased.

      Mit einem Zähler hatte ich es schon mal gemacht und würde es vielleicht hier wieder machen, mal sehen, wenn mein Ansatz nicht funktioniert, komm ich drauf zurück.

      Ich hätte alle EEprom Zellen mit Wert 65535 als leer betrachtet, so wie sie es nach dem Löschen sind.
      Beginnend mit der ersten Minute, also 12:01 wird der Inhalt dekrementiert
      Nach der ersten Stunde, 60 Minuten, ist der EEprom-Inhalt bei 65475 und so weiter.
      Da 65535 nicht aufgeht mit den Minuten des Tages, ist bei 65520 Dekrementen Schluss, das ist ein Wert von 15, der übrig bleibt.
      Beim Programmanfang prüfe ich das EEprom Array.
      Steht in einer EEprom-Zelle 15, dann ist sie verbraucht, nächste Zelle usw.

      @six1
      so weit würde ich gar nicht gehen mit dem Ausnutzen der Speicherzelle. Lieber einen Puffer lassen. Eine kaputte Zelle ist in den Sekunden nach dem Beschreiben sicher noch gut lesbar, aber wenn der Strom wirklich mal ne Stunde weg ist, dann ist die Ladung der Speicherzelle auch weg. Dann eher bis 100k zählen und zur nächsten Zelle, das würde fast 50 Jahre reichen ;)
    • Michael wrote:

      Steht in einer EEprom-Zelle 15, dann ist sie verbraucht, nächste Zelle usw.
      Da die zweite Zelle dabei nur 255 mal beschrieben werden muß können aus 512 Byte 511Word werden.
      Gut für knapp 50 Jahre. Es wird jedoch nötig zwischendurch die Uhr neu zu syschronisieren. (Hin und wieder wird ein Takt ausfallen) Ein Kontakt an der Uhr ist nicht vorgesehen?
    • Ich kenne das so, dass nach jedem Stromausfall (und somit auch beim ersten Einschalten) die Uhr auf 12:00 geht, sich die DCF-Zeit zusammenbastelt und sich dann darauf stellt. Kein Taster, kein EEPROM. Warum geht das in Deinem Fall nicht? Kann man die Uhr gar nicht elektrisch auf 12:00 Uhr stellen? Was passiert denn, wenn mal Impulse verloren gehen?
      Das mit dem EEPROM-Schreiben ist ja in jedem Fall eine Krücke, auch wenn natürlich sehr gute Ansätze genannt wurden. Letztlich ist das dennoch nie eine saubere Lösung, denn Du arbeitest vom erstem Moment an der Zerstörung des EEPROM. wir wissen alle, dass das EEPROM nicht für minütliches Speichern da ist. Eigentlich sollte man ja eine Unterspannungserkennung haben und dann mit letzter Kraft noch die Daten speichern. Aber Du kannst anscheinend nicht an der Hardware ändern, oder? Andere Speicher kannst Du ja auch anscheinend nicht anschließen. Warum kann die Uhr sich nicht jedesmal neu einstellen? Weil es dann nach Stromausfall 2 Minuten dauern würde? Könntest Du nach Stromausfall die Zeit aus dem Internet beziehen??
    • stefanhamburg wrote:

      denn Du arbeitest vom erstem Moment an der Zerstörung des EEPROM
      :D ich habe mal ein gewerbliches Projekt umgesetzt, bei welchem ein Sekunden genauer Betriebsstundenzähler gefordert war.
      Da habe ich das mit Pointer und "vom erstem Moment an der Zerstörung des EEPROM" Version gearbeitet ;)
      Die gesicherte Laufzeit war ~ 11 Jahre und danach im schlimmsten Fall eine neue Platine fällig.
      Wobei ich mal annehme, dass das locker 20 Jahre läuft...
      Code first, think later - Natural programmer :D
    • Ja, verstehe ich. In der Praxis wird kein Gerät so lange eingesetzt sein. Obwohl ... ich habe noch eine Funkuhr mit Analoganzeige, die seit 1988 ihren Dienst tut. Die stellt sich nach Batteriewechsel erst auf 12:00. Das scheint bei Michaels Hardware wohl nicht möglich zu sein.
      Ich komme eher wieder mit „unsportlich“. Es wird ja auch manchmal von Waits abgeraten und zu Timern geraten und da geht noch nicht einmal etwas irgendwann kaputt. Aber Michael wird natürlich andere Lösungen bereits aufgrund der Rahmenbedingungen ausgeschlossen haben.
    • stefanhamburg wrote:

      Ich kenne das so, dass nach jedem Stromausfall (und somit auch beim ersten Einschalten) die Uhr auf 12:00 geht, sich die DCF-Zeit zusammenbastelt und sich dann darauf stellt. Kein Taster, kein EEPROM. Warum geht das in Deinem Fall nicht? Kann man die Uhr gar nicht elektrisch auf 12:00 Uhr stellen? Was passiert denn, wenn mal Impulse verloren gehen?
      Hier handelt es sich um so eine Art Bahnhofsuhr ohne Sekundenzeiger, wie sie Tschoeatsch oben auch schon benutzt hat. Allerdings ohne Stromausfallerkennung.
      Diese Analog-Funkuhren haben eine Art Schalter oder Lichtschranke für die 12:00 Position, manchmal sogar mehr davon bei 04:00 und 08:00.
      Impulse gehen eher nicht verloren, höchstens, wenn die Mechanik kaputt ist.

      six1 wrote:

      ich habe mal ein gewerbliches Projekt umgesetzt, bei welchem ein Sekunden genauer Betriebsstundenzähler gefordert war.
      ich habe mal einen Ölverbrauchsmessgerät gebaut mit Zehntelsekunden-Erfassung der Betriebsdauer der Pumpe. Das ist aber relativ einfach, weil der Zähler einfach nur inkrementiert werden muss.
      Das hatte ich mit 16Bit Word-Zaehler und den restlichen EEprom-Zellen als Byte-Zähler nach dem Auffüll-Prinzip, wie ich es bereits beschrienben hatte. Überlauf bei 2^16 Schreibzyklen bei etwa 13 Jahren.

      Bei dem Projekt hier kommt aber erschwerend hinzu, dass ich ja die Zeit in den EEprom-Zellen "verschlüsseln" muss.
    • Michael wrote:

      Impulse gehen eher nicht verloren,
      Das ist so sicher wie ein Stromausfall. Spätestens wenn der Puls zeitgleich mit dem Ausfall kommt ist unklar ob die Uhr den Schritt gemacht hat. Es ist aber auch verständlich daß es dem Auftrageber zu aufwendig ist die Uhren/Elektronik unzurüsten. Die eine oder andere Uhr alle paar Jahre mal eine Minute korrigieren ist sicher günstiger. Eine Technik die 20/50Jahre garantierte Lebensdauer hat muß man heute noch finden. Da hätte ich keine Bedenken dem Kunden diese "geplante Obsolenz" zu verbauen. Vielleicht noch ein reserve Chip dazulegen den er in 50 Jahren tauschen kann ;)
      Die Berechnung von Word auf Zeit ist auch eher simpel - also nichts was unerwachtete Watchdog Aktivitäten auslösen würde. So gesehen spricht nicht dagegen das Eeprom zu "schießen"


      @ceperiga existiert der Chip mit dem zerstörte Eeprom noch? Er hatte mehr als eine Milion geschafft?

      Halten die Zellen die noch leben Ihre Daten noch über Tage? Oder nur für Sekunden?