Hallo,
ich möchte gerne mit einem AVR in C einen Sinus / Cosinus mittels PWM
erzeugen.
Die Forensuche und Google habe ich schon fleißig genutzt. Leider fehlt
mir da das Verständnis wie ich soetwas realisiere.
Folgendes habe ich herausgelesen:
Ich brauche zwei Timer, ein PWM Timer, ein durchlaufender Timer.
Dem PWM Timer übergebe ich im Überlauf Interrupt des anderen Timers die
entsprechenden Werte aus einer Tabelle in seine Vergleichsregister.
Wie ermittel ich denn nun die PWM Werte für den Sinus / Cosinus?
Und vor allem: Mit welchem Timing sollten die Timer laufen?
Ich möchte, wie erwähnt, einen Sinus und einen Cosinus mit einer
Frequenz von ~40...70Hz erzeugen, wobei die Frequenz und Phasenversatz
einstallbar sein soll.
Vielleicht bekomme ich ja hier die nötigen Tipps (in Form von Beiträgen
oder Verweise auf Erklärungen)?
Mir geht es hier nicht um das Handling mit Tabellen, C oder der
Registereinstellungen für die Timer.
Danke
Ernst
Falls ich dich richtig verstanden habe:
Sin und Cos hat Werte zwischen -1 und 1. Die PWM Werte zwischen 0 und 1.
Somit musst du den Mittelpunkt auf 0,5 setzen.
Wenn also sin(0°)=0 dann ist v_T = 0,5.
sin(30°)=0,5 -> v_T = 0,75
sin(90°)=1 -> v_T =1
....
Formel: v_T= (sin(phi)+1)/2
Ich würde es folgendermaßen probieren:
Die eine PWM hat eine Periodenlänge von T_1=1/f
Die andere PWM probierst du mit z.B T_2=1/100*T_1
Jetzt lässt du die 2. PWM jeweils mit den vorausberechneten v_T laufen.
Ganz einfach, mit der PWM erzeugst du dir durch einen anschließenden
Tiefpass ne Gleichspannung. Diese Gleichsspannung kannst du von 0-Umax
durch setzen des Tastgrades einstellen. Das heist, dein Sinus hat einen
Offset von seiner Amplitude. Also Ausgang soll 0-5V sein. Bedeutet du
kannst ihn mit 8-Bit PWM zwischen 0 und 5V in 256 Schritten einstellen.
Dein Sinus darf nicht negativ sein und erhält einen Offset auf die halbe
Ausgangsspannung. In dem Fall 2,5V. Dies bedeutet für dich, eine 8-Bit
PWM wird um den Wert 127 herum verändert.
Also Sinus hat eine Amplitude von maximal 2,5V, denn dann geht er von
0-5V.
Du musst dir also ne Wertetabelle anlegen und die Sinuswerte vorher
ausrechnen.
Deine PWM-Frequenz sollte ein ganzes Stück höher liegen als deine
Sinusfrequenz. Mal angenommen deine 8-Bit-PWM läuft mit 64kHz und du
möchtest einen Sinus mit 50Hz erzeugen, hat dieser 256 Zustände die
aller 5 PWM-Perioden aktualisiert werden.
f = 64kHZ/(50Hz*256*x) mit x=5 folgt f=50Hz
Wenn du nicht die Perioden der PWM zählen willst, dann nimm einfach nen
zweiten Timer der dir aller 78,125µs (1/(50Hz*256)) den nächsten Wert
läd.
O.K.
Ich brauche also eine Tabelle mit 256 Werten.
Berechnung: for (i=0; i<255; i++)
wert[i]=128+127*sin((double)i/256*2*pi);
Ich verstehe nun leider nicht, wann, welche Werte davon genau in die
entsprechenden Vergleichsregister vom PWM Timer geladen werden müssen.
Ich möchte ja Frequenz und Phasenversatz einstellen können.
Gehen wir davon aus, dass ich einen PWM Timer nutze (für sin & cos) und
einen freilaufenden Timer der einen Interrupt bei Überlauf ausführt.
In der Überlauf ISR, was muss ich da genau machen. Hier sind die
tatsächlichen Frequenzen der Timer doch dann relevant???
Es wäre toll, wenn mir das jemand schrittweise erläutern kann!
Gruß
Ernst
BTW: Ist es nicht besser eine möglichst große Tabelle anzulegen um einen
sauberen Sinus zu erzeugen? Also >255?
Kennt jemand eine Quelle, wo die ganze Thematik "für dumme" erklärt
wird?
Irgendwie scheint hier allen klar zu sein wie so etwas funktioniert,
bloß mir nicht ;-)
Gruß
Ernst
Ernst wrote:
> Ich möchte ja Frequenz und Phasenversatz einstellen können.
Sieh erst mal zu, dass du überhaupt einen Sinus rauskriegst.
Wenn du dann soweit bist, kannst du ja mal darüber nachdenken, wie man
die Frequenz einstellen kann. Wenn du den Sinus erst mal am Ausgangspin
hast, hast du auch das Wissen, wie man Frequenz bzw. Phasenlage (Phase
in Bezug worauf eigentlich?) einstellen kann.
> Irgendwie scheint hier allen klar zu sein wie so etwas funktioniert,> bloß mir nicht ;-)
Weil es im Grunde watscheneinfach ist.
Können wir mal davon ausgehen, dass du eine PWM hast.
Sprich: Du stellst einen Wert in einem Register ein und am Ausgangspin
(+nachfolgender Elektronik) erscheint die zugehörige Spannung.
Das nehmen wir jetzt einfach mal als gegeben an. Das ist so und
funktioniert (und das sollte dein erster Teilschritt zur Lösung des
kompletten Problems sein)
Was ist dann so eine Sinusschwingung?
Ganz einfach: Über die Zeit gesehen, 'schwingt' die Spannung an besagtem
Ausgangspin in Form einer Sinusschwingung.
Willst du zb haben, dass eine Sinusschwingung 1Hz hat, muss die
Ausgangsspannung in einer Sekunde einmal von 0 nach +1 nach -1 und
wieder zurück nach 0 kommen. (von 2.5 Volt nach +5V nach 0V und zurück
nach 2.5V)
Ist deine Tabelle mit den Stützwerten jetzt 256 Einträge lang, heist
das, dass in besagter 1 Sekunde alle 256 Werte nacheinander an den
Ausgangspin 'geschickt' werden müssen. Wenn möglich in gleichmässigen
Zeitabständen :-)
Daraus folgt: Du musst alle 1/256 Sekunde den jeweils nächsten Wert
ausgeben.
Daraus folgt weiters: Du brauchst einen Mechanismus, der alle 1/256
Sekunde getriggert wird, um jeweils den nächsten Wert auszugeben. Das
ist dein Zeitimpuls, der die Ausgabe vorantreibt.
Wie ist das bei einer Wunschfrequenz von 2 Hz?
Na offensichtlich, muss dann alles doppelt so schnell ablaufen.
Du brauchst einen Mechanismus der dir alle 1/512 Sekunde auslöst. Bei
jedem Auslösevorgang wird der jeweils nächste Tabellenwert an den
Ausgang gelegt (wenn die Tabelle zu Ende ist, fängst du wieder mit dem
ersten Wert an). Da deine Tabelle 256 Einträge lang ist, wird also in 1
Sekunde die Tabelle 2 mal ausgegeben. Und da deine Tabelle genau eine
Schwingung enthält, bedeutet das, dass in 1 Sekunde 2 komplette
Schwingungen ausgegeben werden. Das wiederrum sind 2Hz
Wenn nun dein Zeitimpuls alle 1/512 Sekunde kommt, kannst du dann immer
noch eine Schwingung mit 1Hz erzeugen?
Aber sicher doch! Du ignorierst einfach jeden 2-ten Zeitimpuls. Das
Signal kommt zwar 512 mal in der Sekunde, aber wenn du nur jedes 2-te
mal reagierst, gibst du die komplette Tabelle in einer Sekunde nur
einmal aus -> du hast wieder 1Hz
Was ist, wenn dein Zeitimpuls nicht 512 mal sondern 5120 mal in der
Sekunde kommt. Gleiches Spielchen: Bei einer Tabellengrösse von 256 und
5120 Ausgabetriggern in der Sekunde, wird die Tabelle 20 mal ausgegeben
und da jede komplette Tabellenausgabe ein kompletter Wellenzug ist, hast
du 20 Hz. Kleinere Frequenzen kannst du nach wie vor erreichen, indem du
nicht bei jedem Zeitimpuls eine Ausgabe machst, sondern zb nur bei jedem
2-ten, jedem 3-ten etc.
Und das wars dann eigentlich schon. Alles was du brauchst, ist eine
Idee, wie du den Zeitimpuls realisieren kannst. Und da kommt jetzt der
2-te Timer ins Spiel. Mit seinem Overflow Interrupt kannst du dir zb.
diesen Zeitimpuls erzeugen.
In deiner Vorstellungswelt, musst du die PWM vom Ausgeben der Schwingung
trennen! Das erste hat mit dem zweiten nichts zu tun!
DIe PWM sorgt dafür, dass ein Wert in einem Register in eine Spannung
übersetzt wird. Die PWM interessiert sich aber nicht dafür, wo dieser
Wert herkommt.
Der andere Timer hat eine ganz andere Aufgabe. Seine Aufgabe ist es,
Werte aus einem Array in regelmässigen Zeitabständen zur Verfügung zu
stellen. Ob dieser Wert an einen Port ausgegeben wird um dort
irgendwelche Lämpchen einzuschalten (und so vielleicht ein Lauflicht zu
realisieren) oder ob diese Werte über eine Serielle Schnittstelle
verschickt werden oder ob diese Wert zufällig in besagtes Register zu
laden ist, aus dem sich die PWM versorgt, ist dem Timer erst mal egal.
Der liefert aus dem Array einen Wert nach dem anderen. Und das in
regelmässigen Zeitabständen.
PWM - ist dafür zuständig eine bestimmte Spannung
zu erzeugen
2.te Timer Overflow - sagt der PWM in regelmässigen Zeitabständen
welche Spannung zu erzeugen ist.
Fang mal mit deinem ersten Teilziel an:
Eine PWM laufen zu kriegen, die dir an einem Ausgangspin eine bestimmte
Spannung realisiert.
Grundsätzlich solltest du dich erst einmal mit der Gleichstromerzeugung
mittels PWM befassen.
1.Durch den TP, auf den du deine PWM gibst, wird diese integriert. Das
bedeutet du brauchst einige Perioden damit dein Signal steht. Je weiter
weg die PWM-Frequenz von der Grenzfrequenz des Tiefpass liegt, desto
weniger Ripple hast du.
2. Die einstellbaren Spannungswerte hängen von deiner PWM ab. Bei 8-bit
ergeben sich nun mal nur 256 Tastgrade und somit auch nur 256
Spannungswerte. Also musst du auch nur 256 Werte berechnen.
3. Deine Sinusfrequenz hängt von dem TP-Filter und der Anzahl der
verwendeten Spannungswerte.
Mal angenommen du willst einen 100Hz Sinus mit 256 Spannungswerten
erzeugen. Dann muss du mit einer Frequenz von 100Hz*256 = 25,6kHz die
Spannungswerte (Vergleichswerte) an den PWM-Generator schreiben. Der TP
muss nun jeden Wert integrieren. Mal angenommen deine PWM-Frequenz soll
um den Faktor 10 höher liegen als der TP, dann bedeutet es doch, dass
der TP auf 25,6kHz gelegt wird und deine PWM mit 10*25,6kHz = 256kHz
durchgeführt werden muss.
Wenn du statt 8-Bit PWM eine 10-Bit-PWM nehmen willst, dann ergeben sich
die Werte wie folgt:
Wertübergabe an PWM-Generator mit f = 102,4kHz
Grenzfrequenz Tiefpass: 102,4kHz
PWM-Frequenz: 1,024MHz
Hallo,
erst einmal ein riesen Dank an Karl Heinz!!!
Mit deinem Text, Stift und Zettel ist mir nun einiges klar geworden.
Ich habe mir gerade ein kleines C# Programm geschrieben um eine
Sinustabelle zu erzeugen.
Verstehe ich also richtig, wenn ich folgende Rechnung aufstelle
(CPU_Clock / 256)/ 256 = Basisfrequenz ???
Also z.B.
(16MHz / 256) / 256 = 244,141Hz
Wenn ich nun den PWM Timer (8Bit) und den durchlaufenden Timer (8Bit)
mit
vollem Takt (16MHz) laufen lasse und in jedem Timer Überlauf einem nach
dem anderen Tabbelenwert ausgebe, habe ich eine Frequenz von 244,141Hz.
Erhöhe ich den Zeiger auf den Tabellenwert nur jeden
-zweiten Interrupt =>
244,141 / 2 = 122.0705Hz
- dritten Interrupt =>
244,141 / 3 = 81,380 Hz
usw.
Vielleicht ist das Quatsch was ich gerade geschrieben habe???
Wie kann ich denn die Frequenz jetzt auf 1/10 Hz genau einstellen ?
PWM läuft. Am Wochenende werde ich mal den Sinus mit voller Frequenz
ausgeben.
Vielen Dank für die Unterstützung!
Gruß
Ernst
Wenn die PWM läuft fehlt nur die DDS.
Hatte ich im Forum schonmal erklärt:
Hallo,
du must das System on DDS richtig kapieren.
Deine Tabelle hat 256 Einträge (hier Sinuswerte für eine Periode).
Dein Timer macht ein festes Zeitfenster (CTC mit reload).
Nehmen wir an, das Zeitfenster ist 39,0625 µS (Nachladewert 144 TZ)
und du gibst jedesmal denn nächsten Tabellenwert aus bedeutet das
für eine Periode (Tabelle 0-255) 10 ms (256*39,0625 µs) => eine
Frequenz von 100 Hz.
Das Bedeutet du hast eine Grundfrequenz von 100 Hz.
Du willst jetzt aber 300 Hz ausgeben. Dann mußt du bei
jedem Interrupt nicht eine sondern 3 Positionen weiterspringen.
Dein Additionswert ist jetzt 3.
-> Tabellenposition += Additionswert im Interrupt
mit Additionswert = Ausgabefrequenz / Gundfquenz
Was ist aber bei 25 HZ? Wir brauchen Nachkommastellen.
Additionswert = 25 / 100 = 0,25
Ein UINT16 besteht aus 16 Bit. Wir denken uns jetzt ein Komma
zwischen HighByte und LowByte. Für die 3 von oben steht dann
binär 0000 0011 (,) 0000 0000 und für unsere 0,25
binär 0000 0000 (,) 0100 0000
Unser Tabellenzähler ist jetzt natürlich auch UINT16, das Highbyte
ist dabei unsere Tabellenposition für den Sinuswert.
Wenn man das sauber weiterrechnet kommt man auf die einfache
Endformel (bei 256 Werten):
Additionswert = Ausgabefrequenz Aulösung_max Nachladewert_Timer/Fosc
hier Auflösung_max = 2^16 (16Bit Zählerbreite)
Je höher die Auflösung umso feiner kann abgestuft werden, ein schneller
Fosc sorgt für saubere Signale bei größerer Ausgabefrequenz.
Ich hoffe, so ist es verständlich erklärt.
Gruß Hansl
Hallo Hansl,
jetzt komme ich total durcheinander.
Also ich rechne:
- In der ISR: Tabellenposition += Additionswert im Interrupt
mit Additionswert = Ausgabefrequenz / Gundfquenz
Z.B.
- Additionswert = 25 Hz / 100 = 0,25
Das High Byte ist dann meine Tabellenposition.
Hier die von dir angegebene Endformel:
Additionswert = Ausgabefrequenz Aulösung_max Nachladewert_Timer/Fosc
Was kommt dazwischen? * , / ,... ?
Danke
Das mal! (x, * )
Dann hast du in der Interruptroutine die Tabellenposition berechnet,
das High-Byte ist der ganszahlige Anteil für die Tabelle, holst den
Wert und gibst ihn an deine PWM weiter.
gruß hans
Hallo,
Additionswert = Ausgabefrequenz Aulösung_max
(Nachladewert_Timer/Fosc) ???
Wofür steht denn jetzt Auflösung_max ?
Bis zum Posting von dir habe ich noch (fast) alles Verstanden ;-)
Jetzt werden die Stützpunkte doch weniger, wenn ich nur jeden 3. oder 4.
oder ... aus der Tabelle lese?
Um einen sauberen Sinus zu bekommen sollten es doch nicht zu wenig
Stützpunkte werden, verstehe ich das richtig?
Viell. wäre dann eine >10 Bit PWM sinnvoll.
Ich brauche wohl erst einmal ein wenig Zeit um einen Sinus mit fester
Frequenz auszugeben.
Am Wochenende schnappe ich mir mal mein Board und Messe mal was sich
dann nach dem Ausgangsfilter tut.
Gruß
Ernst
Ernst wrote:
> Jetzt werden die Stützpunkte doch weniger, wenn ich nur jeden 3. oder 4.> oder ... aus der Tabelle lese?
Ja klar.
Wenn du in einer Sekunde angenommen maximal 100 Werte ausgeben kannst,
aber 300 ausgeben müsstest, dann muss irgendwo etwas auf der Strecke
bleiben.
> Um einen sauberen Sinus zu bekommen sollten es doch nicht zu wenig> Stützpunkte werden, verstehe ich das richtig?
Richtig - Shannonsches Abtasttheorem.
>> Viell. wäre dann eine >10 Bit PWM sinnvoll.
Das hat damit nichts zu tun.
Hier geht es lediglich um die Zeitauflösung deines Sinus. Oder mit
anderen Worten: Wenn man sich eine komplette Schwingung ansieht, aus
wievielen Punkten besteht sie. Die Feinheit der PWM regelt, wie fein du
die Amplitude jedes einzelnen Stützpunktes einstellen kannst. Das hat
aber nichts damit zu tun, wieviele Werte du in eine Schwingung packen
kannst. Ganz im Gegenteil: Je mehr Bits du in die PWM steckst, umso mehr
sinkt die Grenzfrequenz bis zu der die PWM deinen Vorgabewerten noch
folgen kann. Und damit sinkt dann auch die maximale Frequenz, die dein
DDS noch sauber generieren kann. Das folgt unmittelbar daraus, wie eine
PWM funktioniert. Je mehr Bits - desto langsamer reagiert die PWM (weil
ja der Zähler einen größeren Umfang zählen muss)
(In diesem Sinne habe ich bisher einen Zusammenhang ignoriert, um dich
nicht zu verwirren. Ich hab weiter oben mal gesagt, dass der
Abtasttimter mit der PWM nichts zu tun hat. Das stimmt so nicht ganz.
Die PWM setzt dir prinzipielle Grenzen, wie schnell dein Abtasttimer
maximal sein kann/darf. Es ist ja völlig sinnlos, wenn dein Abtasttimer
sagen wir mal 400 Werte in der Sekunde zur PWM schickt, wenn die PWM
selber nur maximal 100 Werte in der Sekunde realisieren kann. PWM ist ja
auch nicht gratis, die braucht ja auch Zeit für sich [folgt aus dem
Funkionsprinzip]: Je mehr Bits in der PWM realsiert werden - desto
langsamer)
Ist jeder Beitrag !direkt! an dich persönlich gerichtet?
Ja: Ich bitte um Entschuldigung das ich nicht so schlau bin wie du es
bist.
Nein: Dann ignorier es doch einfach!
Liebe Grüße
Ernst
"Nur mal als Tipp. Für das Thema braucht man nicht Leute in einem Forum
zu nerven."
Hast du auf der Uni gelernt, so freundlich gegenüber Leuten zu sein, die
nicht ihr halbes Leben Zeit hatten abi zu machen und zu studieren (von
Mama und Papa gesponsored)???
Gast wrote:
> "Nur mal als Tipp. Für das Thema braucht man nicht Leute in einem Forum> zu nerven.">> Hast du auf der Uni gelernt, so freundlich gegenüber Leuten zu sein, die> nicht ihr halbes Leben Zeit hatten abi zu machen und zu studieren (von> Mama und Papa gesponsored)???
Quatsch, so alt bin ich noch gar nicht.
Hallo,
jetzt hatte ich ein wenig Zeit die ganze Sache mal in der Hardware zu
testen.
Ich habe eine Tabelle mit 2048 Werten angelegt. Der Timerinterrupt für
die Ausgabe der Tabellenwerte auf das PWM Register erfolgt nach 256
Takten.
Der CPU Takt liegt bei 20MHz.
O.K. die Basisfrequenz liegt jetzt bei 30,05Hz. Das lässt sich auch mit
dem Oszilloskop bestätigen.
Meine Interrupt Overflow sieht so aus:
1
ISR(TIMER0_OVF_vect){
2
3
4
5
6
OCR1BL=pgm_read_byte(&signal[test]);
7
8
9
test+=1;
10
if(test>=2048)
11
test=0;
12
}
Wird der Tabellenwert nur jeden zweiten Interrupt erhöht, so messe ich
knapp 30Hz. Erhöhe ich die Tabellenposition pro Interrupt um 2
Positionen komme ich auf 61Hz.
Soweit so gut ;-)
Ich verstehe bloß nicht wie ich jetzt auf z.B. 50Hz kommen soll ?
Hansl hatte ja bereits folgendes erklärt:
"Additionswert = Ausgabefrequenz / Gundfquenz
Was ist aber bei 25 HZ? Wir brauchen Nachkommastellen.
Additionswert = 25 / 100 = 0,25
Ein UINT16 besteht aus 16 Bit. Wir denken uns jetzt ein Komma
zwischen HighByte und LowByte. Für die 3 von oben steht dann
binär 0000 0011 (,) 0000 0000 und für unsere 0,25
binär 0000 0000 (,) 0100 0000
Unser Tabellenzähler ist jetzt natürlich auch UINT16, das Highbyte
ist dabei unsere Tabellenposition für den Sinuswert.
"
Rechne ich jetzt Wunschfrequenz / Grundfrequenz:
50Hz / 30,5Hz = 1,64
Also müsste ich die Tabellenposition immer (Overflow ISR) um 1,64
Stellen erhöhen.
Das kann ich jetzt leider nicht auf die Aussage von Hansl beziehen.
Bei 0,25 gibt er jetzt 0000 0000 (,) 0100 0000 an. Wieso???
Kann mir bitte jemand auf die Sprünge helfen?
Danke!
Ernst*
*(der nicht studiert hat und auch im Job nichts mit Elektronik zu tuen
hat)
bekomme ich auch 50Hz heraus :-)))
Ehrlich gesagt, verstehe ich das Prinzip noch nicht ganz.
Wie sieht es denn aus wenn ich genauere Frequenzen möchte, also in einer
möglichst feinen Auflösung (z.B. in 0,2Hz Schritten).
Ich könnte ja die Wunschfrequenz mit 1000 Multiplizieren. Bei 33Hz dann
33000 als Int...???
Gruß
Ernst wrote:
> Wie sieht es denn aus wenn ich genauere Frequenzen möchte, also in einer> möglichst feinen Auflösung (z.B. in 0,2Hz Schritten).
Na dann brauchst du vor allem eine größere Tabelle und einen schnelleren
Takt. Nicht umsonst kriegen DDS Chips wie AD9833 nen Takt von 50MHz.
Hallo,
ich hätte mich viell. anders ausdrücken sollen. Ich möchte die Frequenz
verstellen können. Mir schwebt da eine Schrittweite von 0,01Hz vor
(bitte nicht schlagen ;-) ).
Ist das mit dem Verfahren und meinem Hardwarevorraussetzungen ( CPU
Takt, 2048 Werte Tabelle, 8Bit ISR Timer) möglich?
Gruß
Ernst
Der Schrei nach einer noch größeren Tabelle ist reiner Unsinn!
Die Tabellengröße hat mit der Frequenzauflösung nichts zu tun.
Die jetzige ist schon zu groß für die gewünschte Aufgabe mit
PWM-Ausgabe und 40-70 Hz.
Es geht um den Zähler mit dem die Tabellenadresse berechnet wird.
So wie Ernst es jetzt mit seiner Tabelle macht hat er einen
16 Bit Zähler, die obersten 11 Bit ergeben die Tabellenposition
(0-2047).
D.h. er hat 5 Bit Nachkommastellen (1/2 1/4 1/8 1/16 1/32).
Für eine höhere Auflösung braucht er einen breiteren Zähler um
mehr Nachkommastellen unterzubringen. In Assembler würde man
einfach ein Byte dranhängen, in C bleibt (fast) nur der
Einsatz von Unsigned Long.
Die ersten 11 Bit bleiben die Tabellenadresse (Ganzzahlanteil),
der rest ist Nachkommastellen.
Das bearbeiten von 32 Bit Zahlen kostet Zeit, der Interruptaufruf
ebenfalls. Pass auf, das dein Interrupt nicht zu lang wird.
Sonst die Tabelle auf 8 Bit zurückführen, die Interrupthäufigkeit
hochsetzen (Faktor 32 oder mit neuer Grundfrequenz rechnen) und
dann mit dem 32 Bit-Zähler arbeiten.
gruß hans
Hallo Hans,
ich habe die Tabelle so "groß" dimensioniert, weil ich ja noch einen
weiteren phasenverschobenen Sinus ausgeben möchte und der Phasenversatz
möglichst kleinschrittig einstellbar sein soll.
Bei 360° / 2048 hätte ich ja dann ~ 2 ° Schrittweite.
Verstehe ich dich richtig, dass ich für mein Vorhaben dann komplett mit
32 Bit Variablen rechnen müsste, d.h. ein 32 Bit Tabellenzähler
1
FCV=(uint32_t)freq*4294967296*256/F_CPU;
In der ISR dann
1
STEP+=FCV;
2
//von 32 Bit auf Tabellenlänge 2048
3
OFFSET=STEP/2097152;
4
OCR1BL=pgm_read_byte(&signal[OFFSET]);
Bloß wie rechne ich jetzt für "krumme" Frequenzen, wie 50,01Hz oder
50,02Hz , den FCV aus ?
Mit meinem Beispiel oben kann ich ja nur mit ganzen Integer den FCV
ausrechnen.
Der Controller muss sonst nicht viel können, wenn also ein guter Teil
der Ressourcen für die Erzeugung vom Sinus + phasenversetztem Sinus
drauf geht.
Es wäre toll wenn mir da jemand der Ahnung hat helfen kann!
Bis vor einer Woche hätte ich nie gedacht das ich überhaupt einen so
sauberen Sinus aus meinem ATMega 32 heraus kriege ;-)
Gruß
Ernst
Du must halt bei dieser Berechnung auch mit Nachkommastellen arbeiten.
50.5 Hz sind ja das das gleiche wie 505/10 Hz im Dezimalsystem.
Oder 3280/100 in HEX (12928/256=50.5x256/256).
Für die Frequenz in deiner Formel einfach den Wert mit Nachkomma
einsetzen (256 oder 2^x kürtzt sich dann teilweise raus).
Für den Phasenversatz ist ebenfalls nicht die Tabellengröße
wichtig. Hier entscheidet ebenfalls nur der Zähler.
Der eine startet bei 0 der andere bei einem Startwert=Phasenversatz.
0° Phase => Startwert 0
180° Phase => Startwert Tabellengröße/2 (da Tabelle = 360°).
Auch hier kommt es auf die möglichen Nachkommastellen an.
gruß hans
hans wrote:
> Der Schrei nach einer noch größeren Tabelle ist reiner Unsinn!>> Die Tabellengröße hat mit der Frequenzauflösung nichts zu tun.
Indirekt schon, denn bei ganz langsamen Frequenzen will man ja immer
noch möglichst wenig "Treppen" im Signal haben. Wobei das mit dem RC
Tiefpass ja sowieso entschärft wird.
Wobei das natürlich auch nichts mit der Frequenzauflösung direkt zu tun
hat. Aber wenn die Frequenzauflösung halt 50Hz beträgt (als Beispiel),
dann ist 50Hz auch die kleinste Frequenz.
Also hat die Tabellengröße quasi zwei mal indirekt was mit der
Frequenzauflösung zu tun. Najo, hab mich mit dem Thema noch nie so
wirklich befasst.
@Simon
Wenn du schon sagst, daß du dich niecht damit beschäftigt hast, dann
sei doch bitte ruhig, bis sich dieser Zustand geändert hat.
Deine Aussage bzgl. der 50 Hz als kleinste Frequenz ist reiner
Schwachsinn!
Wenn die Grundfrequenz bei 50 Hz liegt, d.h. mit einem Additionswert
von 1 (jeder Tabellenwert nacheinander), ist mit der entsprechenden
Anzahl an Nachkommastellen für den Zähler und den Additionswert jede
Frequenz <50 Hz realisierbar. Der Tabellenwert wird dann mehrmals
Nacheinander zum Ausgabewert, bis die Nachkommastellen einen Überlauf
haben.
Genau das ist das Grunkonzept der DDS!
gruß hans
Hallo,
ich dachte ich kann nur einen Zähler nutzen und dann auf den ermittelten
Index der Sinustabelle entsprechend draufrechnen (+1 = 2°, +2 = 4°...).
So dann entsprechend Rechenleistung einsparen.
Hans, ich kann dir leider nicht folgen. Muss ich dann z.B. für 50,05Hz
1
FCV=(uint32_t)(50050*4294967296*256/F_CPU)1000
;
rechnen ?
und lasse die ISR wie in meinem letzten Posting?
Wie bestimme bzw. berechne ich denn jetzt die kleinst mögliche
Schrittweite ?
Irgendwie muss ich ja jetzt herausfinden wie "kleinschrittig" ich im
Programm arbeiten kann.
Gruß
Ernst
hans wrote:
> Wenn die Grundfrequenz bei 50 Hz liegt, d.h. mit einem Additionswert> von 1 (jeder Tabellenwert nacheinander), ist mit der entsprechenden> Anzahl an Nachkommastellen für den Zähler und den Additionswert jede> Frequenz <50 Hz realisierbar. Der Tabellenwert wird dann mehrmals> Nacheinander zum Ausgabewert, bis die Nachkommastellen einen Überlauf> haben.> Genau das ist das Grunkonzept der DDS!
Wenn der Software Interrupt mit 50Hz kommt und den Phasenakkumulator
hochzählt, wie soll das dann gehen?
Software PLL? ;)
Und da sagte ich ja schon, dass genau das der Grund ist, warum AD9833
und Co. einen sehr hohen Takt bekommen.
Übrigens darfst du auch locker bleiben, immerhin ist das ein Forum, wo
jeder schreiben darf, wie er möchte.
Das Teilen durch die 65536 habe ich durch kürzen gemacht.
Du kannst auch mit einem Zähler arbeiten. Dann den Zähler nach der
Ausgabeberechnung für Signal 1 um den Phasenversatz erhöhen (Zähler
für 1 dabei nicht ändern), d.h. deine 32 Bit Variable + Phasenversatz
in 32 Bit berechnen und dann die vordersten 11 Bit für die
Tabellenadresse verwenden => Signal 2.
gruß hans
Hallo,
wie kommst du von meiner Formel für 50,05HZ auf
1
FCV=(uint32_t)((50.5*65536)*16777216/F_CPU)
?
Ziel ist es, eine Funktion zu schreiben die mir FCV ausrechnet.
Ich möchte der Funktion nur ein integer übergeben und weitestgehend die
Finger von Fließkomma lassen.
Deswegen hatte ich da an frequenz multipliziert mit 1000 gedacht, also
50,05Hz x 1000 = 50050.
Passt meine Formel von oben da nicht?
Bevor ich hier weiter mache. Kann mir jemand erläutern wie ich die
kleinst möglich Schrittgröße ermitteln kann?
Gruß
Ernst
@Simon
Die Tabellenadresse kann bei niedrigen Frequenzen in mehreren
Interruptaufrufen gleich bleiben, nur die Nachkommastellen
des Zählers ändern sich.
Da du bei deiner Aussage bleibst, bleibe ich auch bei meiner.
Es werden hier genug Frager mit Halbwissen verstört.
Sch...
es muß 50.05 heisen.
Deine zweite Version mit 1000 stimmt auch.
gruß hans