Moin, ich hab da mal ne Frage zum Timer1 des ATtiny2313. Also ich habe ein Programm geschrieben, welches den Timer1 so benutzt, dass er rein rechnerisch nach 100ms einen Overflow auslösen müsste. Es wird der interne Quarz als Taktquelle benutzt (1Mhz). Also 1Mhz entspricht 1 µs Daraus folgt 100ms entsprechen 100 000 Zähltakten mit Prescaler 1. Mit Prescaler 256 sind es rund 391 Zähltakte. Da Timer1 aufwärts zählt macht das also einen Startwert von 65145. Merkwürdigerweise machen das meine Tinys (hab 12 Stück) aber nicht. Bei mir dauert es statt 100ms knappe 17s (man beachte den Faktor von 170!) im ersten Durchlauf. Danach funktioniert das Programm wie gewünscht. Woran kann das liegen? Die Programmstruktur ist: Interrupt für Timer1 aktivieren Interrupts generell zulassen Startzeit für Timer 1 laden Timer1 starten Endlosschleife Interrupt Timer 1: Register sichern Timer 1 stoppen Irgendwas machen Startzeit für Timer 1 laden (kann von 100ms Laufzeit abweichen) Timer1 starten Register wieder herstellen Interrupt beenden PS.: Die Zeit von 17s hab ich mit einem Oszi ermittelt.
Der Timer läuft offensichtlich beim ersten Mal die ganzen 64K durch. Programm wäre hilfreich.
Timer 0-1-2 Berechnungstool Das Tool sollte dir helfen erzeug gleich den passenden code in bascom. Ich hoffe du kannst was damit anfangen. http://bascom-forum.de/index.php/topic,114.msg343.html#msg343
Hast du die CLKDIV Fuse deaktiviert? Sosnt läuft der Tiny nämlich nicht mit 1 Mhz sondern mit 1/8 Mhz... Oder lädst du beim erstenmal nicht die Zeit richtig?
So was macht man beim AVR nicht mit Preload. Dafür gibts bei den meisten Timern (und auch beim Timer1 vom Tiny2313) die CTC-Betriebsart, die über die Compare-Einheit arbeitet.
CTC geht nur mit Timer1 und 2 timer0 hat kein compare mode. und wie man den Timer verwendet ist geschmackssache. CTC nehme ich nur wenn ich eine IF-Diode mit 36 KHz Timen möchte .
@Andreas Kaiser: Offensichtlich hast du recht, aber wieso? @TIMER_MAN: Bascom benutze ich nicht, ausserdem scheinen die Berechnungen ja zu stimmen (zumindest im zweiten Durchlauf, siehe Programmcode). @Läubi: Nein die Fuse ist nicht gesetzt, also CLKDIV = 1, damit läuft der Tiny mit 1MHz, sonst mit 8MHz, siehe Manual auf Seite 25: Default Clock Source; Ebenfalls mit Oszi überprüft. @Johannes M.: Könntest du das näher erläutern? Was wäre denn der Unterschied ob ich von 0 bis x zähle oder von x bis 65535 und den Overflow nutze? Ausserdem ist das nicht ganz ohne, wie die Erläuterung auf Seite 99 des Handbuchs zeigt (das Beispiel, wenn man den oberen Wert nahe dem unteren wählt, was ja dann hier der Fall wäre). Programmcode, nur relevante Teile: 65145 in Hex: $FE79
1 | Start: |
2 | |
3 | ; Interrupt aktivieren |
4 | LDI r16,(1<<TOIE1) |
5 | OUT TIMSK,r16 |
6 | |
7 | ; Timer1 Zeit laden |
8 | LDI r16,$79 |
9 | OUT TCNT1L,r16 |
10 | |
11 | LDI r16,$FE |
12 | OUT TCNT1H,r16 |
13 | |
14 | ; Timer1 starten |
15 | LDI r16,$04 |
16 | OUT TCCR1B,r16 |
17 | |
18 | Final: |
19 | |
20 | RJMP Final |
21 | |
22 | Timer1Overflow: |
23 | |
24 | ... ; Register retten |
25 | |
26 | ; Timer1 stoppen |
27 | LDI r16,$00 |
28 | OUT TCRR1B,r16 |
29 | |
30 | ; Timer1 Zeit laden |
31 | LDI r16,$04 |
32 | OUT TCNT1L,r16 |
33 | |
34 | LDI r16,$A7 |
35 | OUT TCNT1H,r16 |
36 | |
37 | ; Timer1 starten |
38 | LDI r16,$04 |
39 | OUT TCCR1B,r16 |
40 | |
41 | ... ; Register wiederherstellen und Interrupt beenden |
Hier passt der CTC Mode besser, weil nur der ein präzises Intervall garantiert (z.B. WGM1x=1100 in TCCR1A/B). Dein Problem allerdings hängt mit der Reihenfolge zusammen, in der du den Timer schreibst. Du schreibst nämlich nicht wirklich ins "high" Register, sondern tatsächlich in ein Temp-Register, das zusammen mit dem darauf folgenden Schreibzugriff aufs "low" Register dann im Timer landet. Und das passiert erst beim ersten Interrupt Steht übrigens in der Doku.
Erm... bei mir steht: >> The device is shipped with CKSEL = “0010”, SUT = “10”, >> and CKDIV8 programmed. und in der Tabelle für ClockSources steht: >> Device Clocking Option CKSEL3..0 >> External Clock 0000 - 0001 >> Calibrated Internal RC Oscillator 4MHz 0010 - 0011 >> Calibrated internal RC Oscillator 8MHz 0100 - 0101 >> Watchdog Oscillator 128kHz 0110 - 0111 >> External Crystal/Ceramic Resonator 1000 - 1111 Ergo: Auslieferungszustand = 4Mhz/8 = 500kHz Oder überseh ich jezt was? Ansosnten hat >>Andreas Kaiser<< recht: Reihenfolge beim Lesen/Beschreiben von 16bit Registern beachten!
Benjamin K. wrote: > @Johannes M.: > Könntest du das näher erläutern? Was wäre denn der Unterschied ob ich > von 0 bis x zähle oder von x bis 65535 und den Overflow nutze? Ausserdem > ist das nicht ganz ohne, wie die Erläuterung auf Seite 99 des Handbuchs > zeigt (das Beispiel, wenn man den oberen Wert nahe dem unteren wählt, > was ja dann hier der Fall wäre). Bei einem Preload musst Du im Interrupt Handler jeweils den Startwert wieder ins Zählregister schreiben (und dabei die Hinweise in Bezug auf 16-Bit-Register beachten). Das kann insbesondere bei kurzen Zeiten zu Ungenauigkeiten führen, weil der Timer verzögert "nachgeladen" wird. Schließlich braucht es einige Taktzyklen vom Auftreten des Interrupts (Flag wird gesetzt) bis zum Beginn des eigentlichen Interrupt Handlers. In Assembler kann man das zwar sehr präzise kontrollieren und kompensieren (indem man den Nachladewert entsprechend anpasst), aber es ist unnötiger Programmieraufwand. Im CTC-Modus schreibst Du einmal den Wert ins Compare-Register und brauchst Dich danach nicht mehr drum zu kümmern, solange der Wert konstant bleibt. Und wenn man erforderliche Änderungen am Compare-Wert synchronisiert (also im entsprechenden Interrupt-Handler) durchführt, kommt es i.d.R. auch nicht zu den von Dir angedachten Problemen.
Eines ist mir in deinem Programm noch aufgefallen: muss bei den 16bit Timerregistern nicht der Timer H-Wert zuerst gladen werden? Warum und wieso steht in der Beschreibung der Timer.
Um beide Compares und den Capture nutzen zu können, verzichte ich meist auf den CTC-Mode und lasse Timer1 frei durchlaufen. Im Compare lese ich OCR aus, addiere das Intervall dazu und schreibe ins OCR zurück. Das ist zwar etwas mehr Programmieraufwand als CTC, ist aber auch jitterfrei, da die Zählerei des Timers dadurch nicht berührt wird. Preload des Timerstandes macht man eigentlich nur noch bei Timern, die kein Compare haben und deren Vorteiler so hoch (langsam) ist, dass sichergestellt ist, dass der Timer beim Laden noch 0 war. MfG, BlauBär
@Läubi: Also wenn ich das nicht falsch verstehe, dann steht da: ... and an initial system clock prescaling of 8, resulting in 1.0 MHz system clock. ... Also ein Teiler von 8 sorgt für 1MHz Takt, was ich ja auch über den CKOUT-Pin mit dem Oszi nachmessen konnte. @Andreas: Das mit der Reihenfolge hats gebracht, danke. Ich habe mein Programm nun so geändert, dass die Timerstartwerte erst in zwei Register geladen werden, also das untere Byte in ein Regster das obere in das andere Register (möchte nachher Werte aus dem Flash laden). Anschließend werden die Werte dann in der richtigen Reihenfolge, wie in der Application Note doc1493.pdf angegeben, in das TCNT1-Register geladen. Der Wert wird in meinem Programm nicht konstant bleiben. Es ist für meine Anwendung auch kein Problem wenn der Timer mal etwas länger oder kürzer läuft, hatte mich nur über die sehr lange Laufzeit im ersten Zyklus gewundert. mfg Benny -> solved
Kleiner Tip noch zum Assembler: ldi r16, low(65145) ldi r17, high(65145) liest und schreibt sich leichter als der Umweg über handgerechnete Hex-Werte.
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.