Forum: Mikrocontroller und Digitale Elektronik Atmega324PB: PWM auf OC4B (PB7) statt an OC4A) ausgeben


von Jakob (Gast)


Lesenswert?

Versuche mich gerade an einer PWM Led Steuerung auf einem Atmega 324PB.

Hier habe ich eine LED an PB7 (OC4B)


Wie schaffe ich es, dass ich mir die PWM auf diesen PIN (OC4B und nicht 
OC4A) gebe.

Folgenden Code verwende ich:
1
DDRB |= (1<<PB7) //Ausgang aktivieren
2
3
 // PWM für blaue LED
4
   
5
TCCR4A |= (1<<COM4A1); // clear OC4A on compare match
6
TCCR4A |= (1<<WGM43)|(1<<WGM42) |(1<<WGM41) |(1<<WGM40); // Fast PWM (m. 15)
7
8
TCCR4B |= (1<<CS40); // Kein Vorteiler
9
   
10
11
OCR4A = 128; // Duty Cycle = 50%

von Stefan F. (Gast)


Lesenswert?

> TCCR4A |= (1<<COM4A1); // clear OC4A on compare match

Ersetze COM4A1 durch COM4B1

von Jakob (Gast)


Lesenswert?

Danke Stefan,

aber irgendwie bin ich zu blöd dafür. Für die beiden anderen LEDs hat es 
geklappt. Aber die blaue LED an PB7 (OC4B) will nicht. Hängt es 
vielleicht damit zusammen, das beim Atmega324PB auch OC3B auf auf PB7 
ist und sich das was gegenseitig blockiert. Bitte um Hilfe weil ich 
einfach nicht weiterkomme.
1
// PWM für rote LED an PB6 (OC3A)
2
  
3
   TCCR3A |= (1<<COM3A1); // clear OC3A on compare match
4
   TCCR3A |= (1<<WGM33)|(1<<WGM32) |(1<<WGM31) |(1<<WGM30); // Fast PWM (mode 15), zählen bis OCR3A
5
6
   TCCR3B |= (1<<CS30); // Kein Vorteiler
7
8
   OCR3A = 30000;
9
   
10
   
11
   // PWM für grüne LED an PD5 (OC1A)
12
   
13
   TCCR1A |= (1<<COM1A1); // clear OC1A on compare match
14
   TCCR1A |= (1<<WGM13) | (1<<WGM12) | (1<<WGM11) | (1<<WGM10); // Fast PWM (mode 15), zählen bis OCR1A
15
16
   TCCR1B |= (1<<CS10); // Kein Vorteiler
17
   
18
   OCR1A = 30000;
19
   
20
   
21
   
22
   // PWM für blaue LED an PB7 (OC4B)
23
   
24
   TCCR4A |= (1<<COM4B1); // clear OC4B on compare match
25
   TCCR4A |= (1<<WGM43)|(1<<WGM42) |(1<<WGM41) |(1<<WGM40); // Fast PWM (mode 15), zählen bis OCR4A
26
27
   TCCR4B |= (1<<CS40); // Kein Vorteiler
28
   
29
   OCR4A = 30000;

von S. Landolt (Gast)


Lesenswert?

Welcher Wert wird OCR4B zugewiesen?

von H.Joachim S. (crazyhorse)


Lesenswert?

Jakob schrieb:

> TCCR4A |= (1<<WGM43)|(1<<WGM42) |(1<<WGM41) |(1<<WGM40); // Fast PWM
WGM42 und 43 liegen in TCCR4B

von Alexander S. (alex998)


Lesenswert?

H.Joachim S. schrieb:
> Jakob schrieb:
>
>> TCCR4A |= (1<<WGM43)|(1<<WGM42) |(1<<WGM41) |(1<<WGM40); // Fast PWM
> WGM42 und 43 liegen in TCCR4B

Analog dazu auch WGM12/13 und WGM32/33.

von Jakob (Gast)


Lesenswert?

Habs jetzt korrigiert und überall WGM angepasst. Danke für den Hinweis. 
Ferner habe ich OCR4B statt OCR4A einen Wert gegeben:
1
DDRB |= (1<<PB7);
2
3
   TCCR4A |= (1<<COM4B1); // clear OC4B on compare match
4
   TCCR4A |= (1<<WGM41) | (1<<WGM40); // Fast PWM (mode 15), Zählen bis OCR4A
5
6
   TCCR4B |= (1<<WGM43) | (1<<WGM42) | (1<<CS40); // Kein Vorteiler
7
   
8
   OCR4B = 30000;

Allerdigs leuchtet damit immer noch nichts durch PWM.



Wenn ich PORTB |= (1<<PB7) setze, leuchtet die LED wunderbar.

von Stefan F. (Gast)


Lesenswert?

Jakob schrieb:
> TCCR4A |= (1<<COM4B1); // clear OC4B on compare match

Der Kommentar gilt für für nicht-PWM Modus. Im PWM Modus ist es "Clear 
OC4B on Compare Match, set OC4B at BOTTOM (non-inverting mode)"

Ein falscher Kommentar kann schädlicher sein, als kein Kommentar.

> ... // Fast PWM (mode 15), Zählen bis OCR4A
> OCR4B = 30000;

Dann musst du auch OCR4A auf einen Wert > 30000 ein stellen, sonst zählt 
er nur von 0 bis 0.

von Jakob (Gast)


Lesenswert?

Im Datenblatt steht in der Tabelle zur FastPWM (Mode 15, Seite 169), das 
dann TOP = OCR4A sei. Daher dachte ich, OCR4A statt OCR4B vorgeben zu 
müssen. Nun ja, ändert ja eh nicht daran das keine PWM erzeugt wird.

von Stefan F. (Gast)


Lesenswert?

OCR4A gibt den TOP-Wert des Zählers vor, also die gesamte Dauer einer 
Periode.
OCR4B stellt die Pulsbreite des PWM Signals ein.

OCR4B muss < OCR4A sein, damit du Impulse bekommst.

von Jakob (Gast)


Lesenswert?

Ok, dann so, leider auch ohne Erfolg
1
 // PWM für blaue LED an PB7 (OC4B)
2
   TCCR4A |= (1<<COM4B1) | (1<<COM4B0); // Clear OC4A/OC4B on Compare Match, set OC4A/OC4B at BOTTOM (non-inverting mode)
3
   TCCR4A |= (1<<WGM41) | (1<<WGM40);
4
5
   TCCR4B |= (1<<WGM43) | (1<<WGM42) | (1<<CS40); // Kein Vorteiler
6
   
7
   OCR4A = 60000;
8
   OCR4B = 30000;

von H.Joachim S. (crazyhorse)


Lesenswert?

Der 324PB hatte auch ein (oder mehrere) Probleme mit den OC-Ausgängen, 
bin ich auch schon mal drüber gestolpert. Steht hier irgendwo im Forum. 
Microchip fand das nicht buggy genug  um es wenigstens in die errata 
aufzunehmen. Ausser Gelaber vom Inder kam da gar nichts. Keine Ahnung ob 
das jetzt auch dein Problem ist, gut möglich. Ich habe keine Lust das 
wieder rauszusuchen, war frustrierend genug.

von Stefan F. (Gast)


Lesenswert?

Jakob, vielleicht bis du für heute ermüdet.

Jakob schrieb:
> TCCR4A |= (1<<COM4B1) | (1<<COM4B0); // Clear OC4A/OC4B on Compare
> Match, set OC4A/OC4B at BOTTOM (non-inverting mode)

Hier stimmt schon wieder der Kommentar nicht. Dieses mal hast du auf den 
"inverting mode" gewechselt, warum eigentlich?

Wahrscheinlich ist irgendwo noch ein Fehler verborgen den ich gerade 
auch nicht erkenne. Läuft der Zähler überhaupt?

Kann es sein, dass du gleichzeitig eine andere alternative Funktion auf 
dem selben Pin aktiviert hast (SCK0, OC3B)?

von Stefan F. (Gast)


Lesenswert?

Da gibt es einen interessanten Satz im Datenblatt "For OC3B or OC4B when 
not using the Output Compare Modulator, PORTD2 must also be set in 
order to enable the output."

Oder du aktivierst halt diesen Modulator, siehe Kapitel 21 im 
Datenblatt.

Hat der Chip noch mehr solche Sonderlocken? Ist ja schlimmer als bei ST!

von Jakob (Gast)


Lesenswert?

Ich geb dann auch mal auf. Was hate denn nun PORTD2 mit OC3B und OC4B zu 
schaffen, die liegen beide mit SCK0 auf PORTB7.

Auf PORTD2 liegt INT0, den ich aber als Eingang brauche.

von Alexander S. (alex998)


Lesenswert?

von 
https://www.avrfreaks.net/forum/need-generate-pwm-waveform-0c3b-atmega328pb

"I also verified that the Output Compare Modulator issue didn't get 
fixed.  It is supposed to be enabled only if OC3B and OC4B are enabled 
but it appears that it is enabled if either OC3B or OC4B are enabled. 
As a consequence of this error, you must write a 1 to bit 2 of PORTD in 
order to get PWM output on PD2 from either Timer3 or Timer4.  I suspect 
that the same workaround would need to be used any time you want OC3B or 
OC4B output on PD2.  If you're actually using the Output Compare 
Modulator you'd write a 0 or a 1 to bit 2 of PORTD depending on whether 
you want AND or OR modulation."

Mit dem PORTD2 wird ein Druckfehler sein (auf dem 328 liegt OC3B/OC4B 
auf PORTD2), schreib mal eine 1 an PORTB7:

PORTB |= (1<<PB7);

siehe auch: 
https://github.com/watterott/ATmega328PB-Testing/issues/29#issuecomment-364785135

: Bearbeitet durch User
von Jakob (Gast)


Lesenswert?

Alexander S. schrieb:
> PORTB |= (1<<PB7);

Danke euch, das hat das Rätsel endlich gelöst. Läuft endlich.
Nochmals Danke, das hat mich jetzt viele Stunden und Nerven gekostet.

von Jakob (Gast)


Lesenswert?

Leider noch nicht so ganz. PWM an OC4B fuktioniert nun super,
nur leider die grüne und rote LED nicht mehr.

Kann langsam auch kaum noch erkennen was ich da eigentlich tippe. Aber 
vielleicht könnte nochmal jemand raufschauen was ich da jetzt versaut 
habe.
1
/////////////////PWM LEDs/////////////////
2
  
3
   PORTB |= (1<<7);
4
   
5
  // PWM für rote LED an PB6 (OC3A)
6
7
  TCCR3A |= (1<<COM3A1);
8
  TCCR3A |= (1<<WGM31) | (1<<WGM30);
9
10
  TCCR3B |= (1<<WGM33) | (1<<WGM32) | (1<<CS30);
11
12
  OCR3A = 1000;
13
  OCR3B = 0;
14
15
  
16
   
17
   
18
   
19
   // PWM für grüne LED an PD5 (OC1A)
20
   
21
   TCCR1A |= (1<<COM1A1); 
22
   TCCR1A |= (1<<WGM11) | (1<<WGM10); 
23
24
   TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS10);
25
   
26
   OCR1A = 1000;
27
   OCR1B = 0;
28
   
29
  
30
   
31
   
32
   // PWM für blaue LED an PB7 (OC4B)
33
   TCCR4A |= (1<<COM4B1); 
34
   TCCR4A |= (1<<WGM41) | (1<<WGM40);
35
36
   TCCR4B |= (1<<WGM43) | (1<<WGM42) | (1<<CS40); 
37
   
38
   OCR4A = 1000;
39
   OCR4B = 0;
40
   
41
  
42
/////////////////////////////////////////////

In der while wird testweise folgendes ausgeführt:
1
OCR1B++; //grüne LED
2
OCR3B++; //rote LED;
3
OCR4B++; //blaue LED
4
_delay_ms(10);

... das "Aufdimmen" klappt jetzt leider nur noch bei der blauen LED.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

zeige bitte das gesamte Programm.

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.