Hallo Community, ich bin neu hier und beschäftige mich seid ein paar Tagen mit Controllers. Genauer genommen mit den MSP430. Als Chip benutze ich den G2553. Da ich dieses Jahr meine Ausbildung als Informatiker anfing, hab ich mir ein kleines Projekt vorgenommen, um mein Feingefühl in der Welt der uController zu trainieren. Und zwar hatte ich vor, als erstes, eine .wav Datei auf einer SD-Karte abzuspeichern die ich dann mit dem uController verbinde. Das Audiosignal soll erstmal eine Mono Datei sein, sprich ein Kanal. Ich hab mich nun etwas eingelesen, wie ich das Signal ausgeben kann. Einmal mittels DAC und die weitere Möglichkeit wäre mittels PWM womit man einen Tiefpass vorher beschaltet. http://www.ti.com/lit/ug/tidu703/tidu703.pdf Okay, der G2553 beinhaltet keinen DAC, also benutze ich als erstes die PWM. Ich weiß nun, dass eine Sampling Rate von 8000 Hz ausreicht um 4000 Hz Mono Datei abzuspielen. Was ich mir noch im unklaren bin, ist das Thema mit der Auflösung. Zwar ist mir klar, dass ich mit 16-Bit 65.536 Werte speichern kann, aber wie gehe ich hantier ich damit. Und ist es egal ob ich 8-Bit benutze oder 16-Bit? Das ausrechnen der Bitrate soll auch kein Problem sein. Bei 1 Kanal x zB 16Bit x 8 kHz = 128 kBit/s Der erforderte Speicher für beispielsweise 5 Sekunden auf der SD-Karte wären dann doch: 128 kBit/s / 8 x 5 = 80 Byte Ist das so korrekt? Danke im voraus für jede Unterstützung.
Florian schrieb: > Ich weiß nun, dass eine Sampling Rate von 8000 Hz ausreicht um 4000 Hz > Mono Datei abzuspielen. > Was ich mir noch im unklaren bin, ist das Thema mit der Auflösung. Zwar > ist mir klar, dass ich mit 16-Bit 65.536 Werte speichern kann, aber wie > gehe ich hantier ich damit. > Und ist es egal ob ich 8-Bit benutze oder 16-Bit? Die Qualität bei 16 bit ist höher. Du gibst 8000 mal in der Sekunde einen neuen PWM-Wert vor (vorausgesetzt Deine PWM ist schnell genug). Den Wert kannst Du genauer (16Bit) oder nicht so genau (8Bit) einstellen. Florian schrieb: > Das ausrechnen der Bitrate soll auch kein Problem sein. Bei 1 Kanal x zB > 16Bit x 8 kHz = 128 kBit/s ja. bzw. 16kB (Kilobyte) / Sekunde Florian schrieb: > Der erforderte Speicher für beispielsweise 5 Sekunden auf der SD-Karte > wären dann doch: 128 kBit/s / 8 x 5 = 80 Byte > Ist das so korrekt? nein. Mach mal 'nen Überschlag mit dem Wert oben :-)
Guten Abend Rainer, vielen Dank für deine Antwort. Hab das jetzt mit der Auflösung soweit verstanden. Rainer U. schrieb: >> Der erforderte Speicher für beispielsweise 5 Sekunden auf der SD-Karte >> wären dann doch: 128 kBit/s / 8 x 5 = 80 Byte >> Ist das so korrekt? > > nein. Mach mal 'nen Überschlag mit dem Wert oben :-) Ach total vertan, hab das kilo vergessen, bedeutet es wären dann 80.000 Byte. Ich hab eine erklärung gefunden wie man umgeht, wenn man den Speicher ausrechnen möchte miteinbezogen dem Takt der CPU und der PWM. Bleiben wir bei dem Beispiel mit den 5 Sekunden Audiodatei. Bei einer CPU Frequenz von 16 MHz, einer gewählten Auflösung von 16-Bit bekäme ich eine PWM Frequenz von 16 Mhz / 2^16 = 244 Hz und wenn ich das nun durch 2 teilen müsste, wegen dem Nyquist-Theorem, bekäme ich dann eine hörbare Frequenz von 122 Hz?! So und diese dann noch mal der 5 Sekunden, bekäme ich 610 Byte. Das scheint mir aber sehr wenig zu sein. Kann das soweit stimmen, oder hab ich wieder ein blöden Fehler gemacht?
Hallo, hab da noch eine Frage. Wenn ich statt PWM die DAC benutze und mittels DMA die Daten vom Flash raushole und dem DAC übergebe, brauch ich da unbedingt eine samplingrate? Im Datasheet bspw. von dem msp430f2619 finde ich unter dem Kapitel DAC nichts zu einer conversion time, wie es der Fall bei dem ADC ist. Und noch eine Frage bezüglich des Arrays, wie groß muss das Array mind. sein wenn ich eine .wav Datei da ablegen möchte?
Florian schrieb: > brauch ich da unbedingt eine samplingrate Natürlich. Das ist die Geschwindigkeit, mit der die Daten dem D/A-Wandler übergeben werden. > wie groß muss das Array mind. sein wenn ich eine .wav Datei da ablegen > möchte? Wie groß ist eine .wav-Datei?
Rufus Τ. F. schrieb: > Florian schrieb: >> brauch ich da unbedingt eine samplingrate > > Natürlich. Das ist die Geschwindigkeit, mit der die Daten dem > D/A-Wandler übergeben werden. Hallo Rufus, danke für die Antwort. Wenn ich einen Blick in das Datasheet von dem msp430f2619 werfe, finde ich aber in den Tabellen nichts dazu. Kannst du mir einen Tipp geben, wo ich das finde? Rufus Τ. F. schrieb: > Wie groß ist eine .wav-Datei? Nun ja, wie oben schon ausgerechnet mit den gleichen Parameter, müsste dass dann bei 5 Sekunden .wav Datei einer Größe von 80 kByte sein. Aber was hat das dann mit der Rechnung mit der PWM zutun? Wo ich weiter oben eine Größe von 610 Byte herausbekomme. Bin für jeden Tipp und Ratschlag sehr dankbar
> eine hörbare Frequenz von 122 Hz?! ... bekäme ich 610 Byte
16 Bit Auflösung gehen schlicht und einfach nicht mit deiner PWM.
Du musst umgekehrt rechnen. Du nimmst die PWM Frequenz und die
gewünschte Audiofrequenz. Berechnest damit die mögliche Auflösung. Da
werden so 12 Bit herauskommen.
Nächstes Problem. Dein MC muss die Daten von der Karte holen, in 12 Bit
verschieben und die PWM-Register rechtzeitig füllen. Klappt nur, wenn du
die Interrupts geschickt nutzt und auf den Overhead sauberer
Programmierung verzichtest.
Florian schrieb: > Wenn ich einen Blick in das Datasheet von dem msp430f2619 werfe, finde > ich aber in den Tabellen nichts dazu. Wie soll das auch im Datenblatt stehen? Die Samplerate ist die Abspielgeschwindigkeit Deiner Audiodaten, und hängt von Dir bzw. dem die Audiodaten erstellenden Programm ab. Wenn das beispielsweise CD-Audio ist, beträgt die Samplerate 44.1 kHz. Du musst dann dafür sorgen, daß mit diesem Takt die Daten an den DAC übergeben werden. Der DAC im 'F2619 ist dafür schnell genug, wenngleich er mit seinen 12 Bit Auflösung eher nicht für Audiozwecke geeignet ist. Was aber hat das mit PWM zu tun? Wenn Du einen DAC verwendest, gibt es keine PWM; die PWM ist ein Trick, einen DAC nachzuahmen. Wenn Du aber einen hast (wie im 'F2619), dann musst Du keinen nachahmen. Du solltest Dir vielleicht nochmal genau überlegen, was Du eigentlich erreichen willst -- und womit.
Florian schrieb: > Rufus Τ. F. schrieb: >> Florian schrieb: >>> brauch ich da unbedingt eine samplingrate >> >> Natürlich. Das ist die Geschwindigkeit, mit der die Daten dem >> D/A-Wandler übergeben werden. > > Hallo Rufus, danke für die Antwort. Wenn ich einen Blick in das > Datasheet von dem msp430f2619 werfe, finde ich aber in den Tabellen > nichts dazu. Der F2619 hat R2R-DACs. Die arbeiten theoretisch unendlich schnell, allerdings haben die Eingangs- und Ausgangs-Puffer Grenzen (siehe "settling time" und "slew rate" im Datenblatt), die du mit den DAC12AMP-Bits auch anpassen kannst.
:
Bearbeitet durch User
Danke für die Antworten Leute. Noch einer schrieb: > Du musst umgekehrt rechnen. Du nimmst die PWM Frequenz und die > gewünschte Audiofrequenz. Berechnest damit die mögliche Auflösung. Da > werden so 12 Bit herauskommen. Ich hab das mal umgekehrt gerechnet, wie du mir das empfohlen hast. Zum Verständnis: Die maximale PWM Frequenz ist ja die max. Clock Frequenz (hier wenn man den DCO verwendet wären das 16 MHz) geteilt durch 2, entspricht 8 MHz. Diese 8 MHz teile ich nun durch meine gewünschte Audiofrequenz (ich nehm mal die max. Hörbare Frequenz, dass wären 20 kHz) multipliziere das mit 2, wegen dem Gesetz nach Shannon für die Abtastrate und bekomme 40 kHz heraus. Teile ich nun 8 MHz / 40 kHz bekomme ich = 200 dann zieh ich mittels logarithmus duales den exponenten und erhalte 7,6 Bit. Rufus Τ. F. schrieb: > Was aber hat das mit PWM zu tun? Wenn Du einen DAC verwendest, gibt es > keine PWM; die PWM ist ein Trick, einen DAC nachzuahmen. Wenn Du aber > einen hast (wie im 'F2619), dann musst Du keinen nachahmen. > > Du solltest Dir vielleicht nochmal genau überlegen, was Du eigentlich > erreichen willst -- und womit. Danke für den Tipp. Mein Vorhaben war, ehe ich mir einen neuen MCU kaufe, ich erstmal mittels PWM schauen bzw. hören wollte, wie die Qualität des zu wiedergebenen Audio ist. Clemens L. schrieb: > Der F2619 hat R2R-DACs. Die arbeiten theoretisch unendlich schnell, > allerdings haben die Eingangs- und Ausgangs-Puffer Grenzen (siehe > "settling time" und "slew rate" im Datenblatt), die du mit den > DAC12AMP-Bits auch anpassen kannst. Danke, werde ich mir behalten!
> Teile ich nun 8 MHz / 40 kHz
Anfangs warst du noch der Meinung, 4 kHz reichen dir. Und die Player mit
PWM haben alle Tiefpassfilter mit 3-4 KHz.
10-12 Bit und 4-8 kHz wird da als bester Kompromiss angesehen. Mehr
Qualität geht mit Mikrocontroller PWM nicht.
@noch einer Danke nochmals für deine Antwort. Vor ein paar Tagen bekam ich nun einen MSP mit integrierten DAC ausgeliehen. Ich habe auch soweit erfolgreich ein Summen mittels Array bzw. Schleife wiedergeben können. Da ich aber nun unterschiedliche Frequenzen wiedergeben muss, um eine gescheite Melodie zu hören, bedarf es mehr Hintergrundwissen. Das Internet habe ich auch schon nun seid paar Tagen durchfostert finde aber keine nützlcihe Literatur die schritt-für-schritt erklärt wie man mittels array verschiedene Melodien ausgibt. Hier wollte ich mich nun an euch wieder wenden, ob ihr evtl ein paar nützlcihe LINKs kennt, auf denen ich noch nicht gestoßen bin.
Sowas geht ohne SD-Karte, mit nur 8 MHz (avr), R2R-DAC: http://m.youtube.com/watch?v=_uU4BzSQQmY http://www.linusakesson.net/hardware/chiptune.php Sourcecode ist dabei, vielleicht inspiriert er dich :)
Florian schrieb: > Das > Internet habe ich auch schon nun seid paar Tagen durchfostert finde aber > keine nützlcihe Literatur die schritt-für-schritt erklärt wie man > mittels array verschiedene Melodien ausgibt. Schritt 1) lade Deine Daten in das Array (am einfachsten eine WAV-Datei) Schritt 2) lies das Array in einer Schleife aus und gib die Werte an den DAC Schritt 3) für eine andere Melodie, wiederhole Schritt 1 und 2 Zu welchem Schritt hast Du fragen und welche? Ich rate mal: Schritt 1 Lies in Wikipedia nach, wie eine wav-Datei aufgebaut ist. Lies auch über MP3 und erkenne den erheblichen Zusatzaufwand zum decodieren.
@Planlos: Ja danke für die Internetseite. Rainer U. schrieb: > Schritt 1) lade Deine Daten in das Array (am einfachsten eine WAV-Datei) > Schritt 2) lies das Array in einer Schleife aus und gib die Werte an den > DAC Hallo Rainer, vielen Dank für die Hilfe. Das hab ich schon getan kam leider nur unsinn heraus. Hab dann nachdem ich hier wieder reingeschrieben habe, weiter das Internet und das Forum hier durchforstet und stieß dann auf einen älteren Thread wo jemand das gleiche mal vorhatte. Werde von dort den Lösungsvorschlag mal ausprobieren, hoffe das es dann klappt. Was ich bis jetzt habe ist das hier:
1 | #include <msp430f1611.h> |
2 | |
3 | |
4 | // note periode frequency
|
5 | #define c 3830 //261Hz 0.
|
6 | #define d 3400 //294Hz 1.
|
7 | #define e 3038 //329Hz 2.
|
8 | #define f 2864 //349Hz 3.
|
9 | #define g 2550 //392Hz 4.
|
10 | #define a 2272 //440Hz 5.
|
11 | #define h 2028 //493Hz 6.
|
12 | #define C 1912 //523Hz 7.
|
13 | |
14 | |
15 | //Rest
|
16 | #define R 0 // 8.
|
17 | |
18 | |
19 | // Funktions-Prototypen
|
20 | void setup(); |
21 | void delay(unsigned int m_sec); |
22 | |
23 | |
24 | // globale Variablen
|
25 | unsigned int i = 0, y=0, z=0; |
26 | |
27 | int thisNote = 0; |
28 | |
29 | |
30 | // globale Arrays
|
31 | int melody[]={c,d,e,f,g,g,a,a,a,g,a,a,a,g,f,f,f,f,e,e,d,d,d,d,c,R}; |
32 | |
33 | int noteDurations[] = {4,8,8,4,4,4,4,4,8,8,8,8,8,8,4,4,4,4,8,8,4,4,4,4,8}; |
34 | |
35 | |
36 | // alle meine Entchen: c d e f g g a a a g a a a g f f f f e e d d d d c
|
37 | |
38 | |
39 | |
40 | |
41 | // Hauptprogramm
|
42 | int main(void) |
43 | {
|
44 | WDTCTL = WDTPW + WDTHOLD; |
45 | |
46 | ADC12CTL0 = REF2_5V + REFON; // interne Referenzspannung auf 2,5V |
47 | DAC12_0CTL = DAC12IR + DAC12AMP_7 + DAC12ENC; // DAC12 initialisieren |
48 | |
49 | // Clock einstellen
|
50 | BCSCTL1 &= ~XT2OFF; // Quarz mit 8 MHz |
51 | do
|
52 | {
|
53 | IFG1 &= ~OFIFG; |
54 | for(z= 0xFFF; i > 0; i--) {}; //warte 512 us |
55 | }
|
56 | |
57 | while((IFG1 & OFIFG) != 0); // bis Oszillator eingeschwungen |
58 | |
59 | BCSCTL1 |= XTS; |
60 | |
61 | // für MCLK: Wähle XT2 und Teiler 8
|
62 | // für SMCLK: Wähle XT2 und Teiler 8
|
63 | BCSCTL2 |= SELM_2 + DIVM_3 + SELS + DIVS_3; |
64 | |
65 | |
66 | while(1) |
67 | {
|
68 | setup(); |
69 | |
70 | thisNote = 0; |
71 | |
72 | delay(1000); |
73 | }
|
74 | }
|
75 | |
76 | |
77 | |
78 | void tone(unsigned int Note, unsigned int Duration) |
79 | {
|
80 | DAC12_0DAT = Note*Duration; |
81 | }
|
82 | |
83 | |
84 | |
85 | void setup() |
86 | {
|
87 | for (thisNote = 0; thisNote < 7; thisNote++) |
88 | {
|
89 | int noteDuration = 1000/noteDurations[thisNote]; |
90 | |
91 | |
92 | |
93 | tone (melody[thisNote], noteDuration); |
94 | |
95 | |
96 | |
97 | int pauseBetweenNotes = noteDuration * 1.30; |
98 | |
99 | delay(pauseBetweenNotes); |
100 | }
|
101 | |
102 | }
|
103 | |
104 | |
105 | |
106 | void delay(unsigned int m_sec) |
107 | {
|
108 | while(m_sec--) |
109 | {
|
110 | __delay_cycles(800); |
111 | }
|
112 | }
|
Die Clock und die delay Funktion sind noch nciht richtig eingestellt, dass muss ich noch machen. Und die Noten länge, habe ich erstmal willkürlich gewählt.
Ach so, Du willst Töne einer Tonleiter ausgeben.. Das hat oben nicht so ausgesehen. Bei Deiner Melodie fehlen 2x "a" :-) Mach Dir eine "Note" für die Pause, dann kannst Du Töne und Pausen gleich behandeln und zwischen 2 Tönen eine Pause machen oder auch nicht. Dann bau Dir erstmal eine Funktion, die einen Notenwert als Argument akzeptiert und diesen ausgibt. Evtl. reicht es Dir schon, wenn Du den Port langsamer oder schneller ein- und ausschaltest. Also prinzipiell wenn Du 2 Timer hast: einen Timer(1) stellst Du mit der Notenlänge, einen zweiten (2) mit der Periodendauer. In der ISR on Timer2 schaltest Du den Ausgabepin um, in der ISR vom Timer1 steuerst Du, wie lang der Ton sein soll und machst ihn dann irgendwann aus. Damit bekommst Du "Rechteck-Töne", wenn Du das beherrscht, fällt Dir alles weitere leichter.
@Rainer:
Danke für den Tipp den werde ich gleich mal ausprobieren.
Rainer U.:
> Ach so, Du willst Töne einer Tonleiter ausgeben..
Naja fürs erste, da mein ersteres Vorhaben, in einem Array den Hexcode
speichern und dann per DAC ausgeben, nicht funktioniert hat und ich dann
den Tipp nachgehen wollte.
Mein erstes Ziel liegt noch darin, dass ich eine beliebe WAV Audio Datei
mittels Programm in Hexadezimal umwandel, und das wiedergebe.
Florian schrieb: > dass ich eine beliebe WAV Audio Datei > mittels Programm in Hexadezimal umwandel Die Werte stehen da schon "hexadezimal" drin und müssen gar nicht umgewandelt werden - das ist das einfache an einer WAV-Datei.
@Rainer: Ich hab das jetzt nicht so ganz gemacht wie du es mir geschildert hast, funktioniert aber, auch wenn die Melodie etwas zu schnell abgespielt wird. Und zwar dauert eine Melodie ca. 75ms, statt den gewünschten 15sek. Kommt aber noch! Hier mein Code bisher. Die Notenlänge hab ich noch nicht implementiert.
1 | #include <msp430f1611.h> |
2 | |
3 | |
4 | |
5 | |
6 | //#define c 261 // 0.
|
7 | //#define d 294 // 1.
|
8 | //#define e 329 // 2.
|
9 | //#define f 349 // 3.
|
10 | //#define g 391 // 4.
|
11 | //#define a 440 // 5.
|
12 | |
13 | |
14 | // Werte für das CCR0 Register
|
15 | // Formel: CCR0 = Clock (8MHz) / anzahl Array (200) * gew. Frequenz
|
16 | |
17 | #define a 91 // 0. Herz: 440
|
18 | #define c 153 // 1. Herz: 261
|
19 | #define d 136 // 2. Herz: 294
|
20 | #define e 122 // 3. Herz: 329
|
21 | #define f 115 // 4. Herz: 349
|
22 | #define g 102 // 5. Herz: 391
|
23 | |
24 | |
25 | //Rest
|
26 | #define R 0 // 6.
|
27 | |
28 | |
29 | // globale Variable
|
30 | int dieseNote = 0; |
31 | int z=0; |
32 | |
33 | |
34 | |
35 | // Funktions-Prototypen
|
36 | void setup(); |
37 | void delay(unsigned int m_sec); |
38 | |
39 | |
40 | // globale Arrays -- alle meine Entchen:
|
41 | int melody[] = {c,d,e,f,g,g,a,a,a,g,a,a,a,g,f,f,f,f,e,e,d,d,d,d,c}; |
42 | short interval[] = {8,8,8,8,8,8,8,4,8,8,8,4,4,4,8,8,8,8,8,4,4,8,8,8,8}; |
43 | |
44 | //Sinus table values
|
45 | int sin_vector[] = {2048, 2112, 2177, 2241, 2305, 2368, 2432, 2495, 2557, 2619, |
46 | 2681, 2741, 2802, 2861, 2920, 2977, 3034, 3090, 3145, 3199, 3251, 3303, 3353, 3402, |
47 | 3449, 3495, 3540, 3583, 3625, 3665, 3704, 3741, 3776, 3810, 3842, 3872, 3900, 3927, |
48 | 3951, 3974, 3995, 4014, 4031, 4046, 4059, 4070, 4079, 4086, 4091, 4094, 4095, 4094, |
49 | 4091, 4086, 4079, 4070, 4059, 4046, 4031, 4014, 3995, 3974, 3951, 3927, 3900, 3872, |
50 | 3842, 3810, 3776, 3741, 3704, 3665, 3625, 3583, 3540, 3495, 3449, 3402, 3353, 3303, |
51 | 3251, 3199, 3145, 3090, 3034, 2977, 2920, 2861, 2802, 2741, 2681, 2619, 2557, 2495, |
52 | 2432, 2368, 2305, 2241, 2177, 2112, 2048, 1984, 1919, 1855, 1791, 1728, 1664, 1601, |
53 | 1539, 1477, 1415, 1355, 1294, 1235, 1176, 1119, 1062, 1006, 951, 897, 845, 793, 743, |
54 | 694, 647, 601, 556, 513, 471, 431, 392, 355, 320, 286, 254, 224, 196, 169, 145, 122, |
55 | 101, 82, 65, 50, 37, 26, 17, 10, 5, 2, 1, 2, 5, 10, 17, 26, 37, 50, 65, 82, 101, |
56 | 122, 145, 169, 196, 224, 254, 286, 320, 355, 392, 431, 471, 513, 556, 601, 647, 694, |
57 | 743, 793, 845, 897, 951, 1006, 1062, 1119, 1176, 1235, 1294, 1355, 1415, 1477, 1539, |
58 | 1601, 1664, 1728, 1791, 1855, 1919, 1984}; |
59 | |
60 | |
61 | |
62 | int laenge_melody = (sizeof(melody) / sizeof(int)); |
63 | int laenge_array = (sizeof(sin_vector) / sizeof(int)); |
64 | |
65 | |
66 | |
67 | //------------- Interrupt ---------------------
|
68 | #pragma vector = TIMER0_A0_VECTOR
|
69 | __interrupt void TIMERA0(void) |
70 | {
|
71 | DAC12_0DAT = sin_vector[z]; |
72 | |
73 | |
74 | if(z<(sizeof(sin_vector) / sizeof(int))) |
75 | {
|
76 | z++; |
77 | }
|
78 | else
|
79 | {
|
80 | z=0; |
81 | |
82 | dieseNote++; |
83 | |
84 | setup(); |
85 | }
|
86 | |
87 | |
88 | TACTL &= ~TAIFG; |
89 | }
|
90 | |
91 | |
92 | |
93 | //------------------------------ main -------------------------------------------
|
94 | int main( void ) |
95 | {
|
96 | // Stop watchdog timer to prevent time out reset
|
97 | WDTCTL = WDTPW + WDTHOLD; |
98 | |
99 | |
100 | //--------------- DAC einstellen --------------------
|
101 | ADC12CTL0 = REF2_5V + REFON; // interne Referenzspannung auf 2,5V |
102 | DAC12_0CTL = DAC12SREF_0 + DAC12IR + DAC12AMP_7 + DAC12ENC; // DAC12 initialisieren |
103 | //---------------------------------------------------
|
104 | |
105 | //--------------- Clock einstellen --------------------
|
106 | BCSCTL1 &= ~XT2OFF; // XT2 aktivieren |
107 | |
108 | do
|
109 | {
|
110 | IFG1 &= ~OFIFG; // Oscillator-Fault-Flag löschen |
111 | for(int warte = 0xFF; warte > 0; warte--); // warte 50 us |
112 | }
|
113 | while((IFG1 & OFIFG) != 0); // bis Oszillator eingeschwungen |
114 | |
115 | |
116 | // für MCLK: Wähle XT2 und Teiler 1
|
117 | // für SMCLK: Wähle XT2 bzw. XT1 und Teiler 1
|
118 | BCSCTL2 |= SELM_2 + DIVM_0 + SELS + DIVS_0; |
119 | //------------------------------------------------------
|
120 | |
121 | setup(); |
122 | |
123 | //---------------- Timer konfig ------------------------
|
124 | TACTL |= TACLR; |
125 | |
126 | TACCTL0 = CCIE; // Cap/Comp-Interrupt aktivieren |
127 | |
128 | TACTL |= TASSEL_2 + MC_1 + ID_0; // wähle SMCLK, DIV=1, Upmode |
129 | |
130 | TACTL |= TAIE; |
131 | //------------------------------------------------------
|
132 | |
133 | |
134 | __enable_interrupt(); |
135 | |
136 | |
137 | _BIS_SR(OSCOFF); // schalte DCO aus |
138 | |
139 | |
140 | |
141 | while(1) |
142 | {
|
143 | |
144 | }
|
145 | |
146 | }
|
147 | //-------------------------------------------------------------------------------
|
148 | |
149 | |
150 | //-------- unter Funktionen ----------
|
151 | |
152 | // alle meine Entchen: c d e f g g a a a g a a a g f f f f e e d d d d c
|
153 | |
154 | |
155 | void setup(void) |
156 | {
|
157 | if(dieseNote < laenge_melody) |
158 | {
|
159 | switch(melody[dieseNote]) |
160 | {
|
161 | case a: TACCR0 = a; break; |
162 | case c: TACCR0 = c; break; |
163 | case d: TACCR0 = d; break; |
164 | case e: TACCR0 = e; break; |
165 | case f: TACCR0 = f; break; |
166 | case g: TACCR0 = g; break; |
167 | |
168 | default: TACCR0 = R; break; |
169 | }
|
170 | }
|
171 | else
|
172 | {
|
173 | dieseNote = 0; |
174 | delay(10); |
175 | }
|
176 | }
|
177 | |
178 | |
179 | void delay(unsigned int m_sec) |
180 | {
|
181 | while(m_sec--) |
182 | {
|
183 | __delay_cycles(8000); // 1000 for 1MHz |
184 | }
|
185 | }
|
Ich hab statt ein Rechteck, einen Sinus benutzt den ich wie man sieht in einem Array abgelegt habe. Bin für Jedermann's Vorschläge dankbar, wie ich nun sinnvollerweise die Notenlänge programmiere, damit da auch was vernünftiges heraus kommt.
Ok habs hinbekommen, endlich höre ich was gescheites! Hab einfach den zweiten array mit eingebunden, damit ich pro Note nicht nur eine Periode bekomme, sondern bezüglich der Notenlänge X-viele Perioden ich ausgebe. Wenn jemand weitere Anregungen hat, wie man den letzten Schritt evtl eleganter gestaltet hätte bzw. andere Stellen, bin ich für jeden Dankbar.
Florian schrieb: > Ok habs hinbekommen, endlich höre ich was gescheites! Na fein! Der Rhythmus sieht etwas schräg für mich aus, und der Text hat Migrationshintergrund? ("Alle Meine Entchen schwimmem auf See") ? :-)
Kannst du bitte einmal erklären, wie das Ganze funktioniert? DAC, Timer, Interrupt, ..., Sinustabelle, ...
Rainer U. schrieb: > Der Rhythmus sieht etwas schräg für mich aus, und der Text hat > Migrationshintergrund? ("Alle Meine Entchen schwimmem auf See") ? :-) Danke Rainer, hab ich verbessert :) Nach einer längeren Pause, da ich noch an anderen Sachen beschäftigt war, wollte ich ab heute weiter machen. So mein Vorhaben ist nun der, dass ich gern eine wav Datei die ich vorher in Hex umgewandelt habe, abzuspielen. Hab mich auch ein bisschen über die Struktur des wave Dateiformat eingelesen. Und ich mein Rainer du hast mir ja schon geschildert, dass es kein großer Akt ist, eine wav Datei abzuspielen. Einfach die Werte in ein Array speichern und per DAC ausgeben. Die ? ? ? schrieb: > Kannst du bitte einmal erklären, wie das Ganze funktioniert? DAC, Timer, > Interrupt, ..., Sinustabelle, ... Nun ja, ich gebe dank Interrupt die Freq aus, die gerade im Array(melody) dran ist. Und das geschiet mittels eines Sinus, den ich aus dem Array abspiele. Da aber der Sinus nicht nur einmal durchlaufen wird, sonst wäre ja der Ton paar ms lang, habe ich die Notenperiode mit eingefügt. Im Array 'interval'. So und da schaut das Programm, wie oft nun Sinuse abgespielt werden sollen! Das Herzstück ist natürlich der Timer. Der definiert, wie schnell das Prog in das Interrupt reinspringt. Und das wie oft der reinspringt, ist abhängig von der jeweiligen Freq, die gerade dran ist.
Florian schrieb: > Nun ja, ich ... habe nicht das programmiert, was ich beschrieben habe. In der Timer ISR wird immer eine vollständige Periode durchlaufen. Dann wird die nächste Frequenz eingestellt, wieder für eine Periode, usw. Deine Töne sind alle unter 500Hz. Was für ein Audio Stück soll das werden? Mein Tipp: 1. Töne von 1kHz bis mind. 7kHz auswählen 2. Sinustabelle verkleinern 3. Tastung (Timer Intervall) an höchsten Ton anpassen 4. Notenlänge berücksichtigen. Immer als vielfaches der aktuellen Periode/2.
Die ? ? ? schrieb: > habe nicht das programmiert, was ich beschrieben habe. Jain. Ich hab nachdem ich den Beitrag mit dem Code gepostet habe, geschrieben, dass ich es danach hinbekommen habe. Und im neuen Code habe ich das Array 'Interval', was einfach so da steht berücksichtigt. Meine Beschreibung belief sich auf die neueste Version meines Programms. Die ? ? ? schrieb: > In der Timer ISR wird immer eine vollständige Periode durchlaufen. Dann > wird die nächste Frequenz eingestellt, wieder für eine Periode, usw. Das stimmt, halt für die Version des Programmcodes den ich da gepostet habe. Die ? ? ? schrieb: > Deine Töne sind alle unter 500Hz. Was für ein Audio Stück soll das > werden? Ich wollte Beispielsweise 'Alle meine Entchen' spielen. Und da hab ich halt die Noten im Internet für die Melodie gefunden. Gesucht, welche Frequenzen die Noten ergeben und dann im Programm übernommen. Die ? ? ? schrieb: > Mein Tipp: > 1. Töne von 1kHz bis mind. 7kHz auswählen Kannst du mir den Schritt etwas genauer erklären, wieso das sinnvoller ist? Die ? ? ? schrieb: > 2. Sinustabelle verkleinern Ich hab geplant, einen viertelsinus zu implementieren, dass ist noch besser als Werte vom Array zu lesen. Die ? ? ? schrieb: > 4. Notenlänge berücksichtigen. Immer als vielfaches der aktuellen > Periode/2. Meinst du hier mit Periode/2 eine achtelperiode? Wie die in dem Array 'interval' zu finden ist? Das hab ich dann in der neuen Version, wenn ich dich so verstanden habe, schon eingebaut. So sieht meine neue Unterfunktion 'setup' aus:
1 | void setup(void) |
2 | {
|
3 | if(dieseNote < laenge_melody) |
4 | {
|
5 | TACCR0 = (unsigned long int)(8000000 / ((double)laenge_array * (double)melody[dieseNote])); |
6 | |
7 | switch(interval[dieseInterval]) |
8 | {
|
9 | case 4: anzahl = melody[dieseNote]; break; |
10 | case 8: anzahl = (int)((double)melody[dieseNote] / 2); break; |
11 | |
12 | default: anzahl = 10; break; |
13 | }
|
14 | }
|
15 | else
|
16 | {
|
17 | dieseNote = 0; |
18 | dieseInterval = 0; |
19 | delay(200); |
20 | }
|
21 | }
|
Ich hab nun mittels eines wav to c converter, ein sehr großes Array erstellt. Ein Teil des Arrays in meinem Programm kopiert, dass widerum die einzelnen Werte ans DAC übermittelt. Hab die .wav Datei auf 8000Hz Sampling Rate und 8Bit Auflösung mittels Audacity gewandelt. Hab ebenfalls im Programm den Timer so eingestellt, dass er nach 125us - was 8000Hz entspricht - in die ISR reinspringt und von dort einen Wert im Array an den DAC weiter gibt. Das Programm ist sehr simpel und hat keine Sinusfunktion, wie das Programm davor. Meine Frage nun, wie berückstichtige ich die 8Bit Auflösung bzw. allgemein die Auflösung einer Musikdatei, wenn ich mit uC programmiere wo ich Audiodateien ausgeben möchte. Und ist das Vorgehen so richtig, was ich bis jetzt geschildert habe? Leider kann ich noch nicht viel hören, da der Flash-Speicher einfach zu klein auf dem uC ist. Mein nächstes Vorhaben wird sein, eine SD-Karte dran zu schließen.
Du musst dich mal entscheiden, was du willst. Erst hast du einzelne Noten hintereinander gehängt und jetzt geht es mehrfach überlagerte Töne (nix mehr einfacher Sinus).
Die ? ? ? schrieb: > Du musst dich mal entscheiden, was du willst. Erst hast du einzelne > Noten hintereinander gehängt und jetzt geht es mehrfach überlagerte Töne > (nix mehr einfacher Sinus). Hi, danke für deine einzelnen Beiträge. Entschieden habe ich mich schon. Und zwar habe ich ja in meinem allerersten Beitrag ja geschrieben, dass ich gern eine .wav Datei ausgeben möchte. Da mir aber noch das Wissen zu fehlte, wie ich mit Sampling Rate, Auflösung und generell mit Frequenzen arbeite, wurde mir hier im Forum empfohlen, Töne anhand einer Notentabelle mittels einer Sinustabelle auszugeben. Und die Idee gefiel mir halt, dass ich dies auch tat.
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.