PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer Routine -- Ungenau



surfer
01.02.2005, 09:03
Bin wieder auf ein neues "Problemchen" gestossen.

Ich hab mir eine Timer Routine geschrieben, bei der ich den Timer Initialisieren kann und danach die Zeit in ms angeben kann und eine Verzögerung mit der gewünschten Zeit bekomme. Ich habe fix meinen 4MHz Quarz eingestellt und den Prescaler 1024 gewählt. Nun habe ich das Problem, dass ich auf die ms etwa 1/2 ms abweichung habe. Das macht bei 10ms fast schon eine ganze ms aus.... und ich möchte irgendwann mal eine Uhr machen (jajaja, DCF77 wäre auch eine Möglichkeit). Aber ich will halt eine Timer-Routine, auf die ich immer wieder zurückgreifen kann....

Hier mal mein Code. Ich könnte mir denken, dass die Abweichung von den vielen Rechenbefehlen kommt. Gäbe es eine andere Möglichkeit das alles zu programmieren oder wäre es besser in Assembler ein paar Stellen zu schreiben? Danke



/************************************************** ************************************/
* Erstelldatum: 31.01.2005
* Programmname: timer-src.c
* Funktion: Timer-Routine für ms-genaue Zeitschleifen
************************************************** *************************************/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

volatile float a,i,time;

SIGNAL(SIG_OVERFLOW1)
{
a=0;
}

void timer_init(void)
{
TIMSK=0x80;
TCCR1B=0x05;
}

void timer_set(void)
{
i=4000000/1024;
i=1/i;
i=time/i;
i=65536-i;
TCNT1=i;
}

void timer(float zeit_ms)
{
i=0;
a=1;
time=zeit_ms/1000;
timer_set();
sei();
while(a);
cli();
TCNT1=i;
return;
}



/*---------------------- Testprogramm ------------------------------------------------*/

int main(void)
{
DDRC=0xFF; // PORTC als Ausgang definieren
PORTC=0x00; // Alle LED's aus
timer_init(); // Timer initialisieren
while(1) // Endlosschleife
{
timer(10); // 10ms warten
PORTC=0xFF; // Alle LED's an
timer(10); // 10ms warten
PORTC=0x00; // Alle LED's aus
}
}

PicNick
01.02.2005, 09:37
Hi Kollege.
Ich hab deine Rechnung ins Excel eingetragen




T_ms time I.1 I.2 I.3 TCNT1
10 ms/1000 4Mhz/1024 1 / I.1 time/i.2 65536 - I.3
10 0,01 3906,25 0,000256 39,0625 65496,9375

Irgendwie wirst du dich mit den Dezimalstellen beschäftigen müssen, denn ohne Runden zwickt er die weg, und dann fehlt fast ein 1-er.
mfg robert

surfer
01.02.2005, 09:43
Diese Frage habe ich mir beim programmieren des Rechnungsschrittes auch gefragt. Ich habe dann einfach ohne weiteres Vorgehen weitergemacht, weil ich schlicht nicht weiss wie ich runden soll.... Es gäbe sicher einen Standartbefehl in Stdio oder so... aber das braucht halt wieder enorm Speicher (hab schlechte Erfahrungen gemacht).

Vorschläge zum runden?


Nachtrag:
Hab jetzt mal mit dem Rechner einen Wert ausgerechnet und gerundet.... dann manuell ins TCNT1 geschrieben... gibt mir einen für mich genug genauen Wert an. Wenn ich jedoch nebenbei auch noch meine Rechenschritte durchs Programm laufen lasse, gehen etwa (bei 10ms) .3-.4 ms verloren....
Es liegt vielleicht doch an den Rechenschritten, die zuviel Zeit benötigen.....
:-k :-k

PicNick
01.02.2005, 09:57
Ist sicher so, wie du sagst, Ich würd mal fix den Wert für EINE mS vorher ausrechenen und die function "timer()" auf Vielfache vom mS einschränken.
Ein bißchen sparen kannst du auch:
Statt
i=4000000/1024;
i=1/i;
i = time / i
schreib doch
#define DIVISOR 1024 / 4000000

i = time / DIVISOR

is nicht viel, aber Kleinvieh mach auch mist. mfg robert

und

surfer
01.02.2005, 17:11
Hab jetzt verschiedene Möglichkeiten durchprobiert und bin zum Schluss gekommen, dass ich das mit der Routine lieber lasse... die Unterprogramme fressen am meisten Zeit... ich lass es und schreibe die Befehle direkt ins Programm. Timer ist ja schnell reingeschrieben und dann habe ich auf 1ms eine Abweichung von 0.02ms und das sind genau noch ein paar Takte für die wenigen Befehle die es braucht... das genügt glaub auch für eine Uhr :-)