Hallo Leute
Möchte auf einem PIC18F2550 jede Sekunde einen Zähler um 1 erhöhen.
Daher will ich den Timer0 Interrupt verwenden. Habe noch nie mit einem
Timer Interrupt gearbeitet, und daher einmal das Datenblatt zur Hand
genommen.
Folgende Überlegungen:
Bit0-2: Prescaler soll 256 sein (TOPS0=1 TOPS1=1 TOPS2=1)
(1 Timertakt müsste dann mit Prescaler 21,33uS betragen)
BIT3: PSA = 0 Timertakt kommt von Prescaler
Bit4: T0SE = 0 Für meine Anwendung unwichtig
Bit5: Systemtakt soll verwendet werden (T0CS = 0)
(bei 48Mhz durch 4 müsste der Timertakt 12Mhz betragen. 1 Timertick =
83,3nS)
Bit6: T08Bit = 0 Timer0 ist 16Bit Timer
(46875 Timerticks = 1 Sekunde. Also muss Timer0 mit 18661 vorgeladen
werden)
BIT7: TMR0ON = 1 Timer 0 einschalten
Ist meine Überlegung bezüglich der Vorladung des Timers richtig, oder
habe habe ich da etwas übersehen?
Dankeschön für eure Antworten im Vorhinein
> 1 Timertakt müsste dann mit Prescaler 21,33uS betragen)
das stimmt bei einem internen takt von 48MHz
den rest habe ich mit dem datenblatt nicht kontrolliert. falls du C18
verwendest, nimm doch die funktion OpenTimer0() auf seite 62 von
http://ww1.microchip.com/downloads/en/devicedoc/mplab_c18_libraries_51297f.pdf
diese funktion wird vom C18-compiler in 2 oder 3 befehle umgewandelt,
die genau die richtigen register korrekt setzen - der vorteil ist, dass
wenn du den PIC-typ änderst, du die funktion nicht umschreiben musst,
ganz abgsehen von der leseerlichkeit des codes.
Nein ich verwende den Mikroebasic Compiler von Mikroelektronika.
48Mhz Interner Takt stimmt. Wird über den PLL erzeugt.
Mir ging es mehr darum, ob ich das Ausrechnen der einzelnen Zeiten, und
das voreinstellen des Timers richtig kapiert habe.
t = frequenz, mit der der timer0 hochzählt
t = (interner takt / 4) / prescaler
edit: wieso nicht C18? der ist gut und gratis.
ps: auch der mikrobasic wird irgend so eine Opentimer-funktion haben
Sorry, das war mit 8bit timer, nur da bist du dir sicher, daß du keinen
Fehler hast. Bei 16 bit kannst du den Timer laden, nur da hängst du dir
einen Fehler rein, der mittels ASM Befehle sowie Register timing
korrfigiert
werden muß, welcher aber nur definitiv korrigiert werden kann wenn
der timer0 keinen Prescaler hat, ansonsten hat der Pic nähmlich einen
Jitter von 1 Instruktionszyklus, was ca 83.333 Nanosekunden sind welche
in deinem Beispiel nicht korrigierbar sind, ca 2.4mS am Tag, der Rest
ist korrigierbar, aber nur mittels Disassembler, Instruktionen Zählen
sowie Datasheet genau lesen. Wenn man keinen Vorteiler verwendet, dann
ist dieser Jitter auch korrigierbar, was aber nicht Zweckmäßig ist.
Deshalb, wenn es um genaue Zeit geht, versucht man einen free running
Timer zu haben, den man nicht im Interrupt neu läd.
> Sorry, das war mit 8bit timer,nur da bist du dir sicher, daß du> keinen Fehler hast.
ja?!? das haste mit 8bit auch. sobald die frequenz nicht 2^x ist,
kommste auf krumme kommazahlen beim timer, egal ob mit 16 oder 8 bit.
mit 16 bit hast du bei gleichem code einfach 256 mal weniger interrupts
als bei 8 bit ;-)
aber ja: entweder assembler-code anschauen und im code den
timer-vorladewert anpassen oder einen timer über einen externen
32.768kHz-quarz betreiben.
2.4 ms am Tag sind genau genug. Zur Zeit habe ich es provisorisch mit
einer Variable im Main gemacht. Der läuft pro Sekunde !! 200mS !! plus
minus genau.
Einmal betragen 5 Sekunden nur 4 Sekunden, einmal 6 Sekunden und das
nächste mal irgendwo dazwischen :-) War bis jetzt noch immer genau
genug. Soll ja nur ein freier Logger weren, der alle 20 Minuten einen
Wert abspiechert, und keine Uhr. Mir ging es wie gesagt nur um die
Umrechnung. Dankeschön dafür.
Stimmt, hatte mich verrechnet, sorry war Windows taschenrechner
1(µS)/12(T$aktzeit)=0.083333µS*256(Prescaler)*256(8Bit)=5461.333333µS
je Timerüberlauf, ca 5.46mS sehr praktisch für Timeouts, entprellungen
usw.
1S (1000/5.46133333) ergeben 183 überläufe. Gegenprobe
183*5.461333 = 999423.9999, da fehlen also 576 µS je Sekunde.
5461... /576 = 9.481481481, und jetzt 256 zum Quadrat durch ANS
65536/9.481...=6912 . Dies ist jetzt dein Korrekturfaktor bei einer
16bit Variable.
Gegenprobe: 65536/6912=9.481481481 , dasselbe wie oben.
Das heißt, du hast eine free running Timer mit diesmal ca 5mS ticks
sowie
eine 16bit Variable zur Korrektur um eine genaue Zeit zu erhalten um
damit eine Null Fehler zeit zu haben. Max Abweichung 5.461mS aber
keinen kummulativen Fehler.
C Code zur Veranschaulichung
Es wird angenommen, daß zum Systemstart alle Variablen mit 0 Belegt
werden.
time_error ist eine 16bit Variable, time_sec ist unixtime warscheinlich
32bit und time_cnt ist eine 8bit variable.
time_error+=6912; // korrectur factor
if (!CURRY) // wenn die variable nicht übergelaufen ist
if(!time_cnt--) {
time_cnt=183;
time_sec++;
}
Ansonsten 16bit Wert 46875 im Timer in der Interruptroutine laden,
und mit einem Fehler von ca 2Sekunden zuviel am Tag leben, oder
Wert 46874 laden, disassemblieren, timing anpassen auf 21µS aber die
2 Taktzyklen delay nach dem Laden des Wertes beachten, eventuell auch
46873 laden, mit nop/goto die Zeit korrigieren und der fehler ist dann
nur mehr ca 2ms zuviel am Tag.