>wie Du 32768 durch 1000 ohne Rest teilen wilst.
@Peter & Stefan:
Man kann zwar 32768 nicht ohne Rest durch 1000 teilen, aber man kann
trotzdem aus einem 32768-Takt einen 1 ms-Takt gewinnen.
Bei einem Compare-Wert von 8 produziert der Uhrenquarz-Timer Interrupts
mit der Frequenz 32768/8 Hz = 4096 Hz. Mit dieser Frequenz den µC eine
(sehr kleine) Rechnung durchführen zu lassen, sollte OK sein.
Ein softwaremäßige Frequenzteilung durch 4 nach diesem Schema
---------------------------------
Interrupt:
inc(Count);
IF (Count==4)
{
Count=0;
OneMillisecondHandler;
}
reti
---------------------------------
würde auf die Frequenz 1024 Hz führen. Das ist etwas zu viel, bzw. die
"OneMillisecondHandler"-Aufruftakte wären etwas zu klein (1/1024 s =
0.9765625 ms statt der gewünschten 1 ms).
Man kann nicht erreichen, daß jeder Takt genau 1 ms lang ist (weil
32768 ist nicht ohne Rest durch 1000 teilbar ist), aber machbar ist
eine Taktlänge von 1 ms im zeitlichen Mittel (!).
Dazu ist es notwendig, den Grenzwert des Software-Teilers variabel zu
machen. Wir lassen die Variable Count nicht in allen Fällen bis 4
zählen, sondern ab und zu auch mal bis 5 (!). Die Idee ist, die etwas
zu kurzen 4er-Takte durch eine genau passende Anzahl etwas zu langer
5er-Takte auszugleichen. Wie groß diese "passende Anzahl" ist,
rechnen wir aus:
(N*4 + n*5) * (1/4096) s
-------------------------- = 1 ms
N + n
Die linke Seite ist das zeitliche Mittel des Zeittaktes, den wir im
Durchschnitt erhalten, wenn wir die Variable "Count" N mal bis 4, und
n mal bis 5 zählen lassen.
Das liefert:
N * 4 + n * 5 = (N + n) * 4096/1000
4000 N + 5000 n = 4096 N + 4096 n
904 n = 96 N
n = 96/904 N
n = 12/113 N (12/113 ist nicht mehr weiter kürzbar)
Damit wissen wir, daß auf je 113 4er-Takte genau 12 5er-Takte kommen
müssen, damit die Sache stimmt (wer's nicht glaubt, mache unverzüglich
die Probe...).
Der Interrupt-Handler müssen wir wie folgt gestalten:
---------------------------------
Interrupt:
IF (M>=12) CountMax=4 ELSE CountMax=5;
inc(Count);
IF (Count==CountMax)
{
Count=0;
OneMillisecondHandler;
}
inc(M);
IF (M==113+12) M=0;
reti
---------------------------------
Die Routine "OneMillisecondHandler" wird jetzt 90.4% einer Sekunde
mit einem Takt von 0.9765625 ms ausgeführt, und in den restlichen 9.6%
mit einem Takt von 1.2207 ms. "Zusammen" resultiert daraus ein
mittlerer Takt von genau 1 ms.
Wer sich nicht scheut, kann statt eine "Count"-Variable zu verwenden,
dieses Prinzip auch direkt mit dem Compare-Match-Register des
Hardware-Timers realisieren. Ohne die "M"-Variable geht es
allerdings nicht.
Ich hoffe, das war verständlich.