Forum: Mikrocontroller und Digitale Elektronik kurze Frage zur AVR fast pwm sinus-ausgabe?!


von Oliver R. (rollinator)


Angehängte Dateien:

Lesenswert?

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?

von Michael (Gast)


Lesenswert?

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.

von Uwe (de0508)


Lesenswert?

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 ?

von Jonathan S. (joni-st) Benutzerseite


Lesenswert?

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

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

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

von Oliver R. (rollinator)


Lesenswert?

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.

von Jonathan S. (joni-st) Benutzerseite


Lesenswert?

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.

von Oliver R. (rollinator)


Lesenswert?

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!

von Oliver R. (rollinator)


Lesenswert?

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?

von Jonathan S. (joni-st) Benutzerseite


Lesenswert?

Oliver R. schrieb:
> aber das scheint der kompiler wegzuoptimieren?

Ach nee.......

_delay_us(100) ist dein Freund...


Gruß
Jonathan

von Oliver R. (rollinator)


Angehängte Dateien:

Lesenswert?

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

von Jonathan S. (joni-st) Benutzerseite


Lesenswert?

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

von Dietrich L. (dietrichl)


Lesenswert?

Oliver R. schrieb:
> (10µF + 5,1Ohm)

Das ist aber (fast) ein Kurzschluss. Mach das mal hochohmiger!

Gruß Dietrich

von Oliver R. (rollinator)


Angehängte Dateien:

Lesenswert?

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

von Oliver R. (rollinator)


Lesenswert?

> 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

von Oliver R. (rollinator)


Angehängte Dateien:

Lesenswert?

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!

von Knut (Gast)


Lesenswert?

Je schneller desto weniger Stüzstellen. Daher ist das für hohe 
Frequenzen ungeeignet.


Knut

von Uwe (de0508)


Lesenswert?

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.

von Uwe (de0508)


Lesenswert?

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

von Oliver R. (rollinator)


Lesenswert?

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
Noch kein Account? Hier anmelden.