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.
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!
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
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!
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!