PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer Stoppuhr ist ungenau



Björn
12.08.2005, 18:02
Ich habe diesen Code mit einem ATmega8, intern auf 1Mhz getaktet:



'================================================= ==============================
' Compiler
'================================================= ==============================
$regfile = "m8def.dat" 'Mega32
$crystal = 1000000
'-------------------------------------------------------------------------------


'================================================= ============================

'Hier wird der Timer und der Teiler festgelegt
Config Timer1 = Timer , Prescale = 64
On Timer1 Timer_irq
Const Timervorgabe = 49911

Dim Sekunden As Integer

'================================================= ==============================


Enable Timer1
Enable Interrupts

'================================================= ==============================
' Hauptschleife
'================================================= ==============================

Do

Loop

End

'================================================= ==============================

Timer_irq:
Timer1 = Timervorgabe

Decr Sekunden
Return


Jedoch hat er auf 300 Sekunden ca. 2 Sekunden abweichung.
Was ist falsch?

Gruß, Björn

SprinterSB
12.08.2005, 18:23
Du betreibst Timer1 besser in einem anderen Modus:
Clear Timer on Compare Match und bedienst nicht den Overflow-Interrupt, sondern den Compare Match Interrupt.

Dadurch übernimmt die Hardware das Neusetzen von Timer 1 und nicht wie in deinem Beispiel die Software.
Du verbrätst ja Zeit, bis du nach dem Interrupt wirklich dein Timer1-Wert neu schreibst.
Ob der Wert richtig ist hab ich nicht nachgerechnet.
Zudem überträgt sich die Ungenauigkeit der Takterzeugung auf die Genauigkeit der Uhr.
RC-Oszi ist ungenauer als Quarz.

Björn
12.08.2005, 18:26
Also meinst du ich soll ein externes Quarz verwenden?

Gruß, Björn

SprinterSB
12.08.2005, 18:32
Quarz mache eine bessre Genauigkeit.
Der Fehler bei deiner Uhrliegt aber an der unzureichenden Ausnutzung der Hardware.
Wenn du ein Quarz drantust wird mit dem Programm die Genauigkeit auch miserabel sein...

Björn
12.08.2005, 18:39
Was ist denn Compare Match etc. - Hab ich nocht nicht verwendet. Gibt's da irgendwo Beispiel Code?

Gruß, Björn

Björn
12.08.2005, 19:01
Den Code habe ich übrigens aus diesem rnAVR Programm.
Und selbigen Code hatte ich mal mit nem 7,.... Quarz, das ging meiner Erinnerung nach ganz gut.

Gruß, Björn

Marco78
12.08.2005, 20:19
Musst du wirklich jedes Problem in zwei Beiträgen besprechen???

Björn
12.08.2005, 20:22
Mmhh... ja sorry - :-# Ich dachte mir nur das passt nicht zum Thema "Stoppuhr Source".. 8-[

Soll nicht mehr vorkommen.

Gruß, Björn

sebastian.heyn
13.08.2005, 20:11
ich glaube es entsteht auch eine art ungenauigkeit dadurch, dass beim aufrufen der interruptroutine zeit verbraucht wird. ein schnellerer takt dürfte da glaube ich verbesserung bringen

Marco78
13.08.2005, 20:38
ich glaube es entsteht auch eine art ungenauigkeit dadurch, dass beim aufrufen der interruptroutine zeit verbraucht wird. ein schnellerer takt dürfte da glaube ich verbesserung bringen
Ein schnellerer Takt bringt bloß noch mehr Fehlerzeit. Der Preload muss angepasst werden. Es sind nur ein paar wenige Takt die beim aufrufen einer ISR 'verschwendet' werden.

sebastian.heyn
14.08.2005, 09:39
wie das? wenn du angenommen 20 takte bräuchtest, um den irq aufzurufen, dann sind die 20 takte mit einem schnelleren takt viel schneller abgearbeitet, oder?

Marco78
14.08.2005, 09:42
Ja, aber die Timervorgabe stimmt dann auch nicht mehr.
Wieviel schneller soll der Takt denn sein? Ist es nicht einfacher 20 Takte von der Timervorgabe abzuziehen?

sebastian.heyn
14.08.2005, 14:20
Na das beim ändern der Taktfrequenz die timerwerte geändert werden müssen dürfte ja wohl klar sein, oder?

irgendwo habe ich mal gelesen, wieviel takte bascom braucht, um einen irq aufzurufen, ich glaube es waren 12 oder so. aber bei 16mhz stelle ich mit vor das das ziemlich lange dauern dürfte bis man die abweichung reel messen kann...

Björn
20.08.2005, 08:43
Naja, ich habe aber ja 1 Mhz. Wenn er pro Sekunde 12 Takte abweicht, wären dass in 5min: 300 * 12 = 3600 Takte, naja gut - das sind noch nicht die 2 Sekunden ;-(

Gruß, Björn

Marco78
20.08.2005, 09:20
Nimm doch einfach einen anderen Wert für Timervorgabe.
Änder den Wert etwa (+- ein paar hundert um zu sehen was passiert) und wenn du meinst jetzt läuft sie relativ genau, lass die Uhr eine Stunde laufen und überprüfe wie groß die Abweichung dan ist.

Björn
20.08.2005, 09:21
Das hab ich schon gemacht ;) Nur ich dachte vielleicht gibt es eine elegantere Lösung :)

Gruß, Björn

izaseba
20.08.2005, 09:29
Hallo die elegantere Lösung hat Dir schon der Sprinter genannt :


Du betreibst Timer1 besser in einem anderen Modus:
Clear Timer on Compare Match und bedienst nicht den Overflow-Interrupt, sondern den Compare Match Interrupt.

Dadurch übernimmt die Hardware das Neusetzen von Timer 1 und nicht wie in deinem Beispiel die Software.
Du verbrätst ja Zeit, bis du nach dem Interrupt wirklich dein Timer1-Wert neu schreibst.

Gruß Sebastian

Björn
26.08.2005, 15:19
Ja, hab noch nie von gehört oder so - hätte jemand Beispiel-Code?

Gruß, Björn

SprinterSB
26.08.2005, 19:03
So würde es in C aussehen, ein paar defines fehlen, die aber selbsterklärend sind. Übersetzen nach BASIC verbleibt als Hausaufgabe ;-)



void timer1_init()
{
#if defined (__AVR_AT90S2313__)
// Timer1 ist Zähler
TCCR1A = 0;
// Timer1 läuft mit voller MCU clock
TCCR1B = _BV (CS10) | _BV (CTC1);
#elif defined (__AVR_ATmega8__)
// Mode #4 für Timer1 (Manual S. 97)
// und volle MCU clock
TCCR1A = 0;
TCCR1B = _BV (WGM12) | _BV (CS10);
#else
#error Dont know how to setup timer1
#endif

// PoutputCompare für gewünschte Timer1 Frequenz
OCR1A = (unsigned short) ((unsigned long) F_CPU / INTERRUPTS_PER_SECOND-1);

// OutputCompare-Interrupt für Timer 1
TIMSK |= _BV (OCIE1A);
}

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
}

Björn
26.08.2005, 21:34
So würde es in C aussehen, ein paar defines fehlen, die aber selbsterklärend sind. Übersetzen nach BASIC verbleibt als Hausaufgabe ;-)



void timer1_init()
{
#if defined (__AVR_AT90S2313__)
// Timer1 ist Zähler
TCCR1A = 0;
// Timer1 läuft mit voller MCU clock
TCCR1B = _BV (CS10) | _BV (CTC1);
#elif defined (__AVR_ATmega8__)
// Mode #4 für Timer1 (Manual S. 97)
// und volle MCU clock
TCCR1A = 0;
TCCR1B = _BV (WGM12) | _BV (CS10);
#else
#error Dont know how to setup timer1
#endif

// PoutputCompare für gewünschte Timer1 Frequenz
OCR1A = (unsigned short) ((unsigned long) F_CPU / INTERRUPTS_PER_SECOND-1);

// OutputCompare-Interrupt für Timer 1
TIMSK |= _BV (OCIE1A);
}

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
}


Na da hab ich ja was vor mir (hab keine Ahnung von C) :D
Ich glaube aber, ich lasse den Code so, denn ich habe eben ein 7,3728 Quarz eingebaut um den AVR extern zu takten. Jetzt geht die Uhr so genau, dass man auf 5min keine Abweichungen "sehen" kann. Das reicht für meine Zwecke ja aus ;)

Gruß, Björn

Björn
31.08.2005, 19:07
Ok, ich habe mit altem Code und dem 7,3728 Mhz Quarz auf 12 Std. keine nennenswerte Abweichung (keine mit dem Auge sichtbare ;) ).

Damit habe ich das Stoppuhr-Projekt erolgreich abgeschlossen :D

Gruß, Björn

der anmeldefaule E-Fan
01.09.2005, 09:35
...irgendwo habe ich mal gelesen, wieviel takte bascom braucht, um einen irq aufzurufen...

Das kannste Dir im Simulator anzeigen lassen. In der Zeile ganz unten läuft ein Zykluszähler mit. Darfst natürlich die Simulation nur schrittweise durchfühern *g*