Forum: Mikrocontroller und Digitale Elektronik Hardware PWM auf ATmega8


von Eric W. (ceikolon)


Lesenswert?

Hallo,
ich bin in dem Gebiet der µCs noch Neueinsteiger und versuche mich zZ an 
einer Hardware PWM. Verwendet wird ein Atmega8 mit 8MHz.
Als Vorlage habe ich diese Seite genommen: 
http://extremeelectronics.co.in/avr-tutorials/pwm-signal-generation-by-using-avr-timers-part-ii/

Ich hab den Code soweit auf mein Atmega8 angepasst
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
void InitPWM()
5
{
6
   /*
7
   TCCR0 - Timer Counter Control Register (TIMER0)
8
   -----------------------------------------------
9
   BITS DESCRIPTION
10
   
11
12
   NO:   NAME   DESCRIPTION
13
   --------------------------
14
   BIT 7 : FOC0   Force Output Compare [Not used in this example]
15
   BIT 6 : WGM00  Wave form generartion mode [SET to 1]
16
   BIT 5 : COM01  Compare Output Mode        [SET to 1]
17
   BIT 4 : COM00  Compare Output Mode        [SET to 0]
18
19
   BIT 3 : WGM01  Wave form generation mode [SET to 1]
20
   BIT 2 : CS02   Clock Select               [SET to 0]
21
   BIT 1 : CS01   Clock Select               [SET to 0]
22
   BIT 0 : CS00   Clock Select               [SET to 1]
23
24
   The above settings are for
25
   --------------------------
26
27
   Timer Clock = CPU Clock (No Prescalling)
28
   Mode        = Fast PWM
29
   PWM Output  = Non Inverted
30
31
   */
32
33
   //Set OC2 PIN as output. It is  PB3 on ATmega16 ATmega32/Atmega8; PortD6 Kontrolle
34
   DDRD  =  0b01000000;
35
   DDRB  =  0b00001000;
36
   //TCCR0|=(1<<WGM00)|(1<<WGM01)|(1<<COM01)|(1<<CS00);
37
  TCCR2=01101001;
38
39
}
40
41
/******************************************************************
42
Sets the duty cycle of output. 
43
44
Arguments
45
---------
46
duty: Between 0 - 255
47
48
0= 0%
49
50
255= 100%
51
52
The Function sets the duty cycle of pwm output generated on OC0 PIN
53
The average voltage on this output pin will be
54
55
         duty
56
 Vout=  ------ x 5v
57
         255 
58
59
This can be used to control the brightness of LED or Speed of Motor.
60
*********************************************************************/
61
62
void SetPWMOutput(uint8_t duty)
63
{
64
   OCR2=duty;
65
}
66
67
/******************************************************************** 
68
69
Simple Wait Loop
70
71
*********************************************************************/
72
73
void Wait()
74
{
75
 _delay_loop_2(62000);
76
}
77
78
void main()
79
{
80
   uint8_t brightness=0;
81
82
   //Initialize PWM Channel 0
83
   InitPWM();
84
85
   //Do this forever
86
87
   while(1)
88
   {
89
      //Now Loop with increasing brightness
90
91
      for(brightness=0;brightness<255;brightness++)
92
      {
93
         //Now Set The Brighness using PWM
94
95
         SetPWMOutput(brightness);
96
     
97
     //Kontrolllampe
98
    PORTD^=0b01000000;
99
         //Now Wait For Some Time
100
         Wait();
101
      }
102
103
      //Now Loop with decreasing brightness
104
105
      for(brightness=255;brightness>0;brightness--)
106
      {
107
         //Now Set The Brighness using PWM
108
109
         SetPWMOutput(brightness);
110
111
         //Now Wait For Some Time
112
         Wait();
113
      }
114
   }
115
}

Leider kann ich am PortB3 kein oszillieren messen. Vielleicht könnt ihr 
ja einen Fehler finden...
Achja am PortD6 hängt ne LED, die mir bestätigt das beide For 
Anweisungen durchlaufen werden...

Bin für jede Antwort Dankbar!

von Karl H. (kbuchegg)


Lesenswert?

Eric Weiß schrieb:

> Leider kann ich am PortB3 kein oszillieren messen. Vielleicht könnt ihr
> ja einen Fehler finden...

Dein Hauptfehler besteht darin, dass du auf bescheuerter Syntax 
bestehst.

Das hier
1
  TCCR2=01101001;

tut nicht das, was du denkst das es tun sollte.
01101001
ist keine Binärzahl sondern eine Oktalzahl.

Und darf man erfahren, warum du diese Schreibweise, der einfach zu 
lesenderen, einfacher zu analysierenden und zumindest in dieser Hinsicht 
WESENTLICH weniger fehleranfälligen Schreibweise
1
   TCCR2 |= (1<<WGM20) | (1<<WGM21) |    // Fast PWM
2
            (1<<COM21) |                 // Clear when Up, Set when down
3
            (1<<CS20);                   // Prescaler 1
vorziehst?
Da sieht man auf einen Blick, welche Bits gesetzt werden und kann mit 
den Bitnamen im Datenblatt vergleichen. Schreibst du das binär, muss man 
erst mal die Bits auseinander dröseln, ehe man feststellen kann, was du 
da überhaupt alles einschaltest.
Benutze die Bitnamen aus dem Datenblatt! Dazu wurden die Header Files 
entsprechend gepimpt, damit du das machen kannst!


Hier
   DDRB  =  0b00001000;
ist es zwar prinzipiell richtig, aber von der Schreibweise genau das 
gleiche:
Wenn du Bit 3 (PB3) auf 1 setzen willst, dann schreib das auch so:
   DDRB |= ( 1 << PB3 );

Jetzt kann der Blindenhund eines Blinden auf 15 Meter Entfernung 
erkennen, dass das Bit für PB3 auf 1 gesetzt wird. Kein Mensch muss dazu 
irgendwelche Bits zählen (und sich 3 mal verzählen) oder irgendwelche 
Prefixe für Binärzahlen benutzen (und manchmal darauf vergessen).

von Eric W. (ceikolon)


Lesenswert?

Vielen Dank für deine sehr belustigende Antwort ;-).
Grund warum ich es so schreibe steht vermutlich gleich in der ersten 
Zeile meines Beitrages oben.
Ich habe auch erst seit heute deine Schreibweise kennengelernt, werde 
mich aber nun darrauf umstellen (versprochen!).

Die PWM läuft nun auch, Vielen Dank!

von Karl H. (kbuchegg)


Lesenswert?

Eric Weiß schrieb:

> Ich habe auch erst seit heute deine Schreibweise kennengelernt,

Tja.
Zitat
1
   DDRB  =  0b00001000;
2
   //TCCR0|=(1<<WGM00)|(1<<WGM01)|(1<<COM01)|(1<<CS00);
3
  TCCR2=01101001;

Man beachte die auskommentierte Zeile

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.