Hallo, ich wollte in späteren Projekten die PWM des AVR (ATmega8) als DAC nutzen können. Aus diesem Grund habe ich mich mal mit der fast pwm auseinandergesetzt. Das Tastverhältnis kann ich auch über den OCR1A Wert ändern. Die PWM Frequenz liegt bei ca 61kHz (Oszillator 16MHz Quarz). Jetzt wollte ich ein Sinus ausgeben (klar, dass ich am Ausgang mindestens ein RC-Glied brauche) aber irgendwie scheint der die Zählerwerte (pwm_value), die das Tastverhältnis angeben, nicht zu übernehmen?
Oliver R. schrieb: > ... aber irgendwie scheint der die Zählerwerte (pwm_value), die > das Tastverhältnis angeben, nicht zu übernehmen? Was heißt "scheint"? Im Simulator kannst du doch sehen, ober die Werte jeweils ins Register geladen werden, oder nicht. Deine Modulation wird sehr schwach sein, solange du nur das OCR1AL Register schreibst.
Hallo, leider fehlt noch einiges am veröffentlichten Programm. Bitte hänge das noch mal an. nur so, macht das Sinn ?
1 | if (i == 90) i = -1; |
Ein Index der -1 ist ? Ich habe auch schon viel mit Audio-PWM gemacht und es sollten 3 PWM Schwingungen für eine Sinusstützstelle vorhanden sein, bei 256 Sinusstützstelle, ist das dann eine PWM-Frequenz von mindestens: f_PWM = 3 256 f Welche Ausgabefrequenz soll den erzeugt werden ?
Michael schrieb: > Deine Modulation wird > sehr schwach sein, solange du nur das OCR1AL Register schreibst. Nein, denn er benutzt doch die 8-Bit PWM. Ich würde sagen, der Controller rattert die Sinustabelle so schnell runter, dass die PWM nicht hinterherkommt. Du musst noch ein _delay_us(100) zwischen den Aktualisierungen einbauen, damit das Tastverhältnis auch korrekt geändert wird. So werden jetzt vielleich 10 - 50 Werte pro PWM-Zyklus in OCR1AL geschrieben - aber die PWM ist halt nicht schnell genug und übernimmt den Wert nur 1x pro Zyklus. Gruß Jonathan
Habe mir jetzt nicht alles angeschaut, aber ein paar Sachen die mir aufgefallen sind.
1 | TIMSK = (1 << OCIE1A); // activate on compare interrupt at channel 1 Timer1 |
Wo ist die passende ISR?
1 | while(1) |
2 | {
|
3 | OCR1AL = sine[i]; |
4 | if (i == 90) |
5 | i = -1; |
6 | i++; |
7 | }
|
Du aktualisierst OCR1AL viel zu schnell, du musst warten bis ein Compare ausgelöst wurde oder der Timer wieder von vorne anfängt zu zählen. Du hast nur ein viertel des Sinus berechnet, soweit so gut. Du musst das Array aber einmal vorwärts und einmal rückwärts durch laufen. So hast du zumindest die Positive Halbwelle, fehlt noch die negative Halbwelle.
1 | sine[i] = sin(pi/180 * i)*256; |
Bin mir nicht ganz sicher aber für sin() musste bei gcc-avr etwas beachtet werden, eine andere lib glaube ich.
1 | high = (((pwm_value) & 0xFF00)>>8); // set pwm value high part |
2 | low = ((pwm_value) & 0x00FF); // set pwm value low part |
3 | OCR1AH = high; |
4 | OCR1AL = low; |
OCR1AH belegst du nur ein einziges mal, ist das so gewollt? Gruß Marco
Uwe S. schrieb: > Ein Index der -1 ist ? ja ne danach kommt ja gleich i++! so, dass beim nächsten Lesen von sine[] der index mindestens 0 ist! Uwe S. schrieb: > f_PWM = 3 256 f > > Welche Ausgabefrequenz soll den erzeugt werden ? Das ist erstmal egal. Eigentlich wollte ich das so einfach mal ausgeben und schauen welche Frequenz raus kommt! Später hätte ich mich dann um eine spezielle Frequenz gekümmert.
Uwe S. schrieb: > nur so, macht das Sinn ? > > if (i == 90) i = -1; Ja, denn direkt darauf folgt ein i++. Das mache ich auch öfters so.
Jonathan Strobl schrieb: > Nein, denn er benutzt doch die 8-Bit PWM. Ich würde sagen, der > Controller rattert die Sinustabelle so schnell runter, dass die PWM > nicht hinterherkommt. Du musst noch ein _delay_us(100) zwischen den > Aktualisierungen einbauen, damit das Tastverhältnis auch korrekt > geändert wird. So werden jetzt vielleich 10 - 50 Werte pro PWM-Zyklus in > OCR1AL geschrieben - aber die PWM ist halt nicht schnell genug und > übernimmt den Wert nur 1x pro Zyklus. Jo das klingt plausibel werde ich gleich mal ausprobieren!
Hmmh ich hab gedacht, ich könnte so: for (i = 0; i <= 1600; i++) { j = i; } 100µs totschlagen? aber das scheint der kompiler wegzuoptimieren?
Oliver R. schrieb: > aber das scheint der kompiler wegzuoptimieren? Ach nee....... _delay_us(100) ist dein Freund... Gruß Jonathan
Jonathan Strobl schrieb: > Ach nee....... > > _delay_us(100) ist dein Freund... hmmhh ich hab das jetzt so gemacht, dass in der timer_isr immer ein Flag gesetzt wird und nur wenn dieses gesetzt ist, wird der pwm_value geändert! Das Ausgangssignal ist nach einem schlechten RC-Glied aber noch sehr weit von einem Sinus entfernt? (10µF + 5,1Ohm) Wie war das mit der Frequenz? also das Signal mit dem nicht wirklich Sinus förmigen Verlauf hat eine Frequenz von 666Hz!!
Oliver R. schrieb: > hmmhh ich hab das jetzt so gemacht, dass in der timer_isr immer ein Flag > gesetzt wird und nur wenn dieses gesetzt ist, wird der pwm_value > geändert! Sehr gut, das wäre dann nämlich der nächste Schritt gewesen ;) Oliver R. schrieb: > Wie war das mit der Frequenz? Da muss man teilen: 16MHz (µC-Takt) : 256 (Schritte pro PWM-Zyklus) : 90 (Sinus-Werte) = 694 Hz. Oliver R. schrieb: > 666Hz Ist doch nah dran, oder? Die 28Hz Unterschied sind Ungenauigkeiten von µC-Takt oder Messung. Oliver R. schrieb: > sehr weit von einem Sinus entfernt? Deine Sinus-Tabelle ist nicht vollständig. Gruß Jonathan
Oliver R. schrieb: > (10µF + 5,1Ohm) Das ist aber (fast) ein Kurzschluss. Mach das mal hochohmiger! Gruß Dietrich
Ich hab das jetzt ein wenig modifiziert und zwar mal 128 für positive Sinuswert und für negative Sinuswerte 128- positive Sinuswerte. sieht schon etwas mehr nach einem Sinus aus!!
> Da muss man teilen: > > 16MHz (µC-Takt) : 256 (Schritte pro PWM-Zyklus) : 90 (Sinus-Werte) = 694 > Hz. > Hmmh das heißt wohl im Umkehrschlusa, dass wollte ich ein Signal mit 20kHz darstellen dieses Signal nur mit knapp 3 Abtastwerten (hier proportional: pwm_duty cycles) darstellen muss!! --> samples = (16MHz/256)/20000kHz = 3,125
So jetzt habe ich noch ein wenig weiter herumgespielt: Jetzt mache ich das ganze ohne Sinus. Ich gebe einfach nur ein Signal mit einer bestimmten Frequenz aus. über FREQ_DIV kann man die Ausgabefrequenz variieren. z.B. für bei meiner Konstellation der Eintrag eines Wertes von 3 zur Ausgabe eines 11kHz Signales. Die maximal mögliche Frequenz läge dann bei ca 14kHz, aber das kann mein Lautsprecher nicht (oder ich)! jetzt kann ich mir ja mal beizeiten Gedanken über eine ausgefuchstere Lösung machen bzw. schauen, wie das mit dem ADC war und dann beides kombinieren!
Je schneller desto weniger Stüzstellen. Daher ist das für hohe Frequenzen ungeeignet. Knut
hallo Oliver, noch ein Tipp zum Sinus, bei 254 Bit PWM-Auflösung liegt der 0V Punkt digital auf 128 Bit = 0x80. Das ist auch der Shift (Achsenverschiebung) für deine Sinustabelle. Mit einer pi/4 Sinustabelle können die 4 Abschnitte eines Sinuses ausgegeben werden. Abschnitt 1: fsin(0),..,fsin(89) 2: fsin(90),..,fsin(1) 3: -fsin(0),..,-fsin(89) 4: -fsin(90),..,-fsin(1) fsin(x) ist der Tabellenwert, -fsin(x) der an der X-Achse gespiegelte Wert.
Hallo Olover, schau dir bitte die attiny85 und attiny861 an, dort kann die PWM-Einheit bis 64MHz laufen, da eine PLL den Takt entsprechned erhöht. Der AVR sollte dann auch mit 16MHz laufen und hat sehr viel zu tu, um die Sinustabelle aus zu geben. Ich habe das schon verwendet und einen HiFi Tongenerator für CW Übungen programmiert. Über 5 Perioden wird die Lautstärke am Anfang und Ende des Tons hoch und wieder heruntergeregelt...
Uwe S. schrieb: > schau dir bitte die attiny85 und attiny861 an, dort kann die PWM-Einheit > bis 64MHz laufen, da eine PLL den Takt entsprechned erhöht. Der AVR > sollte dann auch mit 16MHz laufen und hat sehr viel zu tu, um die > Sinustabelle aus zu geben. ja ist auf jeden Fall ne Überlegung wert! Ich hab mal in das Datenblatt des Tiny geschaut. Ich hab irgendwie den Eindruck, dass der in fast allen Belangen besser als der ATmega8 ist! Cool finde ich ja den eingebauten Temperatursensor! Und das mit dem fast pwm soll ja genauso wie bei der fast pwm des Atmega8 gehen? wenn ich dann meinen Sinus mit 90 Stützstellen ausgeben wollte hätte der dann eine Frequenz von 2,7kHz? f = (64MHz/256)/90 256 repräsentiert den "TOP VALUE" der PWM!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.