Forum: Compiler & IDEs Probleme mit PWM Erzeugung


von Simon H. (himmsi)


Lesenswert?

Hallo zusammen,

ich hab folgendes Problem. Ich möchte am Port D Pin 5 eines Atmega88 ein 
PWM Signal generieren. Allerdings klappt das ganze nicht. Im folgenden 
meine PWM Initialisierung.

Vielen Dank schon mal für Eure Hilfe!!
1
void pwm_generator(void)
2
{
3
  DDRD |= (1<<PD5);
4
  TCCR2A  |=  (1<<WGM21) |  (1<<WGM20);    //Modevorwahl Fast-PWM
5
  TCCR2A  |=  (1<<COM2A1) |  (0<<COM2A0);    //clear on Compare-match
6
7
  TCCR2B  |=  (0<<WGM22);                //Modevorwahl Fast-PWM
8
  TCCR2B  |=  (0<<CS22) |  (1<<CS21) |  (1<<CS20);  //Vorteiler N=23
9
    
10
  TIMSK2  |=  (1<<TOIE2);            //Interrupt bei Overflow enable
11
12
}
13
14
15
ISR (TIMER2_OVF_vect)    //Interrupt Overflow Timer2
16
{
17
  
18
  OCR2A;    //Vergleichsregister neu beschreiben
19
  
20
}

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

OC2A liegt an PB3. Um an PD5 eine PWM zu nutzen musst du den Timer0 
verwenden.

Gruß,
Magnetus

von Simon H. (himmsi)


Lesenswert?

Au ja, stimmt!

Aber da ich an dem Port D pin 3 auch ein PWM Signal benötige habe ich 
jetzt das Programm mal noch folgendermaßen abgeändert. Ist das Programm 
dann so richtig, um am Port B Pin 3 und am Port D Pin 3 ein PWM Signal 
zu bekommen?

Ich hab nämlich bis jetzt keinen wirklichen Erfolg damit gehabt.

Grüße Simon
1
void pwm_generator(void)
2
{
3
  OCR2A=255;
4
  OCR2B=255;
5
  DDRB |= (1<<PB3);
6
  TCCR2A  |=  (1<<WGM21) |  (1<<WGM20);    //Modevorwahl Fast-PWM
7
  TCCR2A  |=  (1<<COM2A1) |  (0<<COM2A0);    //clear on Compare-match
8
9
  TCCR2B  |=  (0<<WGM22);                //Modevorwahl Fast-PWM
10
  TCCR2B  |=  (0<<CS22) |  (1<<CS21) |  (1<<CS20);  //Vorteiler N=23
11
    
12
  TIMSK2  |=  (1<<TOIE2);            //Interrupt bei Overflow enable
13
}
14
15
16
ISR (TIMER2_OVF_vect)    //Interrupt Overflow Timer2
17
{
18
  OCR2A;    //Vergleichsregister neu beschreiben
19
  OCR2B;
20
}

von XXX (Gast)


Lesenswert?

Hallo

Ist das
TCCR2B  |=  (0<<WGM22);
             ^
wirklich das, was du willst?

Such mal nach Bitmanipulation!

Gruß
JJ

von Karl H. (kbuchegg)


Lesenswert?

Simon Hi schrieb:

> Ich hab nämlich bis jetzt keinen wirklichen Erfolg damit gehabt.

Nun ja.
Bei Vergleichswerten von 255 würde ich bei einer PWM die auf einem 8-Bit 
Timer läuft auch nicht wirklich grossartig etwas an den Ausgangspins 
erwarten

von Simon H. (himmsi)


Lesenswert?

Vielen Dank für die zügige Antwort!!

@ Gast: Ja hast recht, um WGM22 zu setzten muss es mit ner 1 verodert 
werden.

@ Karl heinz Buchegger: Ja natürlich, des sind ziemlich kurze Impulse ;)

So müsste es jetzt eigentlich passen, oder? Allerdings funktioniert es 
noch immer nicht so, wie ich eigentlich will :(
1
void pwm_generator(void)
2
{
3
  OCR2A=1;
4
  OCR2B=1;
5
  DDRB |= (1<<PB3);
6
  DDRD |= (1<<PD3);
7
  TCCR2A  |=  (1<<WGM21) |  (1<<WGM20);    //Modevorwahl Fast-PWM
8
  TCCR2A  |=  (1<<COM2A1) |  (0<<COM2A0);    //clear on Compare-match
9
10
  TCCR2B  |=  (1<<WGM22);                //Modevorwahl Fast-PWM
11
  TCCR2B  |=  (0<<CS22) |  (1<<CS21) |  (1<<CS20);  //Vorteiler N=32
12
    
13
  TIMSK2  |=  (1<<TOIE2);            //Interrupt bei Overflow enable
14
}
15
16
17
ISR (TIMER2_OVF_vect)    //Interrupt Overflow Timer2
18
{
19
  OCR2A;    //Vergleichsregister neu beschreiben
20
  OCR2B;
21
}

von Karl H. (kbuchegg)


Lesenswert?

Simon Hi schrieb:

> So müsste es jetzt eigentlich passen, oder? Allerdings funktioniert es
> noch immer nicht so, wie ich eigentlich will :(

Und was willst du?


> ISR (TIMER2_OVF_vect)    //Interrupt Overflow Timer2
> {
>   OCR2A;    //Vergleichsregister neu beschreiben
>   OCR2B;
> }

Interessanter Code.
Nur bewirkt er nichts.

von Simon H. (himmsi)


Lesenswert?

Ich möchte eigentlich ne Motorsteuerung für zwei Gleichstrommotoren zum 
laufen bekommen. Die Vorwahl der Drehrichtung und die anderen 
Programmteile sind bereits fertig und funtionieren, wenn ich den Port, 
auf dem ich das PWM Signal ausgeben möchte, manuell auf "High" setze.

Nun versuche ich bereits seit mehreren Tagen die PWM zum Laufen zu 
bekommen. Da dies mein erstes Projekt mit PWM ist und ich erst wenig 
Erfahrung mit Mikrocontrollern habe, habe ich noch leichte Probleme mit 
dem Lesen und verstehen des Datenblatts. Soviel zu meiner 
"Vorgeschichte".

Jetzt zum Programm. Ich habe zu Beginn erst mal die Definition für die 
PWM an PB3 (OC2A) durchgeführt. Da ich im Datenblatt gelesen habe, dass 
man die PWM mit ner anderen Schrittweite am Port PD3 (OC2B) auch noch 
anlegen kann, dachte ich, man könnte das so deklarieren. Aber dem 
scheint nicht so.

Also möchte ich erst mal das Problem mit mit der PWM am PB3 lösen.

Ich komm einfach nicht weiter und weiß nicht wo ich mit der Fehlersuche 
ansetzen soll. Die folgende Dekleration müsste nach meinem Verständnis 
eigentlich passen (jetzt erst mal um ein PWM Signal am PB3 zu bekommen. 
Wenn ich allerdings mit dem Oszi am Port PB3 das Signal anschaue, kann 
ich keine PWM erkennen.
1
void pwm_generator(void)
2
{
3
  DDRB |= (1<<PB3);
4
  OCR2A=100;
5
  TCCR2A  |=  (1<<WGM21) |  (1<<WGM20);    //Modevorwahl Fast-PWM
6
  TCCR2A  |=  (1<<COM2A1) |  (0<<COM2A0);    //clear on Compare-match
7
8
  TCCR2B  |=  (1<<WGM22);                //Modevorwahl Fast-PWM
9
  TCCR2B  |=  (1<<CS22) |  (1<<CS21) |  (1<<CS20);  //Vorteiler N=1024
10
    
11
  TIMSK2  |=  (1<<TOIE2);            //Interrupt bei Overflow enable
12
}
13
14
15
ISR (TIMER2_OVF_vect)    //Interrupt Overflow Timer2
16
{
17
  OCR2A;    //Vergleichsregister neu beschreiben
18
}

von Bernadette (Gast)


Lesenswert?

Deswegen benutze ich BASCOM:

Config Timer1=Pwm,Pwm=9,Compare A Pwm=Clear Up,Compare B 
Pwm=Disconnect,Prescale = 1

Locate 1 , 1 : Lcd "PWM-Test"
Wait 1

Cls
Do

U1 = Getadc(1)

If U1 > 512 Then
   Direction = 1 : U1 = U1 - 512
Else
   Direction = 0 : U1 = 513 - U1
End If

If U1 > 510 Then U1 = 510

Pwm1a = U1

loop

von Karl H. (kbuchegg)


Lesenswert?

Simon Hi schrieb:

> Ich komm einfach nicht weiter und weiß nicht wo ich mit der Fehlersuche
> ansetzen soll.

Warum hat dein Code, als ich vor 3 Minuten hier reingesehen habe, noch 
ganz anders ausgesehen? Da war das Schalten auf Output bzw das Setzen 
von OCR2A noch nicht drinnen.

Poste deinen Originalcode!
Wenn der umfangreich ist, dann erzeuge ein Demoprojekt, das in sich 
vollständig ist und dein Problem zeigt.

Aber wenn du deinen Code extra fürs Forum jedesmal händisch umarbeitest, 
dann weiß man nie ob du in deinem realen Projekt dieselben Probleme 
hast!

Ein Demoprojekt nur für die PWM mit dem Timer 2 wäre sowieso angebracht. 
Dann könntest du nämlich ein komplettes Programm zeigen und nicht immer 
nur äußerst seltsame Ausschnitte, wie zb die Overflow ISR

von Simon H. (himmsi)


Angehängte Dateien:

Lesenswert?

So ich hab den Code nun angehängt. Die Overflow ISR stammt aus 
vorherigen versuchen, als ich versucht habe, die Pulsweite zu verändern.

von Karl H. (kbuchegg)


Lesenswert?

Das hier

  TCCR2A  |=  (1<<WGM21) |  (1<<WGM20);    //Modevorwahl Fast-PWM
  TCCR2B  |=  (1<<WGM22);                //Modevorwahl Fast-PWM


ergibt Modus 7.
In diesem Modus ist OCRA aber der Top-Wert und nicht der Vergleichswert. 
Du willst Modus 3 (der Timer läuft durch von 0 bis 0xFF, beide OCR 
Register stehen zur PWM Erzeugung zur Verfügung), darfst also WGM22 
nicht setzen.

(Siehe Tabelle 17-8 auf Seite 155 im Datenblatt)

von Simon H. (himmsi)


Angehängte Dateien:

Lesenswert?

Vielen dank für den Hinweis!!

Aus dem Datenblatt konnte ich diesen Unterschied nicht ablesen. Jetzt 
hab ich es geändert und es funktioniert!! Das mit dem PWM Signal am Port 
PD3 hab ich jetzt auch hinbekommen.

Vielen Dank nochmal!!

Im Anhang nochmal der funktionierende Code.

von Karl H. (kbuchegg)


Lesenswert?

Simon Hi schrieb:
> Vielen dank für den Hinweis!!
>
> Aus dem Datenblatt konnte ich diesen Unterschied nicht ablesen.

Drum ist diese Tabelle im Datenblatt so interessant. Da stehen die 
wesentlichen Eckpunkte aller Timer-Modi drinnen. Das ist eigentlich 
meistens mein erster Anlaufpunkt, wenn ich einen Timer Modus auswähle.

von Karl H. (kbuchegg)


Lesenswert?

Was hängt bei dir eigentlich am Port C?

Hintergrund: Du schaltest mir in deinem Programm etwas zuviel an den DDR 
Registern rum.
Wenn du dem Port C am Ende der lese_Eingang die unteren 4 Bits auf 
Ausgang schaltest, sind die Pullups dort noch aktiv. zb ein Taster der 
dort nach Masse gedrückt ist, ist für den AVR dann ein Kurzschluss am 
Ausgang nach Masse. Nicht gut!

In den meisten Programmen stellt man die DDRx am Anfang des Programms 
korrekt ein und dann werden sie in Ruhe gelassen!

Ich seh in deinem Programm eigentlich keinen guten Grund, warum man 
diese 4 Bits am C-Port jemals von Eingang auf Ausgang schalten möchte.

Selbiges für die Motor-Pins. Es gibt im Programm keinen wirklichen 
Grund, warum die alle 100ms erneut auf Ausgang geschaltet werden müssen.

von Simon H. (himmsi)


Lesenswert?

Ich hab am Port C Pin 0 bis Pin 3 ein Display angeschlossen. Das hab ich 
während der Entwicklung des Programms für die Ausgabe von Zuständen 
verwendet. Ist also noch ein überbleibsel. Den Code muss ich erst noch 
ein bisschen bereinigen.

von Simon H. (himmsi)


Lesenswert?

Zudem befinden sich am gleichen Port noch meine vier Taster - ebenfalls 
auf Pin 0 bis Pin 3. Deshalb muss ich immer zwischen Eingang und Ausgang 
umschalten.

von Simon H. (himmsi)


Lesenswert?

Ich hab's geändert. Zu Beginn werden jetzt meine Ausgänge definiert und 
anschließend nicht mehr verändert.

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.