Wer einen genauen Frequenzzähler zur Verfügung hat, kann die Gangabweichung unter Kontrolle bringen:
Aber wie erreicht man eine Genauigkeit von 10-6 bei lauter
8-bit-Teilern?
Irgendwelche Fummeleien mit umschaltenden Teilern sehen nicht gerade
elegant aus...
Die Lösung ist ein genügend breiter Überlauf-Zähler. Wie funktioniert das?
... dec r18 ;r18 sei der ISR-Teiler brne ende ldi r18,32 call SekundeVergangen ende: ... |
... ldi r16,8 add r18,r16 ;r18 sei der ISR-Akkumulator brcc ende call SekundeVergangen ende: ... |
| Tint = 1024 * 256 / fosz, fosz = 8000000 Hz |
Erwischt! Mit Zeiten rechnen ist einfacher!
| Tint = 1024 * 256 * Tosz, Tosz = 125 ns |
Die Zeit beträgt in diesem Falle:
| 0,032768 s |
Also eine Zahl, die kleiner als Eins ist, und das ist gut so!
Jetzt brauchen wir nur noch ein bisschen Festkommaarithmetik, nehmen wir
32 bit für eine Auflösung von bis zu 10-9.
Dazu ermitteln wir einen (endlichen) Bruch, in dessen Nenner die computerfreundliche Zahl 232 steht, wir erweitern also um 232:
| Tint = 1024 * 256 * Tosz * 232 / 232 |
Und fortan nehmen wir davon nur den (gerundeten) Zähler. Der ist eine riesige Ganzzahl und beträgt hier:
| 140737488 - hexadezimal 0x08637BD0 |
Und was macht man nun damit?
Diese Konstante wird bei jedem Interrupt auf einen 4-Byte-Akkumulator addiert;
bei jedem Überlauf ist eine Sekunde vergangen!
In Atmel-Worten:
Exakt gleich lange Sekunden können nur mit einem gezogenen Quarz
erreicht werden.
Andererseits darf SekundeVergangen auch die Interrupts freigeben;
darf dann allerdings nicht mehr als eine knappe Sekunde verbrauchen,
alles bei voller sonstiger Interruptlast.
Ein Uhrenvergleich mit einer Funkuhr ist ein sehr langwieriges Unterfangen
und sollte nur im Notfall nach guter Vorbereitung erfolgen.
Als Messzeit sollte man 24 Stunden einplanen.
Die Quarzfrequenz darf keinesfalls direkt am Quarz gemessen werden,
weil die Tastspitze mit ihrer (kapazitiven) Last unweigerlich den
Quarz wegzieht.
Schreiben Sie in Ihre ISR Kode hinein, das ein Ausgabepin hin- und her
schaltet (toggelt, halbe Frequenz beachten!) oder pulst.
Oder aber, geben Sie im Sekundentakt einen Puls aus.
Hierbei ist der Jitter ist für das Kalibrieren katastrophal, deshalb
benutzt man zunächst einen »geraden« Wert für die Konstante, bspw. 0x08000000.
Die Quarz-Periodendauer ergibt sich dann einfach zu:
Notieren Sie dabei die Temperatur der Schaltung.
Für eine Kennlinie brauchen Sie einen Gefrierschrank und einen Ofen,
um für jede Temperatur (bspw. alle 5 °C) die Oszillatorperiodendauer zu messen.
Dieser 4-Byte-Akkumulator beinhaltet die »Nachkomma-
Und das ist alles, was von der grauen Theorie übrig bleibt!
.dseg
VierByteAkku: .byte 4
.cseg
Timer0ISR:
push r16
in r16,sreg
push r16
push xl ;xh sei stillschweigend stets Null
push r4
ldi xl,VierByteAkku
ld r4,x
ldi r16,$D0 ;letztes Byte
add r4,r16
st x+,r4
ld r4,x ; das schreit
ldi r16,$7B ; nach
adc r4,r16 ; einem
st x+,r4 ; Makro!
ld r4,x
ldi r16,$63
adc r4,r16
st x+,r4
ld r4,x
ldi r16,$08 ;erstes Byte
adc r4,r16
st x+,r4
pop r4
pop xl
jnc ende
call SekundeVergangen
ende: pop r16
out sreg,r16
pop r16
reti
Jitter-Betrachtungen
Der Sekunden-Tick tritt alle 31..32 Zeitgeber-Interrupts auf.
Die Programm-Reentranz-Betrachtungen
Das Unterprogramm SekundeVergangen darf keinesfalls länger als
knapp zwei Interruptperioden Zeit verbrauchen,
denn verschluckte Interrupts führen zur falschen Uhrzeit!
Andernfalls kommt es zur Reentranz (= ungewollte Rekursion).
Dagegen helfen selbstgebastelte Semaphoren (siehe anderes Kapitel).
Kalibriervorgang
Sie benötigen dazu ein genügend genaues Frequenz/Periodendauermessgerät.
Lassen Sie es nach Vorschrift/Bedienungsanleitung warmlaufen.
Tosz = Tgemessen
/ Vorteiler / 256 ( / 32 für Sekundentakt)
haftmann#software, 22.6.2004