Hallo zusammen
Ich betreibe hier einen ATtiny13A mit dem
RC-Oszillator bei 9,6MHz.
Eine ISR soll alle 20µs aufgerufen werden.
Dazu habe ich folgendes Programm geschrieben,
in dem zur Messung ein Ausgang bei jedem Aufruf
gekippt wird.
ERgebnis: Der Aufruf erfolgt alle 23µs.
So ungenau kann der RC_Osz. doch nicht sein.
Ich habe daher ein zweites Programm geschrieben,
bei dem ich die Delay-Funktion benutze. Hier
messe ich 20,08µs. Das finde ich akzeptabel.
Kann mir eine sagen, welcher Fehler in meiner
ersten Programmversion steckt? Ich will natürlich
die Interruprvariante nutzen.
1
//Version 1 mit Interrupt
2
#define F_CPU 9600000UL //CPU-Takt 9,6MHz ohne Teiler durch 8
3
#include<avr/io.h>
4
#include<avr/interrupt.h>
5
6
#define OUT 0 //Taktausgang
7
8
intmain(void)
9
{
10
DDRB=(1<<OUT);//Ausgang festmachen.
11
12
//Zähler 0 mit Compare-Interrupt einrichten
13
//Die ISR wird alle 20µs aufgerufen
14
TCCR0B=(1<<CS00);//ohne Vorteiler.
15
OCR0A=192;//1/9,6MHz * 192 = 20µs
16
TIMSK0=(1<<OCIE0A);//Interrupt bei erreichen von OCR0A
17
sei();//generelle Interruptfreigabe
18
19
while(1)
20
{}//Hier ist noch nichts zu tun
21
}
22
23
ISR(TIM0_COMPA_vect)//Aufruf alle 20µs
24
{
25
TCNT0=0;//Timer zurücksetzten
26
PORTB^=(1<<OUT);
27
}
28
29
//###################################
30
31
//Version 2 mit delay
32
#define F_CPU 9600000UL //CPU-Takt 9,6MHz ohne Teiler durch 8
Reinhard #. schrieb:> TCNT0 = 0; //Timer zurücksetzten
Das ist der Fehler. Das Rücksetzen erfolgt zu spät.
Abhilfe bringt eine andere Betriebsart des Timers oder - schlechte
Lösung - ein TCNT0 = xx, wobei xx die µs für den Aufruf der ISR
kompensiert.
CTC ist das einzig richtige hier. Nebenbei solltest du auch
1
OCR0A=192;//1/9,6MHz * 192 = 20µs
auf 191 korrigieren, denn die Null zählt ja mit. Nebenbei bemerkt, du
brauchst im CTC Mode gar keine ISR, wenns dir nur im Toggeln des Pins
geht, das kann der kleine Kerl in Hardware an OC0A = PB0 mit dem COM0n
Bits.
m.n. schrieb:> OCR0A += NACHLADEWERT; // nächsten Zeitpunkt festlegen
Auch da ist der unbedeutende Rundungsfehler wieder drin, denn aus dem
Nachladewert kommt 192 raus und nicht 191, was richtig wäre. Ausserdem
verstehe ich nicht, warum man sich unbedingt Jittern einfangen will.
1
//Zähler 0 mit CTC einrichten
2
//Zero Effort Toggle PB0 mit 20µs
3
TCCR0A=(1<<COM0A0)|(1<<WGM01);
4
OCR0A=191;//1/9,6MHz * 192 = 20µs
5
TCCR0B=(1<<CS00);//ohne Vorteiler.
Das ganze läuft ohne ISR im Hintergrund. An- und Ausschalten kann man
z.B. mit dem DDRB.
Matthias S. schrieb:> Ausserdem> verstehe ich nicht, warum man sich unbedingt Jittern einfangen will.
Das war die Anforderung:
> Eine ISR soll alle 20µs aufgerufen werden.
m.n. schrieb:> Das war die Anforderung:>> Eine ISR soll alle 20µs aufgerufen werden.
Gut, in der vorhandenen ISR wird aber wieder nur PB0 getoggelt. Aber ist
ja einfach. Fügt man eben noch
1
TIMSK0=(1<<OCIE0A);
2
sei();
hinzu. Dann wird getoggelt und auch noch 'ne ISR aufgerufen. Nur das man
in der ISR sich um keine Timerladerei kümmern muss und der Pin toggelt
auch schon von alleine.
Matthias S. schrieb:> Gut, in der vorhandenen ISR wird aber wieder nur PB0 getoggelt.
Nochmal vollständig zitiert:
> Eine ISR soll alle 20µs aufgerufen werden.> Dazu habe ich folgendes Programm geschrieben,> in dem zur Messung ein Ausgang bei jedem Aufruf> gekippt wird.
PB0 zu toggeln ist nur Mittel zum Zweck und wird vermutlich anschließend
wieder gelöscht.
Mit dem CTC-Modus verbaut man sich die Möglichkeit, Timer0 für weiters
Timing zu nutzen, sowohl mit OCR0B als auch direkt TCNT0 zu verwenden.
Reinhard #. schrieb:> zur Messung ein Ausgang bei jedem Aufruf> gekippt wird
Ein Pin zu toggeln ist doch garnicht Ziel des ganzen, er nutzt ihn nur
zum Debuging. Ziel ist es die ISR alle 20us aufzurufen. WAS er dann
später in der ISR machen will steht ja noch garnicht auf dem Blatt.
Edit: M.N. war schneller ?
Peter II schrieb:> OCR0A += NACHLADEWERT;> ist keine atomare Operation, damit geht auch immer mindestens 1 Takt> verloren.
Da geht nichts verloren und es muß 192 addiert werden. Das OCR0A
Berechnen muß nur vor dem nächten Match erfolgt sein.
Peter D. schrieb:> Da geht nichts verloren und es muß 192 addiert werden. Das OCR0A> Berechnen muß nur vor dem nächten Match erfolgt sein.
ja stimmt, ich dachte TCNT0 wird verwendet.
Rene K. schrieb:> Ein Pin zu toggeln ist doch gar nicht Ziel des ganzen, er nutzt ihn nur> zum Debuging.
Danke Rene. K und M. N. ihr habt es verstanden.
Das war ein guter Gedanke:
Reinhard #. schrieb:> Das war ein guter Gedanke:> #define NACHLADEWERT (F_CPU/50000) // 50 kHz> ISR(TIM0_COMPA_vect) // Aufruf alle 20µs> {> OCR0A += NACHLADEWERT; // nächsten Zeitpunkt festlegen> PORTB ^= (1<<OUT);> }>> Ich bin jetzt im Bereich der RC-Osz.-Genauigkeit.> Man lernt immer noch dazu. Danke!
Und genau dafür gibt es CTC-Mode bei AVRs - wozu die ganze
Rechnerei und manuelles rücksetzen ?
1
TCCR0A=(1<<WGM1);//* CTC-MODE
2
TCCR0B=(1<<CS00);//ohne Vorteiler.
3
OCR0A=191;//1/9,6MHz * 192 = 20µs
4
TIMSK0=(1<<OCIE0A);//Interrupt bei erreichen von OCR0A
Und in der ISR brauchst du dich weder um TCNT0 noch um OCR0A
zu kümmern...
Guten Morgen miteinander,
wie allgemein bekannt aus dem Datenblatt des attiny13a:
*10.2.2 Toggling the Pin*
/Writing a logic one to PINxn toggles the value of PORTxn, independent
on the value of DDRxn. Note that the SBI instruction can be used to
toggle one single bit in a port./
Kann man hier noch ein wenig optimieren.
> ISR(TIM0_COMPA_vect) // Aufruf alle 20µs> {> OCR0A += NACHLADEWERT; // nächsten Zeitpunkt festlegen> PINB.0 = 1;> }
Wenn man die passende Definition von PINB.0 im Code hat.
Marc V. schrieb:> Und genau dafür gibt es CTC-Mode bei AVRs - wozu die ganze> Rechnerei und manuelles rücksetzen ?
Schon wieder Einer ;-)
Im CTC-Modus wird der Timer sehr schlecht genutzt. Es entfällt die
Möglichkeit, einen weiteren periodischen Interrupt über OCR0B
einzustellen, den OVFL-Interrupt zu nutzen oder den Zählerstand selber
für kurze Zeiten auszulesen und zu verwenden.
Mit Rechnerei hat das doch alles nichts zu tun.
Verwendet man z.B. für den Timer einen Vorteiler von 64, lassen sich mit
einem Nachladewert von 3 ebenfalls 20 µs erzeugen. Benötigt man noch
eine ISR im 1 ms Takt, so kann man das über OCR0B mit 150 als
Nachladewert erreichen.
Karl M. schrieb:> *10.2.2 Toggling the Pin*
Der Punkt war doch schon längst abgehakt.
m.n. schrieb:> Schon wieder Einer ;-)>> Im CTC-Modus wird der Timer sehr schlecht genutzt.> Es entfällt die Möglichkeit, einen weiteren periodischen Interrupt> über OCR0B einzustellen,
Wo hat der TO das verlangt, bzw. überhaupt erwähnt ?
> den OVFL-Interrupt zu nutzen
Diese Anforderung habe ich auch nicht gesehen...
> Zählerstand selber für kurze Zeiten auszulesen und zu verwenden.
Das ist natürlich Blödsinn...
m.n. schrieb:> Verwendet man z.B. für den Timer einen Vorteiler von 64, lassen sich mit> einem Nachladewert von 3 ebenfalls 20 µs erzeugen. Benötigt man noch> eine ISR im 1 ms Takt, so kann man das über OCR0B mit 150 als> Nachladewert erreichen.
Man kann sich noch viele (unnötige) Möglichkeiten ausdenken, aber ich
schlage dir mal vor, den ersten Beitrag von TO zu lesen...