Forum: Mikrocontroller und Digitale Elektronik AVR Frage zu Timer-Einstellungen bei ATmega


von Marco (Gast)


Lesenswert?

Hallo zusammen,

ich versuche mich gerade am Timer meines ATmega88. Ich möchte ein 
Clock-Signal erzeugen, welches dann auf einen Pin ausgegeben werden 
soll. Die Frequenz sollte so bei 350kHz liegen.

Der Timer an sich läuft, aber irgendwie komme ich mit den erforderlichen 
Einstellungen nicht ganz zu recht, genauer gesagt, ich komme nicht auf 
die gewünschte Frequenz. Ich habe im Moment etwa 125kHz, d.h. eine 
Periodendauer von etwa 8µs, Mit Oszi angesehen.

Der ATmega läuft mit 8MHz.

Den Timer wollte ich im CTC Modus laufen lassen.

Unten ist mein Code dazu.

Wäre klasse, wenn mir da jemand aufzeigen könnte, was isch da falsch 
mache oder wo ich da einen Denkfehler drin habe.

Gruß und schon einmal vielen Dank!

Mein Code sieht bisher mal so aus:
1
void main(void)
2
{
3
    cli();        
4
    port();    
5
    time();    
6
7
    while(1);
8
}
9
            
10
11
12
void time(void)
13
{
14
   TCCR0B |= (1<<CS00);  
15
   TCCR0A = (1<<WGM01);  
16
   OCR0A = 6;
17
   TIMSK0 |= (1<<OCIE0A);  
18
}
19
20
21
ISR (TIMER0_COMPA_vect)
22
{
23
    PORTB ^= ( 1 << PB0 );
24
}

von Karol B. (johnpatcher)


Lesenswert?

Marco schrieb:
> Mein Code sieht bisher mal so aus:

Wirklich? Ich sehe keine Funktion port(), und das Aufrufen von cli(), 
d.h. das Deaktivieren von Interrupts macht auch nicht wirklich Sinn, 
wenn diese zuvor nie eingeschaltet worden sind (sei()).

In welchem Modus möchtest du den Timer denn betreiben? Das reine 
Ausgeben eines PWM-Signals kann mittels Output Compares direkt in 
Hardware geschehen. Oder willst du es in Software lösen?

Übrigens: Da du mit jedem Interrupt das Signal nur toggelst, musst du 
deinen Timer so einstellen, dass er mit der doppelten Frequenz, d.h. 700 
kHz Interrupts auslöst.

Mit freundlichen Grüßen,
Karol Babioch

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

In Software mit Interrupts gibts aber nett Jitter.
Guck dir doch mal die Output Compare Units im datenblatt an und erledige 
das Ganze in reiner Hardware.

von Marco (Gast)


Lesenswert?

Hallo, ich habe beim kopieren einige Kommentare gelöscht, dabei habe ich 
wohl auch Codezeilen gelöscht.

Output Compares werde ich mir mal anschauen.
1
void main(void)
2
{
3
    cli();        
4
    port();    
5
    time();    
6
    sei();
7
    while(1);
8
}
9
            
10
void port(void)  
11
{
12
  DDRB |= (1 << PB)|(1 << OUT2_ON_PIN);                                            
13
  PORTB &= ~(1 << PB0);                  
14
}
15
16
void time(void)
17
{
18
   TCCR0B |= (1<<CS00);  
19
   TCCR0A = (1<<WGM01);  
20
   OCR0A = 6;
21
   TIMSK0 |= (1<<OCIE0A);  
22
}
23
24
25
ISR (TIMER0_COMPA_vect)
26
{
27
    PORTB ^= ( 1 << PB0 );
28
}

: Bearbeitet durch User
von Marco (Gast)


Lesenswert?

Hallo,

vielleicht noch als Hinweis. Werde mir die Output Compare Units wie 
geschrieben einmal anschauen und ausprobieren, aber wenn ich diesen Weg 
schon einmal angefangen habe, wäre es nicht schlecht, auch das ans 
Laufen zu bekommen, auch wenn es nicht der Beste Weg ist.

Vielen Dank!

Grüße

von Karl H. (kbuchegg)


Lesenswert?

Marco schrieb:
> Hallo,
>
> vielleicht noch als Hinweis. Werde mir die Output Compare Units wie
> geschrieben einmal anschauen und ausprobieren, aber wenn ich diesen Weg
> schon einmal angefangen habe, wäre es nicht schlecht, auch das ans
> Laufen zu bekommen, auch wenn es nicht der Beste Weg ist.


Das ist überhaupt kein Weg.
Mit einem Interrupt alle 6 Taktzyklen wird das nichts. Alleine bis der 
AVR die Bearbeitung des Interrupt Vektors aufnimmt vergehen schon einige 
Taktzyklen (wenn mich mein Gedächtnis nicht trügt dann sind das 3, je 
nachdem welcher Befehl durch den Interrupt unterbrochen wird). Den 
unvermeidlichen reti noch dazu. Sichern des Statusregisters und Port 
toggeln und du bist schon über den 6 Taktzklen draussen. Sprich: die 
Interrupts werden schneller generiert, als sie abgearbeitet werden 
können. Mit Assembler könnte man das gerade noch so retten, indem man 
den Porttoggler direkt in die Vektortabelle einschreibt.

Nimm die Hardware. Dafür ist sie gemacht worden.
Hinweis. Auch mit einem Timer im PWM Modus kann man prima Schwingungen 
erzeugen. Dann allerdings wirklich runter bis auf 2 Takzyklen pro 
Schwingung. Also 4Mhz bei 8Mhz Taktfrequenz.

: Bearbeitet durch User
von der alte Hanns (Gast)


Lesenswert?

> Mit Assembler könnte man das gerade noch so retten

Nicht wirklich: bis zu 10 für OCR0A ändert sich gar nichts, man bekommt 
ca. 364 kHz, ab 11 sind es dann 333 kHz, also völlig unbrauchbar. Es 
bleibt folglich nur

> Nimm die Hardware

von Bernhard F. (bernhard_fr)


Lesenswert?

Wie berechnest du eigentlich deinen OCRA-Wert?

Wenn ich das richtig sehe, hast du CTC Mode mit OCRA als TOP-Wert und 
Prescaler=1 / no prescaling.

Damit zählt der Counter alle 0,125 µs einen hoch. Mit dem Wert "6" (also 
zählen von 0...6) wird der Interrupt alle 0,875 µs aufgerufen. 
Entsprechende Frequenz wären c.a 1,14 MHz.


Ich komme auf 8MHz/350kHz = 22,86....

Nur theoretisch angenommen die ISR würde keine Rechenzeit benötigen 
müsstest du diesen Wert halbieren und 1 abziehen um den richtigen Wert 
für OCRA in deiner Lösung zu bekommen...
Das ist bei mir nicht 6.

von Marco (Gast)


Lesenswert?

Hallo,

vielen Dank. Das mit der Abarbeitungszeit des Interrupts ist 
verständlich.

Werde mir dann mal die anderen Möglichkeiten ansehen!


Vielen Dank für de schnelle Hilfe!

Grüße

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
Noch kein Account? Hier anmelden.