Hi, ich möchte mich etwas besser mit den Timerfunktionen vertraut machen und bin am überlegen welche Vorgehensweise die geringsten Fehler verursachen. Ganz schön kompliziert das Thema. Ich habe einen Takt von 3,6864 MHz und möchte mir eine Sekundenfunktion erzeugen und diese dann auf Minuten und Stunden umrechnen. 1.delay() braucht ja bei 16bit 4 Zyklen um auf 1µs zu kommen. 4Zyklen * (1/3,6864MHz) =~ 1,085... µs ich müsste dann noch einen Faktor von ~0,9216 reinmultiplizieren... delay(50000) würde mir ja theoretisch schon mal 0,05s erzeugen wenn ich delay(50000) dann in eine schleife packe und diese dann 20mal durchlaufen lasse ergibt sich ja rechnerisch 1sec. Frage1: Kann man die "Durchlaufzeit" der Schleife nicht ermitteln? Ähnlich den 4Takten für delay() und mit einem Faktor weiterarbeiten. Soll d(50000) soll ja nicht genau sein, warum verstehe ich noch nicht ganz, vielleicht kann mir jemand Licht ins dunkle bringen. 2.(mein eigentliches Anliegen) Ich benutze jetzt einen 16bit Timer und mit 3,6864 MHz liefert mir AVRcalc auch verschiedene Möglichkeiten, je nachdem welchen prescale faktor ich wähle: bei 5ms z.B.: kein faktor: TCNT1L=0x00; TCNT1H=0xb8; 1/1024: TCNT1L=0xee; TCNT1H=0xff; 2.Frage: Ist meine Annahme richtig, dass ich ohne einen prescale faktor ein genaueres Ergenis bekomme oder habe ich da falsch gedacht? Ich will 10sec: also nehme ich 1/1024 und erhalte die TCNT1H/L Werte. Jetzt könnte ich doch die 10sec in eine Schleife packen die 6mal z.B. durchläuft. Dann könnte ich doch den Fehler hochrechnen und einen Korrekturfaktor für einen Durchgang in einer Schleife berechnen. Beziehungsweise öfter die Schleife durchlaufen lassen 1Tag z.B. um genauere Werte zu erhalten. 3.Frage: Macht man das so, wenn man eine Stopp-Uhr möglichst genau "machen" will? Oder ist der Fehler nicht wahrnehmbar bei 1-5Minuten. Vielleicht hat das ja schon mal jemand gemessen. 4.Frage: Gibt es noch andere Ansätze wie man ein möglichst genaues Zeitintervall bestimmen will - ausser die Signale der Atomuhr zu empfangen.
Zu 1.) Ich mach mir nicht erst die Mühe das nachzurechnen. Eine delay loop für 1 Sekunde ist mittelprächtiger Unfug. Nimm einen Timer, dafür sind die Dinger ja da. Wenn Du dann nix weiter zu tun hast, kannst Du immer noch den Prozessor schlafen legen und Strom sparen. Zu 2.) > 2.Frage: Ist meine Annahme richtig, dass ich ohne einen prescale > faktor ein genaueres Ergenis bekomme oder habe ich da falsch > gedacht? Wie Du zu dieser Annahme kommst, ist mir rätselhaft. Solange Dein prescaler einen ,,runden'' Wert als Ergebnis liefert (so daß Du danach keine Rundungsdifferenzen hast), kannst Du das allemal machen. Die Faktorenzerlegung für 3.6864E6 ergibt 2^14 * 3^2 + 5^2. Du kannst Dir also einen Prescaler von maximal 2^14 (16384) leisten. Da der maximale Prescaler 2^10 ist, bleibt danach als Frequenz 2^4 + 3^2 * 5^2 übrig (3600 Hz). Wenn Du jetzt noch den Timer im CTC-Modus betreibst, brauchst Du also nur noch 3600 ins OCR1A oder OCR1B zu schreiben, dann hast Du einen 1 s Interrupt, der so genau ist, wie Deine Oszillatorfrequenz auch tatsächlich 3,6864 MHz ist. Overflow interrupt würde ich nicht benutzen, wenn Du denn sowieso einen Timer hast, der CTC kann (clear timer on compare match). > Oder ist der Fehler nicht wahrnehmbar bei 1-5Minuten. Der Fehler ist so genau, wie Dein Oszillator. Für 1 - 5 Minuten dürfte er selbst bei einem schlechten Oszillator (Fehler 1E-4) vernachlässigbar sein (30 ms pro 5 Minuten). Für längere Zeiten sollte man wenigstens einen Trimmer am Quarz haben, um ihn auf genaue Frequenz ziehen zu können.
int main(void) { DDRD = 0xF0; /*PIND5 - LED*/ TCCR1A = _BV(COM1A0) | _BV(COM1B0); /*compare1 mode set*/ TCCR1B = _BV(CS10) | _BV(CS12) | _BV(CTC1); /*CTC mit 1/1024*/ OCR1AH = 0x0e; OCR1AL = 0x10; for(;;){} } Ist ja gar nicht so schwierig, die Timer zu benutzen. Eine Frage habe ich aber noch: Wie kann man es umgehen, dass man z.B. alle LEDs an PinD damit zum blinken bringt? Oder einen anderen Port benutzt? Ein Ansatz reicht mir schon
Ich weiß jetzt nicht genau was du mit diesem Code machst, aber normalerweise ist nur ein Pin vom Compare-Match betroffen. OCR1A heißst der glaub ich. Wenn du einen anderen pin nehmen willst, so musst du eine Interruptroutiene schreiben, welche dir dann den benötigten Pin setzt/löscht. Wenn du ein Code-Beispiel benötigst, so sag mir für welchen Controller. Gruß, Florian
Für eine Uhrenanwendung ist es ja gar nicht nötig, 100% genau 1s zu erzeugen, daß kann eh kein Mensch überprüfen. Abgesehen davon wird Dein Quarz auch nie exakt auf 3,6864 MHz schwingen, d.h. Du wirst immer einen Gangfehler bemerken, aber eben erst, wenn die Uhr mehrere Tage läuft. Zur Theorie, wie man eine genaue Uhr hinkriegt, habe ich hier was geschrieben: http://www.specs.de/users/danni/appl/soft/clock/timebase.htm Ist zwar für den 8051, aber das Prinzip läßt sich leicht auf einen AVR übertragen. Man muß bloß etwas Bruchrechnung können. Peter
Das Programm lässt mir die LED blinken. Du meinst mit overflow interrupt? Mit den TCNT1H/L Werten? Nach dem Motto: TCCR1A = 0x00; /*CTC und PWM aus*/ TCCR1B = (_BV(CS12) + _BV(CS10)) /*(1/1024)-faktor*/ TCNT1 = 0xf1f0 /* reset alle 1000ms bei 3,6864 clk*/ Ja, wäre schön wenn du mir source schnipsel für 4433,M8,8515 etc. posten könntes. Freue mich über alles. Problem meines Vorhabens kann ich selber noch nicht ganz abschätzen. Ich versuche daher momentan eigentlich alle Funktionen zu beherrschen. Konkretes Problem ist, dass ich für eine freiwillige Studienarbeit "irgendetwas" entwerfen will. Ich möchte einfach mal eine Art Demonstration mit AVR bauen. Poti an den ADC und Ausgabe über Uart und Display in Volt, Sleepfunktion, Schalter... was man halt so reinbaun kann. Praktisch das aufwendigste Poti, ausserdem denke ich, dass ich nach dem Projekt auch mal was sinnvolles aufbauen kann. Ich kann mit Taster, LEDs, Ports und Uart umgehen. Jetzt habe ich mir die Timer vorgenommen und prinzipiell verstehe ich sie auch. Was würdet ihr mir raten als nächstes zu machen. Was ich derzeit mit UART versuche ist, dass ich über Tasten zähle wie oft in einer Minute gedrückt wurde, mit entprellten Tastern und dann die Werte über Uart ausgebe. Mit dem Timer wollte ich noch eine Art Zeitanzeige realisieren. Vielleicht schreibe ich es gleichmal in den Beitrag, bevor ich wieder einen aufmachen muss. Ich habe eine static int variable, die mir die Tastendrücke hochzählt und eine UART-transmit-Funktion die vom typ unsigned char ist. Brauche ich dafür itoa()? unsigned char sign = 'k'; ... transmit(sign); Ich möchte jetzt einfach mal "12345" vom Typ integer ans Terminal senden. Habe gedacht, ich müsste nur transmit(unsigned int sign) umändern, aber ich bekomme nur Smilies ans Terminal :-) void transmit(unsigned char data){ while(! (USR & (1<<UDRE))) ; UDR = data; } main(){... transmit('\xxx') ...}
unsigned char sign[4] = "Test"; int i; for(i=0, i<=4, i++){ transmit(sign[i]); } funktioniert auch, aber wie wandle ich integer in einen string?
Muss wohl an der Eule liegen... hat sich (wieder mal) erledigt. habe die ganze Zeit nach itos gesucht, habs ja oben schon geschrieben itoa() Eule
> OCR1AH = 0x0e; > OCR1AL = 0x10; Du magst es umständlich, oder? ;-) Warum schreibst Du nicht einfach OCR1A = 3600; ?
Ja, oft etwas umständlich. Habe nicht gewusst, dass dezimal auch möglich ist, deshalb danke für den Hinweis.
Hallo ! Ich will mit dem 90S8535 einen Sekundentakt mit dem Timer1 (16Bit) erzeugen. Hat da jemand ein Code Schnipsel??? Wäre dafür sehr dankbar. Tagelang sitze ich davor uns probiere, aber es klappt nicht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.