Forum: Mikrocontroller und Digitale Elektronik AVR 16bit PWM Mode 14/15 mit 25kHz


von xeno (Gast)


Lesenswert?

Hallo miteinander,

Habe jetzt schon länger das Problem, dass ich es nicht schaffe auf einem 
Atmega1284p ein 16bit PWM mit ca. 25kHz zu programmieren.

Ich brauche insgesamt vier unabhängige einstellbare PWM-Kanäle mit 
unterschiedlichem duty-cycle - daher auch noch die Verwendung der 
16bit-Timer (auf den 8bit-Timern läuft schon alles ohne Probleme).

Mein Problem ist nun allerdings, dass, egal ob im Fast-PWM Mode 14 oder 
15, ich kein passendes Signal bekomme (habe leider kein Oszi um es zu 
testen, aber das Empfangsgerät reagiert nicht, also unpassende 
Frequenz).

Habe am Atmega den Fuse rausgenommen, damit er bei 8MHz läuft, womit 
sich theoretisch folgender Code ergeben müsste:

Im Mode15:
1
DDRD = (1<<PD4);  //PWM Timer1, OC1B, Pin18 - 16bit
2
3
TCCR1A = (1<<COM1B1) | (1<<WGM11) | (1<<WGM10);
4
TCCR1B = (1<<CS11) | (1<<WGM12) | (1<<WGM13);
5
  
6
OCR1A = 40;    //Top-Wert für 25kHz
7
OCR1B = 10;    //Duty-cycle

Im Mode14:
1
TCCR1A = (1<<COM1A1) | (1<<WGM11);
2
TCCR1B = (1<<CS11) | (1<<WGM12) | (1<<WGM13);
3
  
4
ICR1 = 40;    //Top-Wert für 25kHz
5
OCR1A = 10;    //Duty-cycle

Doch mit beiden Ansätzen funktioniert es nicht.
Wäre Klasse, wenn jmd einen Rat hätte.

Grüße

von amateur (Gast)


Lesenswert?

Keine Ahnung aber das Setzen des ICR1 ist nur bei Einzelereignissen 
sinnvoll.

von spess53 (Gast)


Lesenswert?

Hi

>DDRD = (1<<PD4);  //PWM Timer1, OC1B, Pin18 - 16bit
....
>OCR1A = 40;    //Top-Wert für 25kHz
>OCR1B = 10;    //Duty-cycle

Hier ist OC1B der Ausgang, also PD5.

Die Initialisierung ist eigentlich, bis auf die Ausgänge, in Ordnung. 
Lediglich der Topwert ist für 25kHz nicht 40 sondern 39.

MfG Spess

von xeno (Gast)


Lesenswert?

Den ICR1 will ich genau deshalb auch vermeiden, aber mich wundert 
einfach, dass es mit beiden nicht geht.

Ja sry, TOP-Wert müsste 39 sein, war bloß zu faul es zu ändern, aber ist 
gut innerhalb der Toleranz des Signals, also kein Problem.

Und ja, hab ich oben im Code vergessen: Bei Mode 14 hatte ich den 
Ausgang auf OC1A.

Aber wieso soll OC1B auf PD5 sein? Bei mir im Datenblatt ist der PD4 und 
der OC1A auf PD5 (da kann ich den Fehler auch ausschließen, da atm beide 
auf Ausgang stehen, sowohl als auch, auch schon getestet).

von spess53 (Gast)


Lesenswert?

Hi

>Keine Ahnung aber das Setzen des ICR1 ist nur bei Einzelereignissen
>sinnvoll.

>Den ICR1 will ich genau deshalb auch vermeiden, aber mich wundert
>einfach, dass es mit beiden nicht geht.

Unsinn. Mit OCR1A als Top hast du nur einen PWM-Kanal. Mit ICR1 zwei.

>Aber wieso soll OC1B auf PD5 sein? Bei mir im Datenblatt ist der PD4 und
>der OC1A auf PD5 (da kann ich den Fehler auch ausschließen, da atm beide
>auf Ausgang stehen, sowohl als auch, auch schon getestet).

Entschuldige. War ein Versehen.

MfG Spess

von xeno (Gast)


Lesenswert?

> Unsinn. Mit OCR1A als Top hast du nur einen PWM-Kanal. Mit ICR1 zwei.
Das ist mir klar, aber das ändert ja leider nicht das Problem, dass es 
nicht funktioniert.

Evtl. noch Ideen, wo der Fehler/das Problem liegen könnte?

Gruß

von Vlad T. (vlad_tepesch)


Lesenswert?

mit den ganzen Megas kannst du nur eine 16bit PWM mit maximal 305Hz 
erzeugen.

xeno schrieb:
> OCR1A = 40;

hiermit erzeugst du eine 5 komma irgendwas Bit PWM

von spess53 (Gast)


Lesenswert?

Hi

>Evtl. noch Ideen, wo der Fehler/das Problem liegen könnte?

Sicher, das du das richtige Programm flasht? Ansonsten den Timer so 
langsam machen, das du die PWM mit einer LED beobachten kannst.

MfG Spess

von Michael S. (rbs_phoenix)


Lesenswert?

Vlad Tepesch schrieb:
> mit den ganzen Megas kannst du nur eine 16bit PWM mit maximal 305Hz
> erzeugen.
>
> xeno schrieb:
>> OCR1A = 40;
>
> hiermit erzeugst du eine 5 komma irgendwas Bit PWM

Ich wollt schon fragen. 25kHz ist eine Periodendauer von 40µs. Das mit 
16 bit.. Da müsste der Timer ja mit 1638.4 MHz laufen.

von xeno (Gast)


Lesenswert?

Moment, ich lege doch einen neuen TOP-Wert fest, damit er eben nur noch 
bis dahin zählt - sonst würden all die Frequenzberechnungen ja keinen 
Sinn ergeben.
Wieso sollte er dann noch die vollen 16bit durchlaufen? Es handelt sich 
doch um einen Wertebereich für das Maximum des Interrupt-Flags, nicht 
eine Konstante.

Oder habe ich da einen Denk-/Verständis Fehler.

Aus dem Datenblatt(Seite 126, Letzter Absatz aus 16.9.3 Fast PWM mode):
"The waveform generated will have a maximum frequency of
 when OCRnA is set to zero (0x0000)."

von Hopp Triceratops (Gast)


Lesenswert?

Wenn man eine 16bit PWM haben will, dann verwendet man eine 8Bit PWM und 
macht nochmals 8 Bit mit Subzyklen. Dh man laesst sich den TimerOverflow 
geben und laedt da einen neuen PWM wert. Und den laedt man mit 
subzyklen. Also um einen PWM von 0x1280 zu haben laesst man den 
hardwaere PWM auf 0x12 laufen und aendert in 0x80 von 256 durchgaengen 
den Wert nach 0x13.

von Spess53 (Gast)


Lesenswert?

Hi

>"The waveform generated will have a maximum frequency of
>f_{OCnA} = f_{clk(I/O)}/2
> when OCRnA is set to zero (0x0000)."

PWM heisst Pulsweitenmodulation. Also es geht um ein Signal mit 
variablen Tastverhältnis bei fester Frequenz. Bei OCRnA=0 gibt es aber 
nichts mehr zu variieren. Da ist das Tastverhältnis 50%.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Mal anders rum gefragt

> Doch mit beiden Ansätzen funktioniert es nicht.

Was genau funktioniert denn nicht?
Ich nehme mal an, die 25kHz stimmen nicht. Wie groß ist denn die 
realisierte Frequenz?

> Habe am Atmega den Fuse rausgenommen, damit er bei 8MHz läuft
Und du hast auch kontrolliert, ob das stimmt?

Die Taktfrequenz ist Berechnungsbasis für alles weitere. Wenn die nicht 
stimmt, kannst du rumrechnen soviel du willst, das wird nie stimmen.

von xeno (Gast)


Lesenswert?

Ja, das ist das Problem, habe leider kein Oszi zur Hand um die Frequenz 
zu messen.
Der Fuse ist auf jeden Fall nicht mehr gesetzt, habe es eben noch einmal 
überprüft. Außerdem laufen ja schon zwei 8bit-Timer mit selbem Prinzip 
bei 25kHz (Timer0 und Timer2) auf dem Atmega mit passender 
Signalausgabe.

@Spess53: Da gebe ich dir recht, das steht auch so direkt im Datenblatt 
was du gesagt hast, wollte bloß nicht den ganzen Absatz kopieren, aber 
es heißt wiederrum eben auch das höhere Frequenzen möglich sind.

@Hopp Triceratops: Wie würde man so etwas den konkret umsetzen?


Um das ganze Problem noch mal zu konkretisieren:
Es geht um die Ansteuerung von mehreren PWM-Lüftern, die ich eben gerne 
in mehrere Kanäle splitten würde, da sie an unterschiedlichen Stellen 
eingesetzt werden.
Das Stellsignal ist dabei auf 25kHz (erlaubt zwischen 23 und 28kHz, also 
"kleine" Abweichungen kann ich auch ausschließen) bei +5V festgelegt, 
der duty-cycle gibt dabei prozentual die Drehzahl an.

Grüße

von holger (Gast)


Lesenswert?

>Es geht um die Ansteuerung von mehreren PWM-Lüftern,

16Bit PWM für einen beschissenen Lüfter.
Ich schmeiß mich weg;) Da reichen 10 Stufen.

von Karl H. (kbuchegg)


Lesenswert?

holger schrieb:
>>Es geht um die Ansteuerung von mehreren PWM-Lüftern,
>
> 16Bit PWM für einen beschissenen Lüfter.

Er hat keine 16 BIt PWM.
Er benutzt MOdus 14 oder 15.
(Also entweder ICR1 als Top oder OCR1A)

von Karl H. (kbuchegg)


Lesenswert?

Hmm.
Ich hab mal deine Konfiguration mit dem Datenblatt verglichen und 
nachgerechnet. Sie ist korrekt, wenn der µC ein Mega1284 ist und auf 
8Mhz läuft.

Irgendwelche sonstige Beeinflussung im Code (Output Pin irgendwo 
irrtümlich wieder abgeschaltet? OC2, also der Output vom Timer 2 liegt 
am gleichen Port und wenn du den so
   DDRD = (1<<PD7);
auf Output stellst, drehst du dir für den Timer 1 die Output Pins wieder 
ab).
Mein Vorschlag: ein Testprogramm, bei dem nur und ausschlieslich diese 
PWM in Betrieb genommen wird. Damit ist sicher gestellt, dass es nicht 
irgendwelche Querverbindungen zu anderem Code gibt.

1
#include <avr/io.h>
2
3
int main()
4
{
5
  // Timer 1: Fast PWM, Modus 15
6
  //   Top: OCR1A
7
  //   Duty: OCR1B
8
  //   Output Pin: OC1B, Pin PD4
9
10
  DDRD |= (1<<PD4);
11
12
  TCCR1A = (1<<COM1B1) | (1<<WGM11) | (1<<WGM10);
13
  TCCR1B = (1<<CS11) | (1<<WGM12) | (1<<WGM13);
14
  
15
  OCR1A = 39;    //8Mhz Takt, Vorteiler 8 -> 25kHz
16
  OCR1B = 10;    //Duty-cycle
17
18
  while( 1 )
19
  {
20
  }
21
}

von holger (Gast)


Lesenswert?

>>>Es geht um die Ansteuerung von mehreren PWM-Lüftern,
>>
>> 16Bit PWM für einen beschissenen Lüfter.
>
>Er hat keine 16 BIt PWM.

Das weiss ich. Ich finde nur den Betreff lustig.
Ansonsten hätte ich kein Problem damit per
PWM "La Paloma" von einer SD Karte auf einem
Lüfter per PWM abzuspielen;)

von Karl H. (kbuchegg)


Lesenswert?

holger schrieb:
>>>>Es geht um die Ansteuerung von mehreren PWM-Lüftern,
>>>
>>> 16Bit PWM für einen beschissenen Lüfter.
>>
>>Er hat keine 16 BIt PWM.
>
> Das weiss ich. Ich finde nur den Betreff lustig.
> Ansonsten hätte ich kein Problem damit per
> PWM "La Paloma" von einer SD Karte auf einem
> Lüfter per PWM abzuspielen;)

Ja. Das hat was :-)

von xeno (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> ...(Output Pin irgendwo
> irrtümlich wieder abgeschaltet? OC2, also der Output vom Timer 2 liegt
> am gleichen Port und wenn du den so
>    DDRD = (1<<PD7);
> auf Output stellst, drehst du dir für den Timer 1 die Output Pins wieder
> ab).

Och mist... Wie man sich an Kleinigkeiten eine Ewigkeit aufhalten 
kann...
Das wars! Habe dummerweise die Outputs nacheinander (Zeilenweise) 
definiert und das | (OR) vergessen.
Vielen dank dir!

Hoffe der Fehler war mir eine Lehre xD

@Holger: Dass das nicht gerade ein passendes Einsatzgebiet für einen 
16bit-Timer ist, ist mir klar, ändert aber nix daran, dass man ihn dafür 
verwenden kann ;)

Grüße

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.