www.mikrocontroller.net

Forum: Codesammlung Die genaue Sekunde / RTC

Autor: peter dannegger (Gast)
Datum: 18.12.2003 22:55
Dateianhang: timebase.zip (3,9 KB, 2901 Downloads)

Sehr oft kommt hier die Frage wie man einen Sekundentakt erzeugen kann
oder ob man unbedingt einen Uhrenquarz oder, noch schlimmer, einen
extra RTC-Chip braucht.

Die Antwort lautet: Nein !

Man kann bequem mit dem Timer aus jeder X-beliebigen Quarzfrequenz auf
den Takt genau die Sekunde erzeugen.


Und dann, immer wenn 60 Sekunden um sind, ein Minutenregister
hochzuzählen, nach 60 Minuten ein Stundenregister und nach 24 Stunden
den Tag, das ist ja wohl keine Kunst mehr.


In den Beispiel habe ich versucht, den mathematischen Weg aufzuzeigen.

Außerdem ist dann noch ein Beispielcode in C und in Assembler mit
dabei.

Letztendlich übernehmen beide die nötigen Berechnungen vollautomatisch,
solange man die beschriebenen Randbedingungen einhält.

Man muß also nur seine Quarzfrequenz in den Sourcecode eintragen und
ihn compilieren bzw. assemblieren lassen.



Peter
Autor: Tipper (Gast)
Datum: 19.12.2003 09:37

Hallo Peter,

wie sieht es denn mit der Ganggenauigkeit über 1Jahr aus?

Ist da ein Uhrenquarz nicht genauer und stabiler?


Schönen Gruß   Tipper
Autor: peter dannegger (Gast)
Datum: 19.12.2003 11:18

@Tipper

"wie sieht es denn mit der Ganggenauigkeit über 1Jahr aus?"

Ich kann nicht klagen.
Ich habe schon seit mehreren Jahren eine Uhr mit einem billigen
Standard Quarz 11,0592MHz am laufen.

Zu Anfang habe ich sie 3 Monate laufen lassen und mit der Videotext Uhr
verglichen. Dann die ermittelte Frequenz eingetragen und neu compiliert
und geflasht. Der MC ist ein AT89C2051.

Zur Zeit geht sie 14s vor, dieses Jahr habe ich sie noch nicht gestellt
(Sommerzeitumstellung ist mit einprogrammiert).


Es gibt aber auch von Maxim einen neuen Zeitgeber-Chip mit 38kHz, der
mindestens um den Faktor 10 besser ist als ein Standard 38kHz Quarz.

Prinzipiell sind höherfrequente Quarze immer auch genauer.
Früher wurde deshalb für hochgenaue Uhren ein 4,19MHz Quarz verwendet.

Wie man aber an Maxim sieht, kann man durch bessere Technologie diesen
Unterschied kompensieren. Es könnte aber auch sein, daß in dem Chip ein
Temperatursensor mit integriert ist und dann mit einer Korrekturtabelle
die Schwankungen ausgeglichen werden.



Peter
Autor: Tobias Breckle (Gast)
Datum: 19.12.2003 22:55

junge junge,
so langsam glaub ich du bist echt der mikrocontroller gott!!
und auch noch ne anleitung dazu.
besser gehts ned!! :)
Autor: buz11 (Gast)
Datum: 21.12.2003 19:02

" junge junge,
so langsam glaub ich du bist echt der mikrocontroller gott!! "

Geht mir auch so .

Ich müsste noch mal auf die Welt kommen , und mit ca. 6 Jahren
anfangen mit MC zu spielen ...
Autor: Marcel Meyer (Gast)
Datum: 22.12.2003 00:10

Sehr schöne sache, gefällt mir gut, der code ist ebenfalls recht
verständlich aufgebaut und so langsam klappt es auch bei mir mit den
ganzen "timer gelumpe" :-)

Weiter so! Danke!

Mfg
Marcel
Autor: Paul Baumann (Gast)
Datum: 22.12.2003 22:09

Hallo Leute!
Noch eine Erfahrung hätte ich beizusteuern:Siet dem 10.Oktober habe
ich hier eine Uhr im Gang, die mit At90S2313 und 4MHZ-Quarz arbeitet.
Das Ding habe ich seitdem nicht mehr gestellt und es läuft immer noch
synchron zum Zeitsignal aus Mainflingen.
Man kann generell sagen:Je höher die Quarzfrequenz, desto geringer
die Abweichung.

MfG Paul
Autor: A. Arndt (Gast)
Datum: 29.12.2003 00:41

Hallo,

ich nehme trotzdem lieber einme RTC mit Gangreserve, da kann mit dem uC
rumspilen und muss nicht ständig die Zeit neu einstellen oder auf
DCF-Dekodierung warten.

Gruss
A. Arndt
Autor: Werner Hoch (Gast)
Datum: 29.12.2003 10:22

Hi,

Den Code von Peter finde ich ziemlich cool.
Hier sind trotzdem kleine Verbesserungsvorschläge.

Wird im Timer die Option "Clear On Compare Match" verwendet,
so verliert man den Overflow Interrupt.
Oder möchte man nebenher noch eine Zeit mit dem Capture Interrupt
messen, so benötigt man einen durchlaufenden Timer.
Um dies zu erreichen, wird OCR1A nicht fest eingestellt, sondern
bei jedem Aufruf um den gleichen Wert erhöht.

In Peter's Code wurde der Rest auf einmal abgearbeitet. Damit erspart
man sich bei jedem Interrupt einen Vergleich und die Verarbeitungszeit
verkürzt sich in seinem Code. Der Unterschied zwischen kurzem und
langem
Interrupt ist hier der Rest.
Bei den geänderten Codeschnipseln wird der Rest gleichmäßiger
abgearbeitet.
Der Unterschied zwischen kurzem und langem Interrupt beträgt 1 Takt.

mfg
werner

ungetesteter Code für den durchlaufenden Timer:
==================================================

SIGNAL
(SIG_OUTPUT_COMPARE1A) {
/************************************************************************/
/*      Insert Key Debouncing Here    */
/************************************************************************/

  if( --prescaler == 0 ){
    prescaler = DEBOUNCE;
    second++;      // exact one second over
  }
  if (prescaler <= XTAL % DEBOUNCE) {
    OCR1A += XTAL / DEBOUNCE +1;   /* um 1 Takt längere Periode um
              den Rest abzutragen */
  } else {
    OCR1A += XTAL / DEBOUNCE;   // kurze Periode
  }
}

Um im Sonderfall, daß XTAL%DEBOUNCE null ist, keinen unnötigen
Code zu haben, kann man wieder Präprozessoranweisungen verwenden:

SIGNAL
(SIG_OUTPUT_COMPARE1A) {
/************************************************************************/
/*      Insert Key Debouncing Here      */
/************************************************************************/

  if( --prescaler == 0 ){
    prescaler = DEBOUNCE;
    second++;      // exact one second over
  }
#if XTAL % DEBOUNCE
  if (prescaler <= XTAL % DEBOUNCE) {
    OCR1A += XTAL / DEBOUNCE +1;   /* um 1 Takt längere Periode um
              den Rest abzutragen */
  } else {
#endif
    OCR1A += XTAL / DEBOUNCE;   /* kurze Periode */
#if XTAL % DEBOUNCE
  }
#endif
}
Autor: peter dannegger (Gast)
Datum: 29.12.2003 18:56

Sehr schön.

Es freut mich immmer wieder, wenn jemand meinen Code versteht und
darauf aufbauend sogar noch Verbesserungen oder auch andere Meinungen
dazu hat.


Peter
Autor: Rolf F. (Gast)
Datum: 02.01.2004 13:34

Ja, weil Quarze um 5 MHz am stabilsten sind wurden früher (um 1930 -
Mitte letztes Jahrhunder) damit die damals geauesten Uhren der Welt
gebaut; Uhrenquarze eignen sich eigentlich nur wegen der geringen
Frequenz und der daraus folgenden niedrigen Stromaufnahme gut für
Uhren.

Wenn man es genau machen will, dann kann man noch (Dreh-)Kondensatoren
(von den Quarz-Kontakten sowie -Gehäuse zu Masse) und einen
Parallel-Widerstand/-Poti anschließen und damit die Frequenz genau
einstellen (mit einem 12-stelligen Frequenzzähler). Genauer geht es
dann nocht mit der Temperatur-Kennlinie der Schaltung, die man mit
Software (u. dem MC-internen Temp.-Sensor) eliminieren kann. Wegen
Schaltsekunden u. A. ist aber sowas wie DCF77 oder NTP meist sinnvoller
als dieses Feintuning.

Mal eine Frage zur Sommer-/Winter-Zeit: Gibt es dafür eine Formel?
Gefunden hab ich ja schon Formeln für Schaltjahre, Tage seit dem 1.1.1,
Wochentag, Kalenderwoche (nach DIN 1355) auch vor 1500 aber noch keine
für Sommer-/Winterzeit.
Autor: Matthias (Gast)
Datum: 02.01.2004 14:18

Hi

Umstellung von Winterzeit auf Sommerzeit:
Am letzten Sonntagmorgen im März werden die Uhren von 02:00 auf 03:00
Uhr vorgestellt. Man verliert eine Stunde.

Umstellung von Sommerzeit auf Winterzeit:
Am letzten Sonntagmorgen im Oktober werden die Uhren von 03:00 auf
02:00 Uhr zurückgestellt. Man gewinnt eine Stunde.

Matthias
Autor: peter dannegger (Gast)
Datum: 02.01.2004 14:42

In meinem Beispielcode für die RTC DS1994 ist sowas in Assembler mit
drin, prüft jeden Sonntag darauf.

Funktioniert aber nicht mehr 2100, da das kein Schaltjahr ist, d.h die
Sonntagserkennung schlägt fehl.

Ich nehme auch ab 2100 gerne sämtliche Beschwerden diesbezüglich
entgegen.


Peter
Autor: Rolf F. (Gast)
Datum: 02.01.2004 20:29

@Matthias:

Woher hast Du das?
Es muß dafür eine Norm geben, aber welche konnte ich noch nicht
finden.
Naja, wenn die Sommerzeit so plötzlich abgeschafft wird, wie sie
eingeführt wurde, dann hat sich das Problem erledigt.


@Peter:

In "Das C++ Codebook" steht einiges z. B. mit den Tagen seit dem
01.01.0001, das aktuelle Sternzeichen usw..
Für MCs ist aber eher dies hier interessant (i. W. C mit einigen
C++-Resten):

// http://home.nordwest.net/hgm/kalender/kal-61.htm
// bis http://home.nordwest.net/hgm/kalender/kal-66.htm
// http://home.nordwest.net/hgm/kalender/kal-aa.htm

Ich habe das angepasst für einen MC, der mit der Zeit seit 1.1.2000
0:0:0 rechnet. Bis auf Schaltsekunden u. Winter-/Sommerzeit stimmt die
Zeitrechnung damit (auch mit ALLEN zukünftigen Schaltjahren), aber 2068
läuft der 32-Bit-RTC-Zähler über.
Die Wochentage u. Kalenderwochen nach DIN 1355 stimmen mit den
Funktionen auch.
Fehlen eigentlich nur noch die Mondphasen ...
Autor: Matthias (Gast)
Datum: 02.01.2004 20:49

Autor: Rolf F. (Gast)
Datum: 03.01.2004 01:44

Aha, danke :-)
Bei meinen Links findest Du eine kompakte u. korrekte Version zur
richtigen Berechnung der Schaltjahre. Mit einem 128-Bit-Sekundenzähler
gibt´s dann nur das Problem der Schaltsekunden und der
Quarz-Ungenauigkeit.
Autor: Stefan (Gast)
Datum: 08.01.2004 22:04

Kirk an Peter:

Wie siehts aus mit der Lösung unseres Jahr-2100-Problems?


;-)))   Stefan
Autor: peter dannegger (Gast)
Datum: 08.01.2004 22:43

@Stefan

"Wie siehts aus mit der Lösung unseres Jahr-2100-Problems?"


Ich stelle sie natürlich am 28.02.2100 hier ins Forum.

Kannst mich ja am 27.02.2100 nochmal daran erinnern.



Peter
Autor: Rolf F. (Gast)
Datum: 09.01.2004 20:15

Wo soll 2100 ein Problem sein?
Die Schaltjahr-Berechnung ist doch ganz einfach:

 function ist_Schaltjahr(jahr) {
   if (jahr % 4 == 0)
      if (jahr < 1582)
         return 1;
      else if (!(0 == jahr % 100))
              return 1;
           else if (0 == jahr % 400)
                   return 1;
   return 0;
 }

http://www.nwn.de/hgm/kalender/kal-61.htm

Die Abfrage mit dem Jahr 1582 kann man im Microcontroller weglassen.
Autor: peter dannegger (Gast)
Datum: 10.01.2004 13:52

"Wo soll 2100 ein Problem sein?"


Ich dachte, daß meine Bemerkungen dahingehend eindeutig sind:

Es macht einfach keinen Sinn, sich schon jetzt damit zu beschäftigen.

Keiner weiß doch, ob der Flash-Speicher überhaupt dazu in der Lage ist,
100 Jahre lang einen Programmcode fehlerfrei zu speichern.


Peter
Autor: Rolf F. (Gast)
Datum: 10.01.2004 17:28

Ich meine ja nur, dass man die Formel zur Schaljahrberechnung in wenigen
Sekunden korrigieren kann; das sind ja weniger als 10 kurze Zeilen.
Autor: Martin (Gast)
Datum: 25.05.2004 17:23

Hi, Peter!
Habe ich den folgenden Satz in deiner Beschreibung richtig verstanden?
--------------------------------------------------------------
Deshalb wird jedensmal, wenn der Softwareteiler Null ist und die
Sekunde weitergezählt wird, ein anderer Comparewert geladen. Dieser ist
dann um den Rest größer. Und beim nächsten Timerinterrupt wird dann
wieder der Comparewert geladen, der das Ergebnis der Division war.
--------------------------------------------------------------


Heißt das, dass der Comparewert beim ersten mal 43198 + 64 ist,
um die fehlenden 64 Zyklen in der Sekunde auszugleichen,
und alle anderen Comparewerte in der selben Sekunde sind 43198?

Martin
Autor: Markus Holzapfel (Gast)
Datum: 31.05.2004 20:12

Hallo Martin,

> Heißt das, dass der Comparewert beim ersten mal 43198 + 64 ist,
> um die fehlenden 64 Zyklen in der Sekunde auszugleichen,
> und alle anderen Comparewerte in der selben Sekunde sind 43198?

Ja. Ganz genau das heißt das.

Gruß,
Markus
Autor: A. Arndt (Gast)
Datum: 15.10.2004 11:58

Hallo Peter,

bin jetzt auch nochmal auf den DS1994 bzw. DS1904 gestossen, der zählt
ja nur Sekunden hoch und ich müsste dann immer in Minuten,, Stunden
Tage, Monate und Jahre umrechnen, gibt es kein anderes ibutton der
diese Daten wie der Ds1307 ablegt ?

Gruss
A. Arndt
Autor: Peter Dannegger (Gast)
Datum: 15.10.2004 17:18

Ja, ich finde das auch sehr umständlich.

In meinem Tiny12 Beispiel wird einfach beim Einschalten die Uhr
hochgezählt, bis der 32Bit-Wert mit dem im DS1994 gleich ist.
Das kann dann in 100 Jahren schon ein paar Sekunden dauern.


Allerdings ist der DS1994 nicht sehr genau. Bei mir geht er 10min/Jahr
vor. Ich müßte also noch den 32Bit-Wert mit 0,99998049 multiplizieren,
aber dann wird eng im Tiny12 mit dem Programmspeicher.


Peter
Autor: Matthias (Gast)
Datum: 15.10.2004 17:29

Hi

dann zieh doch einfach alle 52560 Sekunden eine Sekunde ab.

Matthias
Autor: nobody0 (Gast)
Datum: 15.10.2004 17:48

Naja, wenn da alle x Sekunden korrigiert wird, dann kann das Fehler
verursachen, beispielsweise bei Zeitdifferenz-Messungen.
Beim Multiplizieren ist es ähnlich, denn die Sekunden werden ja nur
ohne Nachkommastellen, also gerundet verwendet; d. h. plötzlich dauert
eine angezeigte Sekunde zwei Sekunden oder null Sekunden; das kann auch
Fehler verursachen.
Autor: Matthias (Gast)
Datum: 16.10.2004 09:56

Hi

natürlich kann das Probleme machen. Wenn aber nur um eine reine Uhr
geht ist das eigentlich keine große Sache. Man zieht die Sekunde
natürlich nicht um 12:00 Uhr Mittags ab sondern irgendwann mitten in
der Nacht.

Matthias
Autor: tex kerstan (Gast)
Datum: 15.11.2004 09:58

Hallo Rolf!
Habe ich Deinen Beitrag richtig verstanden, dahingehend, dass Du die
Uhr auf der Basis des Julianischen Datums programmiert hast?
Falls ja und wenn Du es hergeben würdest, würde ich mir das Programm
gerne mal ansehen.
Grüße aus Berlin
tex
Autor: nobody0 (Gast)
Datum: 15.11.2004 19:13

Hallo tex,
das Programm macht nichts anderes als einen 32-Bit-Zähler hochzuzählen
- jede Sekunde einmal + gelegentlich Minute, Stunde usw. hochzählen.
Code ist u. a. von hier:
 http://home.nordwest.net/hgm/kalender/kal-61.htm
 bis http://home.nordwest.net/hgm/kalender/kal-66.htm
 http://home.nordwest.net/hgm/kalender/kal-aa.htm

Dabei ist mir wichtig, dass Schaltjahre richtig berechnet werden und
leicht berechnet werden kann, ob ein Datum existiert oder nicht, wie z.
B. der 31.2..
Mit ein paar kleinen Funktionen ist das kein Problem.
Zusätzlich habe ich u. A. noch kleine Funktionen beispielsweise zum
Inkrementieren u. Dekrementieren des Datums gemacht.
Autor: tex kerstan (Gast)
Datum: 15.11.2004 19:52

Hi Nobody0!
Das Geheimnis des Julianischen Datums ist, das es keine falschen Tage
gibt, also keinen 31.2. ... Die ganze Bastelei mit den Tagen, Monaten
ect. ist total überflüssig, wenn man die Information aus dem JT zieht.
Dann kommen alle Gemeinheiten des Kalenders ganz automatisch 31.7 /
31.8. ...
Das Julianische Datum hab ich unter Kontrolle ich bin zu blöd den
Zähler zu programmieren!
Autor: nobody0 (Gast)
Datum: 16.11.2004 10:12

Das hilft aber nicht, wenn in einem Menü ein User als Geburtsdatum den
31.2.2033 eingeben kann.
Bei 99,9 % aller Menüs oder anderer Eingaben kann dies nicht direkt
abgefangen werden, weil da immer der Tag 1 bis 31 ausgewählt werden
kann und ähnliches für Monat und Jahr gilt.
Dass es das obige Datum nicht gibt und selbst die dem nahekommenden
Daten (Dekrementieren/Inkrementieren bis ein gültiges Datum erreicht
wird) in der Zukunft liegen, sollte mit ein paar kleinen Funktionen
erkannt werden.
Das Datum muß vor der eigentlichen Verarbeitung erstmal einige Checks
bestehen, bevor es akzeptiert werden kann.
Autor: tex kerstan (Gast)
Datum: 16.11.2004 11:01

OK! Da haben wir total gegensätzliche Anwendungen. Ich brauche eine
genaue Uhrzeit im µC. Da sind abstrakte Usereingaben nur bedingt
relevant. Ich habe halt bisher nur absurde Kalendarien gefunden die in
gigantischen Arrays definiert wurden um die ganzen Absurditäten unseres
Kalenders abzufangen, Sekunden wurden zu Minuten aufaddiert, Minuten zu
Stunden ...
Ich möchte die Uhr über die serielle Zahl des Julianischen Datums
definieren, weil ich so diesen absureden Kram mit Minuten, Sekunden,
Stunden, Tagen, Schaltjahren ... los bin. Die Formeln für das Datum
habe ich aber bei Interrups, Counterpreloads, ... hörts bei mir auf.
Autor: nobody0 (Gast)
Datum: 16.11.2004 18:09

Das ist doch ganz einfach: Nimm als Zähler die Sekunden seit z. B.
1.1.2000 0:00:00 und rechne ohne Schaltsekunden (d. h. in TAI):

blub = counter;
blub %= 60;
Sekunden = blub;
blub %= 60;
Minuten = blub;
usw.

Für Tage im Monat braucht man ein Array und für Tage im Jahr die
Schaltjahr-Funktion.

In einer Schicht darüber kann man Schaltsekunden berücksichtigen und
eine weitere Schicht darüber Sommer-/Winter-Zeit. Darüber wiederum kann
man weiteres packen, beispielsweise metrische Zeitrechnung für eine
metrische Uhr.

Damit man wenig einstellen muß, nehme ich als Startwert den vom
Zeitpunkt der Compilierung; dafür gibt's ja _DATE__ und __TIME_.
Autor: nobody0 (Gast)
Datum: 16.11.2004 18:25

Nachtrag: Vor der Minuten-Zeile muss

blub /= 60;

stehen.
Danach hat man die Zeit in Minuten.
Dasselbe muß in die Zeile darunter; danach hat man die Zeit in
Stunden.
So kommt man letztlich zum Jahr.
Autor: Jochen (Gast)
Datum: 25.12.2004 16:40

Huhu Peter,

hab mal ne Frage:

Du hast jeweil im main-loop folgendes stehen:

ASM:   out  ddrb, second
C:     LED_DIR = second (wobei LED_DIR weiter Oben als DDRB deffiniert
ist)

sollte das nicht jeweils PORTB heißen?

Oder versteh ich da den Code net richtig?

Ansonsten Danke für den Code funktioniert super.

Frohes Fest, Jochen
Autor: Hans (Gast)
Datum: 25.12.2004 20:19

hat von euch schon mal jemand versucht vom tv-signal eine
referenz-frequenz abzuleiten ??
weil die haben doch ein besseres trift-verhalten als ein normal
quarz...

und wie schauts eigentlich mit den teilen aus handys aus???

sind die stabil oder werden die durch das signal von den basis
stationen stabil gemacht?

und dann ist da noch die frage wie stabil sind die 50hz....fragen über
fragen ;)

73+55 für 2005 de oe6jwf / hans
Autor: peter dannegger (Gast)
Datum: 25.12.2004 20:52

@Jochen,

die Ports sind ja nach den Reset auf 0.
Daher kann man eine LED einschalten, indem man das Directionbit auf 1
setzt.


Peter
Autor: Jochen (Gast)
Datum: 25.12.2004 23:56

Joo, so stimmt das natürlich auch wieder ;-)

Danke für die Antwort

Jochen
Autor: Kurt (Gast)
Datum: 12.01.2005 12:06

Hallo Hans,

schau mal bei DK6RX

Gruss Kurt
Autor: Alexander Muthmann (Gast)
Datum: 05.03.2005 18:21

Hallo...

so hab das ganze jetzt mal aufgegriffen, und ein kleines Problem
damit:

ich hab mal den asm code genommen und kompiliert.
Dabei bekam ich in Zeile 71 einen Fehler.
ldi  prescaler, debounce
Das Prog versucht 256 in r18 zu schreiben => geht nich, zu groß die
Zahl => out of Range

kann es also sein, dass das nicht
ldi  prescaler, debounce
sondern
ldi  prescaler, debounce-1
heißen muss???

würd mich freuen wenn mir da mal jemand weiter helfen kann...
schöne grüße
Alex
Autor: Werner Hoch (Gast)
Datum: 05.03.2005 19:43

Die Zahl 256 ist einfach wieder 0.
Damit wird die Sekunde in 256 Unterschritte (Timerinterrupts)
aufgeteilt.

Die Zahl muß nur so gewählt werden daß
Clock/debounce < 0xFFFF ist
und debounce selber <= 256

Mit 256 (0) hat Peter die Maximale Anzahl an Unterschritten gewählt.
Ich würde eher 250 nehmen, dann vergehen zwischen den Timerinterrupts
4ms.

Wenn du die Fehlermeldung entfernen willst kannst du die konstante
kapseln z.B. LOW_BYTE(debounce).
Ich halte dies aber nicht für empfehlernswert.

BTW: hat der assembler eine Warnung oder eine Fehlermeldung ausgegeben?
Welchen Assembler hast du verwendet?

MfG Werner
Autor: Alexander Muthmann (Gast)
Datum: 05.03.2005 19:46

Hallo,

ich verwende mom AVRStudio und es war ein Error und keine Warning.
soll ich dann einfach 0 statt 256 nehmen?
also ldi prescaler, 0 ?

schöne Grüße
Autor: Werner Hoch (Gast)
Datum: 05.03.2005 20:08

Nein, den debounce wird, wie du sicherlich gesehen hast, auch für die
Berechnung anderer Register verwendet.

Wenn du debounce auf 0 setzt sind diese Werte falsch.
Es ist besser du reduzierts debounce ein wenig.
Autor: Alexander Muthmann (Gast)
Datum: 05.03.2005 20:11

Ne ich meinte die Konstante gleichlassen, nur in den betroffenen Zeilen
halt nicht debounce einzufügen, sondern 0,
also halt wie oben ldi prescaler, 0 statt ldi prescaler, debounce
die anderen Register würden dadurch doch nicht verändert

mfG
Autor: Werner Hoch (Gast)
Datum: 05.03.2005 20:21

Von der Funktion her kannst du das zwar machen, aber spätestens wenn du
den Wert von debounce beim nächsten mal änderst, wirst du die Null
vergessen und dein Programm funktioniert nicht mehr richtig.

Konstanten sollten im Quelltext alle nur einmal definiert werden.
Konstanten im Programm haben, abgesehen von Spezialfällen, nichts im
Programmquelltext zu suchen.
Autor: Alexander Muthmann (Gast)
Datum: 05.03.2005 20:22

OK ;)
hab erst vor was mehr als 2 Wochen angefangen, gut zu wissen mit den
Konstanten (leuchtet auch irgendwie ein^^)
schönen Abend noch!
Autor: T. Kirchen (Gast)
Datum: 13.04.2005 12:42

Hallo zusammen,

ich habe mich mal so durch die Beiträge gehangelt. Bin momentan an
einen Projekt beschäftigt, in dem ein RTC4553 Chip eingesetzt ist.
Da sich das Datenblatt über die Ansteuerung nur spärlich auslässt,
wollte ich mal anfragen, ob jemand schon mal mit dem Chip gearbeitet
hat. Ich kann irgendwie die Zeit nicht vorgeben bzw. auslesen.
Keine Ahnung, ob das an der SPI-Übertragung liegt.
Im Datenblatt wird alles mit A3..A0,D3..D0 angegeben und für die
Übertragung muss man dann die Daten in der Reihenfolge A0..A3,D0..D3
anlegen bzw. auslesen.
Kann da jemand weiterhelfen????
Autor: peter dannegger (Gast)
Datum: 13.04.2005 16:22

@T. Kirchen

Bitte nicht einen Thread hijacken sondern für neue Fragen einen neuen
Thread aufmachen !


Hier ging es nämlich gerade NICHT um externe RTC-Chips.


Peter
Autor: hanes (Gast)
Datum: 24.04.2005 16:24

Dar ich dein code im wiki veröffentlichen?
Autor: peter dannegger (Gast)
Datum: 24.04.2005 18:45

Ja

Peter
Autor: hanes (Gast)
Datum: 25.04.2005 18:54

Autor: C. Romas (Gast)
Datum: 10.05.2005 18:43

Sorry ich bin blutiger Anfänger und habe mir das Assemblerscript mal
egnommen.

Allerdings bekomme ich an den 8 LEDs nichts zu sehen wenn ich es
programmiere. Ich benutze einen ATMega128. Es sind nur die
Kompatibilitätsfuse geändert worden und JTAG ausgeschaltet. Takt ist
demnach noch 1MHz (so stehts auch im AVR Studio)

Im Code habe ich nur an den beiden Zeilen wo auf ddrb geschrieben wird
ddrC genommen.

Habe ich etwas vergessen zu konfigurieren im Code oder liegt das an
meiner HW?
Autor: Werner B. (Gast)
Datum: 11.05.2005 16:18

Wenn Du DDRB in DDRC änderst, musst Du natürlich auch PORTB in PORTC
(und ein eventuell vorhandenes PINB in ein PINC ändern).
Autor: Juel (Gast)
Datum: 22.10.2005 14:08

Hi, habe mir gerade mein erstes AVR-Testboard aufgebaut, aber leider
bekomme ich die Uhr nicht zum laufen :/
Benutze einen 90S8515 mit 8Mhz quarz.

Habe #define OCR1A OCR1 auf #define OCR1A OCR1A geändert,
und die KEY_INPUT geschichte sowie unten die whileschleife
auskommentiert in der Hoffnung dass die Uhr dann sofort losläuft.
Leider gehts nicht... kann mir jemand weiterhelfen ?

#include <io.h>
#include <interrupt.h>
#include <signal.h>


#ifndef OCR1A
#define OCR1A OCR1A  // 2313 support
#endif

#ifndef WGM12
#define WGM12 CTC1  // 2313 support
#endif

//#ifndef  PINC
//#define  KEY_INPUT  PIND  // 2313
//#else
//#define KEY_INPUT  PINC  // Mega8
//#endif
#define  LED_DIR    DDRB

//#define XTAL    11059201L  // nominal value
#define XTAL    8000000L  // after measuring deviation: 1.5s/d

#define DEBOUNCE  256L    // debounce clock (256Hz = 4msec)

#define uchar unsigned char
#define uint unsigned int

uchar prescaler;
uchar volatile second;      // count seconds


SIGNAL (SIG_OUTPUT_COMPARE1A)
{
/************************************************************************/
/*      Insert Key Debouncing Here      */
/************************************************************************/

#if XTAL % DEBOUNCE
  OCR1A = XTAL / DEBOUNCE - 1;    // compare DEBOUNCE - 1 times
#endif
  if( --prescaler == 0 ){
    prescaler = (uchar)DEBOUNCE;
    second++;        // exact one second over
#if XTAL % DEBOUNCE      // handle remainder
    OCR1A = XTAL / DEBOUNCE + XTAL % DEBOUNCE - 1; // compare once per
second
#endif
  }
}


int main( void )
{
  LED_DIR = 0xFF;

  //while( KEY_INPUT & 1 );    // start with key 0 pressed

  TCCR1B = 1<<WGM12^1<<CS10;    // divide by 1
          // clear on compare
  OCR1A = XTAL / DEBOUNCE - 1;
  TCNT1 = 0;
  second = 0;
  prescaler = (uchar)DEBOUNCE;

  TIMSK = 1<<OCIE1A;
  sei();

  for(;;){
    if( second == 60 )
      second = 0;
    LED_DIR = second;      // display second (binary)
  }
}
Autor: Werner Hoch (Gast)
Datum: 22.10.2005 16:05

Hallo Juel,

du hast meine Variante mit der von Peter vermischt ohne die Anpassungen
zu machen:
1. DEBOUNCE < 256 Begründung findest du weiter oben
2. Compare Match Interrupt aktivieren
3. Port bei der ausgabe beschreiben, nicht die Richtungsregister

MfG
Werner

Die Init-Section für einen 2313 sieht bei mir so aus:
--------------
 seg7_init();
  /* seg7_test(); */

  TCCR1B = _BV(CTC1) | _BV(CS10); /* clear on compare match, prescaler
1 */

  OCR1A = UC_CLOCK / SUB_CLOCK - 1;
  TCNT1 = 0;
  prescaler = SUB_CLOCK;

  TIMSK = _BV(OCIE1A);
  sei();
----------------
SUB_CLOCK ist bei dir DEBOUNCE
Autor: Werner Hoch (Gast)
Datum: 22.10.2005 16:17

TssTs.

Mein Beitrag von vorher ist falsch, bis auf den Punkt 3.
Du mußt den Wert auf den Port ausgeben:
PORTD = second.
Autor: Juel (Gast)
Datum: 22.10.2005 16:53

Dankeschön, jetzt gehts auch bei mir :)
Echt super die schnelle Antwort!!
Autor: Max (Gast)
Datum: 02.01.2006 01:22

Hallo Peter,

mit welchem Compiler hast du den Code geschrieben, bzw mit welchem kann
man den Code in einen AVR flashen?
Gruß Max
Autor: Manfred Steiner (Gast)
Datum: 29.03.2006 15:34

Das ist doch alles voll blöd hier. Da such ich ein Assembler Programm
und alles was ich finde ist kein Assembler!
Autor: Alexander Muthmann (Gast)
Datum: 29.03.2006 15:37

och du armer ;)
weiß zwar nich was du unter nem Assembler Programm verstehst, ich
versteh das darunter was im ersten post wunderbar zum download steht^^
Autor: Uffz Meier (Gast)
Datum: 22.04.2006 17:14
Dateianhang: sekunde.c (2,3 KB, 429 Downloads) | formatierter Code

morschen Leute

ich habe den original Code von ganz oben verwendet und will damit
möglichst genaue Sekunden erreichen. Ausgegeben wird dann Sekunde,
Minuten und Stunden per UART, wenn der Timer Interrupt eintritt (jedoch
am ende des Interrupts um die vorherige Hochzählung nicht zu stören).
Leider scheint es trotzdem zu störungen zu kommen. Nach 1 Stunde habe
ich schon eine Sekunde Abweichung. Kann mir jemand sagen warum, und wie
ich sonst das kontrollierne kann, wenn nicht per UART?
Autor: Werner Hoch (Gast)
Datum: 22.04.2006 17:57

Dein Oszillator/Quarz ist wahrscheinlich ungenau.

Lass deine Uhr einen Tag laufen, miss den Zeitfehler aus und
korrigiere
XTAL entsprechend auf 3999....Hz
Autor: peter dannegger (Gast)
Datum: 22.04.2006 19:07

@Uffz,

wenn die UART nicht mit Interrupt und gepuffert ist, dann darf man
sowas lahmarschiges natürlich nicht in einen Interrupt schmeißen.

Alles, was Du in den Interrupt reinpackst, muß bis zum nächsten
Interrupt beendet sein.



Peter
Autor: Uffz Meier (Gast)
Datum: 22.04.2006 20:05

Ist es so dass die Endlosschleife im main() recht hochfrqeuentiert
unterbrochen wird und in den Interrupt springt? Das sieht nämlich so
aus .
Bei mir ist es wichtig neben dem Counter-Zeug noch Ruhe für andere
Sachen zu haben. Also etwa jede Sekunde in einen Interrupt springen
wäre OK aber scheller würde mein Programmablauf zerreißen.
Autor: peter dannegger (Gast)
Datum: 22.04.2006 21:27

@Uffz,

genau das ist ja der Sinn eines Interrupts, das Main zu unterbrechen,
ohne daß es gestört wird.
Deshalb sollte man ihn eben so kurz wie möglich halten und keine
arschlahmen Sachen darin machen.
Zerrissen wird dabei nichts.


Peter
Autor: Don Martin (Gast)
Datum: 28.01.2007 15:11

Hallo Peter,

uchar prescaler;
uchar volatile second;      // count seconds

müsste man prescaler nicht auch als volatile deklarieren?

Martin
Autor: holger (Gast)
Datum: 02.04.2007 19:31

Angeregt durch einen anderen Thread habe ich gerade mal
die "genaue Sekunde" ausprobiert. Das geht soweit ganz gut.

Die erste Sache die man beachten muss ist natürlich:

>  OCR1A = XTAL / DEBOUNCE - 1;    // compare DEBOUNCE - 1 times

OCR1A darf nicht größer 65535 werden.

Bei den neuen AVR mit 20MHz kommt aber folgendes Problem
dazu. DEBOUNCE ist mit 256 zu klein ! Es muss mindestens 306 sein.
XTAL / 65536 = 305,7 .

prescaler muss dann ein uint sein. So klappt die "genaue Sekunde"
wieder ;)
Autor: manow (Gast)
Datum: 24.09.2007 16:20

Ich hab den Code gestern ausprobiert und mich gewundert wieso bei mir
die Sekunde ziemlich schnell lief? Den Fehler habe ich dann auch
gefunden. prescaler wird mit 256 geladen, das ist doch zu groß, oder?¿?
Nach uint geändert und schon läuft die Sekunde.
Autor: Peter Dannegger (peda)
Datum: 24.09.2007 16:56

manow wrote:
> Ich hab den Code gestern ausprobiert und mich gewundert wieso bei mir
> die Sekunde ziemlich schnell lief? Den Fehler habe ich dann auch
> gefunden. prescaler wird mit 256 geladen, das ist doch zu groß, oder?¿?
> Nach uint geändert und schon läuft die Sekunde.

Ne, das paßt schon.
256 wird zu 0 und nach 256 mal ist es wieder 0.
Man kann also mit einem Byte /256 teilen.

Der Fehler ist woanders, kannst ja mal Deinen Code als Anhang senden.


Peter
Autor: manow (Gast)
Datum: 24.09.2007 17:31

Hmm, seltsamer weise kann ich den Fehler nicht mehr rekonstruieren.
Jetzt funkt. es auch so, im Gegensatz zu heute halb drei in der Früh.
Vielleicht war ich etwas langsam...