Forum: Mikrocontroller und Digitale Elektronik Audio MSP430


von Florian (Gast)


Lesenswert?

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.

von Rainer U. (r-u)


Lesenswert?

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 :-)

von Florian (Gast)


Lesenswert?

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?

von Florian (Gast)


Lesenswert?

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?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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?

von Florian (Gast)


Lesenswert?

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

von Noch einer (Gast)


Lesenswert?

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

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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.

von Clemens L. (c_l)


Lesenswert?

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
von Florian (Gast)


Lesenswert?

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!

von Noch einer (Gast)


Lesenswert?

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

von Florian (Gast)


Lesenswert?

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

von Planlos (Gast)


Lesenswert?

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 :)

von Rainer U. (r-u)


Lesenswert?

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.

von Florian (Gast)


Lesenswert?

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

von Rainer U. (r-u)


Lesenswert?

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.

von Florian (Gast)


Lesenswert?

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

von Rainer U. (r-u)


Lesenswert?

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.

von Florian (Gast)


Lesenswert?

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

von Florian (Gast)


Lesenswert?

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.

von Rainer U. (r-u)


Lesenswert?

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") ? :-)

von Die ? ? ? (Gast)


Lesenswert?

Kannst du bitte einmal erklären, wie das Ganze funktioniert? DAC, Timer, 
Interrupt, ..., Sinustabelle, ...

von Florian (Gast)


Lesenswert?

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.

von Die ? ? ? (Gast)


Lesenswert?

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.

von Florian (Gast)


Lesenswert?

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
}

von Florian (Gast)


Lesenswert?

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.

von Die ? ? ? (Gast)


Lesenswert?

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

von Florian (Gast)


Lesenswert?

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