Forum: Mikrocontroller und Digitale Elektronik AVR ATmega168 Timer2 PWM Verständniss


von Christian M. (blacky10)


Lesenswert?

Hallo zusammen,
Ich versuche schon länger auf einem ATmega168 beim Timer2 Pin OC2A eine 
Fast PWM zu entlocken, allerdings erfolglos. Beim Timer1 hatte ich keine 
Probleme, doch bei  Timer2 habe ich keinen Erfolg. Kann mir einer helfen 
wo ich auf dem Schlauch stehe?

1
#include <avr/io.h>
2
3
int main(void)
4
{
5
  
6
  /* PB3 as output */
7
  DDRB = (1<<PB3);
8
  
9
  /*Asynchronous status register*/
10
  ASSR = (0<<EXCLK) |    //Enable External clock input
11
      (0<<AS2);    //Enable Asynchronous Timer 2
12
  
13
  /* Timer Counter Control Register A */
14
  TCCR2B = (0<<FOC2A) |  //Force Output compare A
15
       (0<<FOC2B) |  //Force Output compare B
16
       (1<<CS21) |  //Clock select, 32
17
       (1<<CS20);    //Clock select
18
       
19
  /* Timer Counter Control Register B */
20
  TCCR2A = (1<<COM2A1) |  //Connect OC2A
21
       (0<<COM2A0) |  //Connect OC2A
22
       (0<<COM2B1) |  //Connect OC2B
23
       (0<<COM2B0) |  //Connect OC2B
24
       (1<<WGM21) |  //Waveform generation mode, Fast PWM
25
       (1<<WGM20);  //Waveform generation mode
26
  
27
  /* Output Compare Register A*/
28
  OCR2A = 127; //50% cycle
29
  
30
  /* Timer Counter Interupt Mask Register */
31
  TIMSK2 = (0<<OCIE2B) |  //Timer 2 output compare match B interrupt enable
32
      (0<<OCIE2A) |  //Timer 2 output compare match A interrupt enable
33
      (0<<TOIE2);    //Timer 2 overflow interrupt enable
34
35
36
37
    while(1)
38
    {
39
    
40
    }
41
}


Vielen Dank für eure Hilfe :D
Gruss Christian

von Thomas E. (thomase)


Lesenswert?

Christian Müller schrieb:

>   /*Asynchronous status register*/
>   ASSR = (0<<EXCLK) |    //Enable External clock input
>       (0<<AS2);    //Enable Asynchronous Timer 2
Lass das mal ersatzlos weg. Du hast ihm gerade den Clock weggenommen.

mfg.

von holger (Gast)


Lesenswert?

>>   ASSR = (0<<EXCLK) |    //Enable External clock input
>>       (0<<AS2);    //Enable Asynchronous Timer 2
>Lass das mal ersatzlos weg. Du hast ihm gerade den Clock weggenommen.

ASSR mit 0 zu beschreiben dürfte das nicht machen.

Setz mal WGM22 in TCCR2B auf 1.

von Christian M. (blacky10)


Lesenswert?

Hm das hab ich gemacht, hat leider nix gebracht. Allerdings sollte dies 
meiner Meinung nach sowieso keinen Einfluss gehabt haben, da ich die 
interne Clock benütze. Aber danke für die Idee, hast du weitere?

Ahja was ev noch weiterhilft: Ich habe das Programm im Simulator (AVR 
Studio 5) ausprobiert. Dort Toggelt PORTB.3
Ebenfalls hab ich die Hardware über folgenden Befehl überprüft:
1
DDRB = (1<<PB3);
2
PORTB = (1<<PB3);

Der Ausgang geht wie Erwartet auf High. Ein Defekt kann also 
ausgeschlossen werden.

von Christian M. (blacky10)


Lesenswert?

Ok ich hab jetzt auch den Tipp von Holger ausprobiert und den folgenden 
Teil geändert:
1
TCCR2B = (1<<COM2A1) |  //Connect OC2A
2
       (0<<COM2A0) |  //Connect OC2A
3
       (0<<COM2B1) |  //Connect OC2B
4
       (0<<COM2B0) |  //Connect OC2B
5
       (1<<WGM22)  |  
6
       (1<<WGM21) |  //Waveform generation mode, Fast PWM
7
       (1<<WGM20);  //Waveform generation mode

Ich nehme an, dass es sich bei WGM22 um TCCR2B.3 handelt (im Datasheet 
liegt wohl ein Fehler vor, da es das Bit WGM22 TCCR2B nur als Read 
beschreibt).

Jetzt ist der Pin immer HIGH.

: Bearbeitet durch User
von holger (Gast)


Lesenswert?

Wieso hast du die beiden jetzt auch in TCCR2B gesetzt?

       (1<<WGM21) |  //Waveform generation mode, Fast PWM
       (1<<WGM20);  //Waveform generation mode

Die gibt es dort gar nicht.

von Christian M. (blacky10)


Lesenswert?

Hm da ist mir wohl beim Posten was durcheinander gekommen sry, danke für 
den Hinweis. Um Missverständnisse ausschliessen zu können, hier der 
aktuelle Code:
1
#include <avr/io.h>
2
3
int main(void)
4
{
5
  
6
  /* PB3 as output */
7
  DDRB = (1<<PB3);
8
  
9
//   /*Asynchronous status register*/
10
//   ASSR = (0<<EXCLK) |    //Enable External clock input
11
//       (0<<AS2);    //Enable Asynchronous Timer 2
12
//   
13
  /* Timer Counter Control Register A */
14
  TCCR2B = (0<<FOC2A) |  //Force Output compare A
15
       (0<<FOC2B) |  //Force Output compare B
16
       (1<<WGM22)  |  
17
       (1<<CS21) |  //Clock select, 32
18
       (1<<CS20);    //Clock select
19
       
20
  /* Timer Counter Control Register B */
21
  TCCR2A = (1<<COM2A1) |  //Connect OC2A
22
       (0<<COM2A0) |  //Connect OC2A
23
       (0<<COM2B1) |  //Connect OC2B
24
       (0<<COM2B0) |  //Connect OC2B
25
       (1<<WGM21) |  //Waveform generation mode, Fast PWM
26
       (1<<WGM20);  //Waveform generation mode
27
  
28
  /* Output Compare Register A*/
29
  OCR2A = 127; //50% cycle
30
  
31
  /* Timer Counter Interupt Mask Register */
32
  TIMSK2 = (0<<OCIE2B) |  //Timer 2 output compare match B interrupt enable
33
      (0<<OCIE2A) |  //Timer 2 output compare match A interrupt enable
34
      (0<<TOIE2);    //Timer 2 overflow interrupt enable
35
36
37
38
    while(1)
39
    {
40
    
41
    }
42
}

von holger (Gast)


Lesenswert?

>Setz mal WGM22 in TCCR2B auf 1.

Nee, nimm das wieder weg. TOP muss 0xFF sein.
WGM21 und WGM20 auf 1 ist ok.

Dummerweise sehe ich dann aber keinen Fehler mehr in deinem Code.
Müsste gehen.

von Thomas E. (thomase)


Lesenswert?

holger schrieb:
>>>   ASSR = (0<<EXCLK) |    //Enable External clock input
>>>       (0<<AS2);    //Enable Asynchronous Timer 2
>>Lass das mal ersatzlos weg. Du hast ihm gerade den Clock weggenommen.
>
> ASSR mit 0 zu beschreiben dürfte das nicht machen.
>
> Setz mal WGM22 in TCCR2B auf 1.

Ja habe ich auch gerade gesehen. Wieder dieses dämliche 0 schieb 
sonstwohin. Erleichtert die Fehlersuche ungemein.

1
#include <avr/io.h>
2
3
int main(void)
4
{  
5
  DDRB = (1<<PB3);
6
  TCCR2B = (1<<CS21)|(1<<CS20);    //Clock select       
7
  TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20);  //Waveform generation mode
8
  
9
  OCR2A = 127; //50% cycle
10
11
    while(1)
12
    {
13
    
14
    }
15
}

> (1<<WGM22)  |

WGM22 war gesetzt. Damit ist TOP OCR2A und Duty ist OCR2B. Nur mit WGM20 
und 21 ist das Mode3 mit TOP = 0xFF und Duty OCR2A. Mit OCR2B und COM2B1 
kannst du den 2.PWM-Kanal schalten.

mfg.

: Bearbeitet durch User
von Christian M. (blacky10)


Lesenswert?

Boa vielen Dank, es funktioniert :D
Ich Code eigentlich auch nicht mit (0<<x) jedoch, habe ich es zu 
debuggingzecken so geschrieben. Allerdings sehe ich den Unterschied zu 
meinem allerersten Post nicht (ausser dass der Code natürlich bedeutend 
schlanker ist ;D)

Nochmals vielen Dank, hier sind super hilfsbereite Leute.

von holger (Gast)


Lesenswert?

>Boa vielen Dank, es funktioniert :D
>Ich Code eigentlich auch nicht mit (0<<x) jedoch, habe ich es zu
>debuggingzecken so geschrieben. Allerdings sehe ich den Unterschied zu
>meinem allerersten Post nicht (ausser dass der Code natürlich bedeutend
>schlanker ist ;D)

Zeig deinen neuen Code doch mal.

von Christian M. (blacky10)


Lesenswert?

Ich verwende jetzt 1:1 den Code von Thomas:
1
#include <avr/io.h>
2
3
int main(void)
4
{  
5
  DDRB = (1<<PB3);
6
  TCCR2B = (1<<CS21)|(1<<CS20);    //Clock select       
7
  TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20);  //Waveform generation mode
8
  
9
  OCR2A = 127; //50% cycle
10
11
    while(1)
12
    {
13
    
14
    }
15
}

von holger (Gast)


Lesenswert?

>Ich verwende jetzt 1:1 den Code von Thomas:

Ist identisch zu deinem zuerst geposteten Code.
Da sind nur die funktionslosen Nullschieber rausgekürzt.

Dein Code hätte auch so funktionieren müssen.

von Thomas E. (thomase)


Lesenswert?

holger schrieb:
>>Ich verwende jetzt 1:1 den Code von Thomas:
>
> Ist identisch zu deinem zuerst geposteten Code.
> Da sind nur die funktionslosen Nullschieber rausgekürzt.
>
> Dein Code hätte auch so funktionieren müssen.

Ich sehe da auch keinen Unterschied. Dem Compiler ist es auch Wurscht, 
wie das aussieht. Hauptsache er bekommt seine Klammern und Semikolons.

@Christian
Schreib nicht so viele Kommentare. Einmal oben drüber, was der Timer 
machen soll und gut ist. Daß die WGM-Bits für den Modus, die CS-Bits für 
den Prescaler und die COM-Bits für die Ausgänge sind, weiss man, wenn 
man das ein paar Mal gemacht hat, auch so. Und sonst gehört das 
Datenblatt sowieso auf den Tisch oder in 2 Registerkarten in den 
Browser. Eine fürs Pinout, die andere zum Blättern.

mfg.

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.