Wie funktioniert PWM beim ATmega328

OP #5178336
Lesenswert?

Hallo zusammen,

Ich setze mich nun schon seit einiger Zeit mit Mikrocontrollern 
auseinander, bin aber noch ein ziemlicher Noob, wenn es darum geht die 
Prozesse zu verstehen, welche im Hintergrund ablaufen. Eins stößt mir 
besonders vor den Kopf, Stichwort:PWM. Meines wissens besitz der Arduino 
keinen D/A-Wandler, sondern regelt dies über PWM. Nur gibt es bei der 
Sache einen kleinen Haken. Um das Signal aufrecht zu erhalten, muss doch 
der Controller ständig Regeln. Wenn ich aber in der Zwischenzeit etwas 
anderes mache, z.B. delay() hat er doch keine Zeit mehr das Signal 
aufrecht zu erhalten.
Bsp
1
loop(){
2
   analogWrite(3,255);//volle Leistung
3
   delay(1000);       //Immer noch volle Leistung
4
                      //sollte aber eigentlich von delay() blockiert sein.
5
 
6
   analogWrite(3,125);//halbe Leistung
7

8
}
Wo liegt mein Denkfehler?
#5178359
Lesenswert?

Lothar M. schrieb:
> Die PWM ist in Hardware auf dem AVR vorhanden.

Stefan K. schrieb:
> ie PWM erzeugt ein eigenständiger Timer. Die CPU muss nach dem
> (einmaligen) Festlegen des PWM-Verhältnisses nicht mehr tun

Das dürfte speziell für Arduino auf AVR nicht stimmen, weil er mehr 
analoge Ausgänge bietet als er Hardware PWM-Kanäle hat. Es wird also 
eine Soft-PWM sein, wo der Timer nur noch als Interrupt-Quelle genutzt 
wird und die ISR die digitalen(!) Ausgänge passend zu den zugewiesenen 
Analogwerten ein- bzw. ausschaltet.

Aber natürlich funktioniert das auch dann noch, wenn man eine 
Verzögerungsschleife auf die harte Tour mit busy waiting macht.
Gast #5178367
Lesenswert?

Axel S. schrieb:
> Es wird also
> eine Soft-PWM sein, wo der Timer nur noch als Interrupt-Quelle genutzt
> wird und die ISR die digitalen(!) Ausgänge passend zu den zugewiesenen
> Analogwerten ein- bzw. ausschaltet.

Ja, das kann man hier auch "erahnen"

https://www.arduino.cc/en/Reference/AnalogWrite

...
The PWM outputs generated on pins 5 and 6 will have higher-than-expected 
duty cycles. This is because of interactions with the millis() and 
delay() functions, which share the same internal timer used to generate 
those PWM outputs. This will be noticed mostly on low duty-cycle 
settings (e.g 0 - 10) and may result in a value of 0 not fully turning 
off the output on pins 5 and 6.
...
Gast #5178429
Lesenswert?

momo schrieb:
> Axel S. schrieb:
>> Das dürfte ...
>> Es wird also ...
>
> Auch was definitives?

Ja!

Der AVR Arduino Core nutzt Hardware PWM.
Für den Uno (ATMega328P) gilt: 3 Timer 6 PWM Kanäle.

Natürlich gibt es auch Software PWM Libs.
Aber die haben nichts mit dem analogWrite() des Arduino Core zu tun.
#5178431
Lesenswert?

momo schrieb:
> Axel S. schrieb:
>> Das dürfte ...
>> Es wird also ...
>
> Auch was definitives?

Wer es genau wissen will, soll halt die Quellen der Arduino-Lib lesen. 
Da ich diese Lib nicht verwende, werde ich es sicher nicht tun. 
Andererseits sind es definitiv mehr "analoge" Ausgänge als PWM-Kanäle. 
Es kann also nur Soft-PWM sein.

Für die Frage des TE ist das ein unerhebliches Detail. Sowohl Hardware- 
als auch Software-PWM funktionieren im Hintergrund.
Gast #5178437
Lesenswert?

#5178731
Lesenswert?

Lothar M. schrieb:
> Marinus O. schrieb:
>> sollte aber eigentlich von delay() blockiert sein.
> Warum sollte das delay() irgendwas blockieren?

Natürlich blockiert delay() "irgendwas", nämlich die CPU.

Die ist zwar nicht für die Erzeugung des PWM-Signals zuständig, das 
macht die jeweilige Peripherie.
Trotzdem ist deine polemische Scheinfrage mehr als unangebracht.
Gast #5178738
Lesenswert?

Ich zittiere mal aus der Datei wiring_analog.c für AVR Mikrocontroller:
1
// Right now, PWM output only works on the pins with
2
// hardware support.  These are defined in the appropriate
3
// pins_*.c file.  For the rest of the pins, we default
4
// to digital output.
5
void analogWrite(uint8_t pin, int val)
6
{
7
  // We need to make sure the PWM output is enabled for those pins
8
  // that support it, as we turn it off when digitally reading or
9
  // writing with them.  Also, make sure the pin is in output mode
10
  // for consistenty with Wiring, which doesn't require a pinMode
11
  // call for the analog output pins.
12
  pinMode(pin, OUTPUT);
13
  if (val == 0)
14
  {
15
    digitalWrite(pin, LOW);
16
  }
17
  else if (val == 255)
18
  {
19
    digitalWrite(pin, HIGH);
20
  }
21
  else
22
  {
23
    switch(digitalPinToTimer(pin))
24
    {
25
      // XXX fix needed for atmega8
26
      #if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
27
      case TIMER0A:
28
        // connect pwm to pin on timer 0
29
        sbi(TCCR0, COM00);
30
        OCR0 = val; // set pwm duty
31
        break;
32
      #endif
33

34
      #if defined(TCCR0A) && defined(COM0A1)
35
      case TIMER0A:
36
        // connect pwm to pin on timer 0, channel A
37
        sbi(TCCR0A, COM0A1);
38
        OCR0A = val; // set pwm duty
39
        break;
40
      #endif
41

42
      #if defined(TCCR0A) && defined(COM0B1)
43
      case TIMER0B:
44
        // connect pwm to pin on timer 0, channel B
45
        sbi(TCCR0A, COM0B1);
46
        OCR0B = val; // set pwm duty
47
        break;
48
      #endif
49

50
      #if defined(TCCR1A) && defined(COM1A1)
51
      case TIMER1A:
52
        // connect pwm to pin on timer 1, channel A
53
        sbi(TCCR1A, COM1A1);
54
        OCR1A = val; // set pwm duty
55
        break;
56
      #endif
57

58
      #if defined(TCCR1A) && defined(COM1B1)
59
      case TIMER1B:
60
        // connect pwm to pin on timer 1, channel B
61
        sbi(TCCR1A, COM1B1);
62
        OCR1B = val; // set pwm duty
63
        break;
64
      #endif
65

66
      #if defined(TCCR1A) && defined(COM1C1)
67
      case TIMER1C:
68
        // connect pwm to pin on timer 1, channel B
69
        sbi(TCCR1A, COM1C1);
70
        OCR1C = val; // set pwm duty
71
        break;
72
      #endif
73

74
      #if defined(TCCR2) && defined(COM21)
75
      case TIMER2:
76
        // connect pwm to pin on timer 2
77
        sbi(TCCR2, COM21);
78
        OCR2 = val; // set pwm duty
79
        break;
80
      #endif
81

82
      #if defined(TCCR2A) && defined(COM2A1)
83
      case TIMER2A:
84
        // connect pwm to pin on timer 2, channel A
85
        sbi(TCCR2A, COM2A1);
86
        OCR2A = val; // set pwm duty
87
        break;
88
      #endif
89

90
      #if defined(TCCR2A) && defined(COM2B1)
91
      case TIMER2B:
92
        // connect pwm to pin on timer 2, channel B
93
        sbi(TCCR2A, COM2B1);
94
        OCR2B = val; // set pwm duty
95
        break;
96
      #endif
97

98
      #if defined(TCCR3A) && defined(COM3A1)
99
      case TIMER3A:
100
        // connect pwm to pin on timer 3, channel A
101
        sbi(TCCR3A, COM3A1);
102
        OCR3A = val; // set pwm duty
103
        break;
104
      #endif
105

106
      #if defined(TCCR3A) && defined(COM3B1)
107
      case TIMER3B:
108
        // connect pwm to pin on timer 3, channel B
109
        sbi(TCCR3A, COM3B1);
110
        OCR3B = val; // set pwm duty
111
        break;
112
      #endif
113

114
      #if defined(TCCR3A) && defined(COM3C1)
115
      case TIMER3C:
116
        // connect pwm to pin on timer 3, channel C
117
        sbi(TCCR3A, COM3C1);
118
        OCR3C = val; // set pwm duty
119
        break;
120
      #endif
121

122
      #if defined(TCCR4A)
123
      case TIMER4A:
124
        //connect pwm to pin on timer 4, channel A
125
        sbi(TCCR4A, COM4A1);
126
        #if defined(COM4A0)    // only used on 32U4
127
        cbi(TCCR4A, COM4A0);
128
        #endif
129
        OCR4A = val;  // set pwm duty
130
        break;
131
      #endif
132
      
133
      #if defined(TCCR4A) && defined(COM4B1)
134
      case TIMER4B:
135
        // connect pwm to pin on timer 4, channel B
136
        sbi(TCCR4A, COM4B1);
137
        OCR4B = val; // set pwm duty
138
        break;
139
      #endif
140

141
      #if defined(TCCR4A) && defined(COM4C1)
142
      case TIMER4C:
143
        // connect pwm to pin on timer 4, channel C
144
        sbi(TCCR4A, COM4C1);
145
        OCR4C = val; // set pwm duty
146
        break;
147
      #endif
148
        
149
      #if defined(TCCR4C) && defined(COM4D1)
150
      case TIMER4D:        
151
        // connect pwm to pin on timer 4, channel D
152
        sbi(TCCR4C, COM4D1);
153
        #if defined(COM4D0)    // only used on 32U4
154
        cbi(TCCR4C, COM4D0);
155
        #endif
156
        OCR4D = val;  // set pwm duty
157
        break;
158
      #endif
159

160
              
161
      #if defined(TCCR5A) && defined(COM5A1)
162
      case TIMER5A:
163
        // connect pwm to pin on timer 5, channel A
164
        sbi(TCCR5A, COM5A1);
165
        OCR5A = val; // set pwm duty
166
        break;
167
      #endif
168

169
      #if defined(TCCR5A) && defined(COM5B1)
170
      case TIMER5B:
171
        // connect pwm to pin on timer 5, channel B
172
        sbi(TCCR5A, COM5B1);
173
        OCR5B = val; // set pwm duty
174
        break;
175
      #endif
176

177
      #if defined(TCCR5A) && defined(COM5C1)
178
      case TIMER5C:
179
        // connect pwm to pin on timer 5, channel C
180
        sbi(TCCR5A, COM5C1);
181
        OCR5C = val; // set pwm duty
182
        break;
183
      #endif
184

185
      case NOT_ON_TIMER:
186
      default:
187
        if (val < 128) {
188
          digitalWrite(pin, LOW);
189
        } else {
190
          digitalWrite(pin, HIGH);
191
        }
192
    }
193
  }
194
}


Das ist eindeutig kein Soft-PWM. Es zeigt auch eindeutig, dass die 
Anzahl der verfügbaren PWM Ausgänge vom konkreten Chip abhängt. Pervers 
finde ich, dass die Library einfach auf digitale LOW/HIGH Ausgabe 
wechselt, wenn man einen Ausgang analog zu verwenden versucht, bei dem 
das nicht geht.
#5178864
Lesenswert?

Arduino F. schrieb:
> Axel S. schrieb:
>> Andererseits sind es definitiv mehr "analoge" Ausgänge als PWM-Kanäle.
>> Es kann also nur Soft-PWM sein.
> Nein!

Aha. So kann man sich irren. Ich hatte angenommen, daß Arduino jeden Pin 
für analogwrite() erlaubt. Wie gesagt, ich nutze diese API nicht (ist 
mir zu fett, zu langsam und allgemein zu wenig nützlich). Da hatte ich 
denen einfach zu viel zugetraut.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren