Hallo
Ich möchte für eine Uhr ein relativ genaues 1Hz-Signal erzeugen
PIC16f84).
Ausprobiert habe ich folgendes:
1. TRM0-Überlauf; mit polling am Überlaufbit
2. TMR0-Überlauf per Interupt
3. keramikschwinger gegen Quarz ausgetauscht
4. "zero-error" von http://www.ezy.net.au/~fastvid/one_sec.htm (beide
versionen: mit echtem Interupt und mit "falschem" Interupt.
Alle Signale waren im vergleich zu meiner Windows-Uhr extrem ungenau.
Auf eine halbe Stunde kamen folgende Ungenauigkeiten:
1. hab ich vergessen. jedenfalls zuviel
2. 4s auf 20 min!!
3. Keramikschwinger und Methode 2: in 30 min 4 Sekunden schneller als
PC-Uhr
Quarz und Methode 2: in 30 min 4 Sekunden zu langsam
4. Pro Minute 0,5 bis 1s Fehler!
Irgendeie verstehe ich das nicht.
Methode 1 ist verständlich. Beim Pollen wird nicht jeder Überlauf des
TMR0 erkannt.
Bei Methode 2 dürfte meiner Meinung nach nicht eine solch große
Abweichung auftreten. Der Interupt wird auomatisch beim Überlauf des
TMR0 ausgeführt. Fehlerquelle wäre da nur, dass der Befehl, der zum
Zeitpunkt des Interupts ausgeführt wird, den Interupt etwas(!)
verzögert. Da handelt es sich ja dann nur um Mikrosekunden. Dass kann ja
eigentlich nicht zu so einer großen Abweichung führen.
Ich hatte mir überlegt, ob es vielleicht am Oszillator liegt. Aber als
ich dem Keramikschwinger gegen den sehr viel genaueren Quarz
austauschte, lief die Uhr zwar nicht mehr zu schnell, dafür aber viel zu
langsam.
Dass auch Methode 4 nicht genauer ist, wundert mich dann doch schon. Der
Fehler soll durch Operationen im Quellcode ausgeglichen werden. Aber
trotzdem habe ich extreme Abweichungen.
Wie erzeugt ihr denn genaue Zeiten?
Kennt jemand einen Link zu einem genaueren Timer bzw. Uhr, der brauchbar
ist?
Wo könnten z.B. in Methode 2 beim Interupt diese groben Abweichungen zu
erklären sein?
mfg Wolfram Hildebrandt
übliche MC-Quarze sind bei weitem nicht so genau, wie oft angenommen
wird. Sie sind zwar relativ stabil gegen Frequenzänderung, absolut sind
sie jedoch doch ein ganzes Stück neben der Sollfrequenz. Ein weiteres
Problem: jeder Quarz hat eine Reihen- und eine Parallelresonanz, die
liegen etwas auseinander. Wenn die Frequenz in Reihenresonanz angegeben
wird, der Osz. aber in Parallelresonanz läuft, hast du schon mal einen
systematischen Fehler.
Ob ein Timerüberlauf direkt oder ein paar Takte später erkannt wird, hat
keine Auswirkungen, da sich dieser Fehler nicht summiert.
Abhilfe:
-genaue Quarze verwenden (sieht man direkt am Preis, statt 49Cent kosten
die dann 8Euro,
-Einsatz einer echten RTC (z.B. von Dallas), hat auch den Vorteil, daß
die bei Stromausfall weiterläuft
-Softwarekalibrierung
-Einsatz eines ext. Oszillators mit 32,768KHz (Uhrenquarz), evtl. mit
Teiler, so daß du jede Sekunde einen ex. Interrupt bekommst.
Es stimmt, MC-Quarze sind nicht absolut genau. Sie müssen ja auch nur
genügend genau sein, damit eine RS-232 oder Ethernetverbindung usw.
synchron bleiben.
Sie sind aber stabiler und weniger temperaturabhängig, als Uhrenquarze.
Das liegt einfach an dem anderen Frequenzbereich (mehrere MHz).
Max 1 Sekunde pro Tag sollte man also erreichen können.
Wenn ich das jetzt richtig verstanden habe, ist beim PIC ein Timer nicht
so einfach neu zu laden. Deshalb sollte man ihn ohne Vorteiler
durchlaufen lassen und die nötigen Korrekturen bei den nachfolgenden
Teiler-Bytes im SRAM machen.
Das Prinzip der Softwarekorrektur habe ich hier für den 8051
beschrieben:
http://www.specs.de/users/danni/appl/soft/clock/timebase.htm
Aber auch normale Quarzuhren müssen abgeglichen werden. Höchstens ganz
billige Werbegeschenkuhren werden nicht abgeglichen und haben dann auch
große Abweichungen.
4s in 30min sind aber auch ohne Abgleich viel zu viel und deuten auf
einen Softwarefehler hin.
Peter
Software-Fehler?
Im Anhang ist der Quellcode in dem mittels Überlauf des TMR0 alle 4ms
ein Interupt ausgelöst wird. Dies wird dann 250 durchlaufen.
Wo könnte denn da der Fehler in der Genauigkeit liegen?
Wie war das doch gleich mit dem Zieh-Kondensator?
Kann ich damit meinen Quarz anpassen?
mfg Wolfram Hildebrandt
Nur eine blöde Idee dazu:
Versuchs doch mal mit der atomgenauen Zeit :)
Siehe z.B. hier:
Two-Transistor Atomic Frequency Standard
http://www.techlib.com/electronics/atomic.html
Das kann man mit Anpassungen sicher auch leicht an einen Mikrocontroller
anschließen. Ich plane das schon. Nur mußt Du bei Verwendung mit
uC darauf achten, daß der analoge 50Hz-Teil gut gegen die Einstreuungen
des uC abgeschirmt ist.
Lustig!
Wenn ich aber diese Signale aus dem Netz auffangen soll, muss ich aber
wohl in der Nähe zu so einem solchen sein. Dann kann ich ja direkt die
50Hz aus dem 230V Netz nutzen und ein Kabel dran legen, wie viele (alte)
Wecker es tun.
Aber noch mal zu meinem Problem: Es muss doch einen Weg geben, wie eine
brauchbare Uhr mit dem PIC 16F84 hinzubekommen ist. Wenn es nicht am
Oszillaor liegt, zumindest nicht in dem Maße, wo ist denn dann der
Fehler. Der *.asm File ist ganz oben in diesen Beitrag.
Was ich mir evtl. vorstellen könnte, ist, dass die
Interuptserviceroutine zu lang ist, und nicht alle Takte erkannt
werden??
das Problem ist einfach, daß hier nicht mehr viele Leute sind, die was
mit PICs machen, schon gar nicht in Assembler. Der Befehlssatz ist
einfach zum Ko...
Ich kenn mich mit dem PIC nicht aus, deshalb kann ich Dir nur sagen, wie
es mit dem 8051 oder dem AVR geht.
Aber vielleicht hast Du einen Simulator, dann kannst Du Dir doch
anzeigen lassen, wieviel Quarztaktzyklen 1 Sekunde, 1 Minute usw.
dauert.
Und dann siehst Du, ob es ein Softwarefehler ist.
Peter
Hm.
Ich bin mir nicht sicher, ob das im PMLAb geht. Ich glaube eher nicht.
Prinzipiell habe ich nichts gegen 8051er oder AVRs.
Wie wäre denn da das 1Hz Signal zu generieren? Wie genau wäre das dann?
Zu dem Quarz: die Quarze bei Conrad haben eine Toleranz von 30ppm. Aber
die 4s Differenz pro 30min können ja dann wohl nicht am Quarz liegen,
wenn einer mit 100pm bei 12Mhz nur 6s pro Tag abweicht.
Auf jeden Fall wohl Software-Fehler.
Hallo
Nochmal die Software betreffend:
Der einzige große Fehler, den ich mir vorstellen könnte, wäre, dass die
Interuptserviceroutine zu lang ist und nicht unter 4ms (Interuptzeit)
zuende ist.
Bei 1us pro befehl hätte ich dann aber 4000 Befehle, Sprungbefehle
ausgenommen. Das ist doch ziemlich viel.
Im der Interuptroutine rufe ich die Unterprogramme INCREASE, OUT und
WECKVERGLEICHSEC auf. In INCREASE rufe ich alle Nase lang OUT auf.
Vielleicht zu oft?
Die Interuptroutine habe ich jetzt verkürzt.
Die sollte nun auf jeden Fall in dem Fenster von 4ms ablaufen.
Die Uhr läuft jetzt testweise ca. 30 min und wieder 4s Abweichung.
Ich habe die Uhr jetzt passend gemacht.
Der Fehler von "9s pro Stunde zu langsam" wird nach jeder Stunde wieder
zu den Sekunden addiert.
Das ist zwar nicht besonderes elegant, ich weiß aber momentan keine
andere Lösung.
mfg Wolfram Hildebrandt
Wenn ich das richtig verstanden habe, wird beim PIC bei jedem Schreiben
auf den Timer der Vorteiler zurückgesetzt.
Du must also unweigerlich Takte verlieren, d.h. zu langsam sein.
Abhilfe:
Entweder keinen Vorteiler oder den Timer durchlaufen lassen.
Bei Deinem Takt von 1MHz:
1MHz 32 256 = 122,07
Du läßt also das Teilerbyte im SRAM durch 122 teilen.
Der restliche Fehler ist dann:
1s - 1/(1MHz 32 256 / 122) = 576µs
Wenn Du dann einmal je Sekunde einen anderen Teilerwert (126) nimmst,
ist Dein Fehler nur noch:
1s - 1/(1MHz 32 256 / ((59 * 122 + 126) / 60)) = 30µs
Das sind dann 2,5s/Tag.
Peter
Sorry, ein Dreckfuhler hat sich eingeschlichen, es muß natürlich heißen:
"Wenn Du dann einmal je Minute einen anderen Teilerwert (126)
nimmst,..."
Peter
Der Vorteiler bleibt schon gleich.
Den habe ich immer auf 32 eingestellt, aber nur einmal am Anfang
initalisiert.
Der Timer wird jedoch in jedem Interupt neu beschrieben.
Max. kann der TMR0 256 (8 Bit) aufnehmen. Davon brauche ich jedoch nur
125 (dann sind 4ms vorbei). Also wird der Timer in jedem Interupt neu
mit 130 geladen. Dieser Wert wird jedoch erst nach ca. 3 Zyklen (3us) in
den TMR0 geladen.
Diese Sache mit dem Ausgleichen habe ich zufällig gestern in einem alten
EAM-Magazin gesehen.
Aber wenn man die Fehlerquellen zusammenrechnet:
Interupt: 2-3 Zyklen (max.3us)
TMR0 laden: 3 Zyklen
kein weiteres Polling etc.
D.h. jede 4 ms großzügig 10us Fehler. 1s hat dann 2500us, also 2,5ms
Fehler. Mal 60 = 150ms in der Minute = 9000ms in der Stunde. Das ist
genau mein Fehler von 9s/Std.
Das überrascht mich jetzt doch selbst. Dieser kleine Fehler scheint wohl
tatsächlich die Ursache zu sein.
Hi!
Du hast doch alles was du brauchst!
Interupt: 2-3 Zyklen (max.3us) Wieso 2-3 Zyklen?? Entweder 2 oder 3,
einen Wechsel der Zykluszeiten kenne ich nicht. Also genau nachschauen!
TMR0 laden: 3 Zyklen
Du brauchst 125 Zyklen. Übrigens Timerüberlauf ist von
255->0= 256 Takte! Also berechnet sich dein Timerwert aus:
0-125+2 (oder auch 3) +3 (Das versteht eigentlich jeder Assembler) Das
sind dann 136 oder 137 als Timerladewert.
Das wäre doch ein Unding wenn das nicht hinzubekommen ist.
MFG Uwe
als erstes müßtes du mal in Erfahrung bringen, was der Vorteiler bei
einem Neuladen des Zählregisters so treibt. Läuft der durch (nehme ich
an, weiß es aber nicht) können die paar Takte nicht der Fehler sein.
Der Vorteiler gibt einen Takt an den Zähler, Zähler läuft über und löst
einen Int aus. Wenn du mit Vorteiler 32 arbeitest, mußt du nur zusehen,
daß auf jeden Fall innerhalb der nächsten 32 Takte das Zählregister
wieder mit dem neuen Startwert geladen ist, dann verlierst du nicht
einen einzigen Takt.
Also Sprung zur ISR, Flags retten, neuen Zählerwert schreiben - das
sollte doch wohl in 32 Takten möglich sein, es sei denn, der Prozessor
treibt sich gerade in einer anderen ISR herum, dann wirds knapp.
Prioritäten verteilen (wenn möglich) bzw. den Rest im Polling laufen
lassen.
Hm.
Das stimmt eigentlich. Der interne Takt beträgt 1Mhz. Plus Vorteiler von
32 bedeutet alle 32us Takt an den Timer.
Der Timer solte eigentlich innerhalb weniger us geladen sein.
32 us sollten da tatsächlich vollkommen ausreichen.
Dann kommt der Fehler aber nicht mehr hin.
Dann habe ich nur den Befehl, der gerade noch zuende ausgeführt wird,
wenn der Interupt auftritt. Also meistens (außer Sprungbefehl) 1us plus
2us für den Sprung zur ISR.
Dann wären das aber nur ca. 3s/Std Fehler, ich habe aber 9s/Std.
Ich muss ja eigentlich nur in jedem Interupt zusätzlich 10us vertrödeln.
Ich habe gerade 10 nop-Befehle in der ISR eingefügt. Also 10us
zusätzlich.
Der PIC, den ich gerade hier habe, habe ich aber schon mal halb
gegrillt. Der wird unverschämt heiß. Ich fahr mir aber gleich ein paar
neue holen und teste das dann einfach mal mit 10us zusätzlich.
mfg Wolfram Hildebrandt
ich fürchte, du hast es immer noch nicht verstanden. Wenn der Timer
nachgeladen ist, ist es völlig wurscht, wie lange du danach
weitertrödelst, der nächste Int kommt exakt 4ms nach dem vorherigen. Die
"Trödelzeit" spielt keine Rolle, der nächste Int kommt zwar dann relativ
eher nach Verlassen der ISR, aber trotzdem genau 4ms nach der
vorherigen.
Bei einem Fehler von 0,25% scheidet eigentlich auch der Quarz als
Fehlerquelle aus, soweit liegen die nicht daneben.
Hast du mal nachgeschaut, was der Vorteiler beim PIC macht? Wenn der mit
zurückgesetzt wird, ist das der Fehler. Kommt auch größenordnungsmäßig
hin. Nach Timerüberlauf, ISR angesprungen und Timer nachgeladen sind
etwa 10 Takte vergangen, der Vorteiler steht also eigentlich schon
wieder auf 10, der nächste Impuls für den Timer müßte also nach weiteren
22 Takten kommen. Wird der Vorteiler mit zurückgesetzt, kommt er aber
erst nach 32 Takten, der Fehler bei 4ms: 4010/4000: 0,25%!
Hallo
Dass das mit der Verzögerung im Interupt Mist ist, stimmt.
Was ich wie lange in der ISR mache, ist ja egal, solange es nicht über
4ms dauert. Dumm gedacht.
Ich habe gerade mal in einem meiner PIC-Bücher nachgesehen. Der
Vorteiler wird durchaus immer bei jedem Schreiben oder Löschen des Timer
zurückgesetzt!
na also.
Was kannst du jetzt tun? Sauberste Lösung wäre ein Quarzwechsel und den
Timer ohne Vorteiler und ohne Nachladen komplett durchlaufen lassen.
Geeignet z.B. 2.048MHz (1.024 ginge auch, weiß aber nicht, ob es die
überhaupt gibt) , alle 125µs würde der Timer-Int ausgelöst.
Ansonsten per Software korrigieren, exakt ausklamüsern, wieviele Takte
der Vorteiler verliert. Gibt dann mehrere Wege, das zu korrigieren. Da
die Int-response-time aber wahrscheinlich nicht exakt angebbar ist,
kommt es aber auch dabei zu weiteren unbestimmbaren Taktverlusten.
Oder du lässt den Timer ohne Nachladen durchlaufen und rechnest mit
256µs als Zeitbasis, einfach in der ISR eine long-Variable
incrementieren und daraus im Hauptprogramm eine darstellbare Zeit
berechnen. Nach 337500000 Ints beginnt ein neuer Tag. Relativ viel
Rechnerei, aber exakt.
@ crazy horse:
Wie kommst du denn auf 125us Interupt?
Quarz 2048000Hz: interner Takt im PIC: 20480000/4= 512000Hz.
1/512000= 0,0000019s = 1,9us. 1,9us * 256 (voller TMR0)=0,0004864. Also
alle 486,4us ein Interupt. Oder Denkfehler bei mir?
ja, habe ich mir schon gedacht. dass der AVR nicht durch 4 teilt, war
mir bekannt. beim nachrechnen kam ich aber nicht auf dein ergebnis, weil
ich mit einem billigen 8stelligen Taschenrechner gerechent habe. deshalb
kam bei mir immer nur ein ähnliches ergebnis heraus (sehr viele
nachkommanstellen).
Also, ich nehme einen Qaurz mit 2,048Mhz. Vorteiler aus. TMR0
durchlaufen lassen. Dann habe ich alle 0,5ms einen Interupt, d.h. ich
muss 2000 Interupts abwarten, bis 1s vorbei ist. Also acht mal eine
Schleife von 250.
Mist.
Bei einem Quarz von 2,048Mhz habe ich nur 500us/1,9us = ca. 263 mögliche
Befehle in der ISR. Da liege ich aber deutlich drüber. D.h ich kann mein
Programm nicht in so einer kurzen Zeit ausführen.
Mit 4,096Mhz komme ich wohl auch nicht hin.
Ich versuche nochmal die Real Time Clock DS1302. Die kann man dann über
I2C auslesen.
Ob mit man auch ich gemeint bin, wird sich zeigen. Der PIC 16F876 hat
für I2C eine Hardwareunterstützung.
Ist denn der DS 1302 voll I2C kompatibel? (Sieht für mich zumindest so
aus.)
Datenblatt im Anhang.
O.K. ich gebe auf.
Ich habe doch schon alle nötigen Reloadwerte für 4MHz hingeschrieben.
Oder wird heutzutage das Rechnen mit gebrochenen Zahlen nicht mehr
gelehrt ?
Peter
Mann oh mann, langsam wirds lästig.
Letzter Versuch. Gehen wir einfach mal von 4.096MHz/250µs Interrupt aus.
In der ISR machst du weiter nichts, als bis 4000 zu zählen. Bei 4000
wird der Zähler wieder auf 0 gesetzt und ein Flag gesetzt, welches
anzeigt: eine Sekunde ist um!
Im Hauptprogramm kannst du dann in aller Seelenruhe dein Uhrprogramm
laufen lassen.
Sekundenbit gesetzt?
nein->weiter warten
ja->Bit zurücksetzen,Sekundenzähler erhöhen, evtl Minuten erhöhen, evtl
Stunden erhöhen
Anzeige aktualisieren
Ja, das stimmt. Wenn ich ein Flag setze, wenn 250us * 4000 =1s vorbei
sind, und dies dann außerhalb auswerte, habe ich keine Zeitprobleme in
der ISR. Man möge mir meine Anfängerfehler bitte verzeihen.
Ich wollte eigentlich noch weiter gehen und Tage, Wochen und Monate
zählen.
Aber der DS 1302 kann das ja alles. Das ist eigentlich sehr viel
effektiver als alles selbst zu schreiben.
Nur die Auswertung per I2C habe ich noch nicht hinbekommen.
Aber das MSSP-Modul des 16f876 habe ich da noch nicht gekannt (das ist
u.a. für I2C zuständig).
Hat schon mal jemand eine ähnliche Real Time Clock ausgewertet?
Wenn Du den 16F876 verwenden willst, warum nutzt du dann nicht das
CCP-Module? Dann gibt es nicht den Fehler mit den 3 oder 4 Zyklen bis
zum Einsprung in die ISR und man kann leicht die Uhr auf den verwendeten
Resonator bzw. Quarz abgleichen.
MfG
Steffen