Hallo, wie kann ich am geschickstesten eine DD Synthese in C Programmieren? Wie kann ich die Funktionswerte am besten abspeichern und dann ausgeben? Gruß Marc
DD Synthese =>DDS => direct digital synthesis....
Ringspeicher, mit einer Periode des gewünschten Signals. Dann zum Pointer, der darauf zeigt, immer das Tuning-Byte/Word dazuaddieren und den Wert an der entsprechenden Speicherstelle via DAC, PWM oder WDTW ausgeben. Aber da findet man echt viel im Netz dazu, ist ja auch nicht so schwierig; das sind etwa zwei Zeilen C-Code plus noch der Datensatz. Aber was ist eigentlich genau deine Frage?
@Ralf Schwarz: Du hast meine Frage eigentlich weitestgehend beantwortet. (Stichwort Pointer, Ringspeicher!) Dankeschön
OK habe nun die Daten im Array nun komm ich aber nicht weiter mit dem Zeiger auslesen. Ich dacht an so etwas: unsigned char iArray[251]; z = &iArray[0]; z++; z++; PORTD = *z; Geht das vom Prinzip her? Als was muss ich z deklarieren? Kann ich ein Byte einfach überspringen indem ich z++; schreibe oder wie macht man das?
>Als was muss ich z deklarieren?
1 | int8_t iArray[251]; |
2 | uint8_t *z = &iArray[0]; |
3 | |
4 | |
5 | //-- zyklisch aufrufen, zB im Timerinterrupt
|
6 | z += x; // x: Tuningbyte |
7 | if ( z > (sizeof(iArray)/sizeof(iArray[0]) ) |
8 | {
|
9 | z -= (sizeof(iArray)/sizeof(iArray[0]); |
10 | }
|
11 | PORTD = *z; |
>Byte einfach überspringen indem ich z++;
z++ geht nur zum Nächsten. Zum Überspringen musst du mindestens zwei
addieren, oder das tuningbyte x. Bei dem Tuningbyte ist allerdings der
Überlauf besonders zu beachten! Mein Beispiel ist da noch nicht
"bombenfest"
@ Matthias Lipinsky Nicht dein Tag heute? ;-) Das > if ( z > sizeof(iArray)/sizeof(iArray[0]) ) ist doch das selbe wie > if ( z > 251 ) und müsste, damit es keinen amoklaufenden Pointer gibt, zumindest so heissen > if ( z >= 251 ) damit nicht hinter das Array gegriffen wird. Leider ist es auch dann noch falsch, weil z ja irgendein Wert (Pointer) ist. Fast sicher ist z aber kein Wert zwischen 0 und 250... >int8_t iArray[251]; Warum nicht einfach eine Array-Größe von 256 definieren? Dann geht das mit dem Überlauf fast von alleine. So z.B.:
1 | int8_t iArray[256]; |
2 | uint8_t z; |
3 | // -- zyklisch aufrufen, zB im Timerinterrupt
|
4 | z += x; // x Tuningbyte |
5 | PORTD = iArray[z]; // z kann nie größer werden als das Array (0...255) |
Die Welt ist einfach und schön rund, wenn für binäre Prozessoren auch binär gedacht wird.
>Nicht dein Tag heute? ;-)
Sieht so aus..
Ich leg mich nochmal hin
Klasse hat geklappt. Vielen Dank! Das Array ging nur bis 251 weil ich zum testen nen Sinus ausgerechnet hab: for (l=0;l<251;l++) { x = (sin(0.025*l))*127.5 +127.5; iArray[l] = x; } (ab 252 ginge der x Wert über 127.5 und es würde einen Zacken geben. Die Kurve hat sowieso einen Zacken weiß auch nich warum aber zum testen isses OK, besser als 200 Werte von Hand auszurechnen^^) Hier meine Provisorische Lösung: signed char iArray[251]; unsigned char *z = &iArray[0]; unsigned char *save = &iArray[0]; z++; zaehler++; if (lol >251) { z = save; zaehler=0; } PORTB = *z; Eins noch: Was macht dieser Befehl: z += x; ?
>>Eins noch: Was macht dieser Befehl: z += x; ?
Das ist dasgleiche wie z = z+x; Das geht auch mit weiteren Operatoren.
Cheers
Detlef
Wie schon gesagt, (Matthias war schlecht aufgestanden :-) das > if (lol > 251) { geht schief, weil dein Array zwar 251 Elemente hat, aber die Indices für diese Elemente zwischen 0 und 250 liegen müssen. Du lässt aber einen Index von 251 noch ohne Überlauf durchgehen!! Korrekt müsste es so heissen: > if (lol >= 251) { Dann tauchen auch diese Zacken nicht mehr auf. Allerdings ist auch deine Berechnung etwas gewöhnungsbedürftig... So wäre sie vielleicht etwas besser durchschaubar:
1 | char iArray[256]; // sollte das nicht besser cArray heissen? |
2 | unsigend char w; |
3 | :
|
4 | for (w=0; w; w++) { // solange, bis w wieder 0 ist, also 256 mal |
5 | iArray[w] = (char)(sin(((float)w/256)*6.283185))*127.5 +127.5; |
6 | }
|
Alternativ auf dein 251 Elementiges Array
1 | char iArray[251]; // sollte das nicht besser cArray heissen? |
2 | unsigend char w; |
3 | :
|
4 | for (w=0; w<=250; w++) { |
5 | iArray[w] = (char)(sin(((float)w/251)*6.283185))*127.5 +127.5; |
6 | }
|
Ah da kommt dieser zacken her. (Das lol soll eigentlich zaehler heißen und cArray wäre sicher sinvoller). Ich muss sagen deine Berechnung von dem Array gefällt mir sehr. Is viel genauer als meine. Dankeschön!!!
Kaum zu glauben, dass die Schleife 256 mal durchlaufen wird. Ich würde eher sagen, gar nicht. Aber ich kann die gewollte Pfiffigkeit erkennen :-)
1 | char iArray[256]; // sollte das nicht besser cArray heissen? |
2 | unsigend char w; |
3 | for (w=0; w; w++) { // solange, bis w wieder 0 ist, also 256 mal |
4 | iArray[w] = (char)(sin(((float)w/256)*6.283185))*127.5 +127.5; |
5 | }
|
Um das Niveau dennoch hoch zu halten, spare ich mir die Korrektur.
@ Schwurbl > for (w=0; w; w++)... Gut, wenigstens einer merkt es ;-) > ...// solange, bis w wieder 0 ist, also 256 mal Die Funktionsweise ist im Kommentar doch klar beschrieben :) > Um das Niveau dennoch hoch zu halten, spare ich mir die Korrektur. Ganz in deinem Sinne...
Die Tabelle unbedingt 256 Bytes groß machen, spart die Abfrage nach >249. Der Phasenakkumulator muss doch viel breiter als der Pointer sein. #define hi 0 //je nach Endianess des Zielsystems union {t_int32 i32;t_int8 Byte[4]} ddsSum,ddsAdd; ddsSum.i32 += ddsAdd.i32; PORTB = iArray[ddsSum.Byte[hi]]; Evtl. löst der Compiler folgendes elegant: PORTB = iArray[(ddsSum.i32+=ddsAdd.i32)>>24]; Eine DDS ist in Assembler wesentlich eleganter. Beitrag "Re: atmega8, pwm, tongenerator ganz einfach" Ganzen Thread lesen. "poor man's dds"
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.