Hallo Leute,
ich bin durch Zufall über dieses Forum gestolpert und dachte mir,
vielleicht könnt ihr mir helfen.
Ich habe mir vor kurzem einen LPC2368 von der Firma NXP besorgt. Nun
wollte ich wissen, wie man über den schon integrierten Lautsprecher eine
Melodie ausgeben kann. Ich habe ein bisschen im Internet gesucht und
herausgefunden, dass man die Noten vordefiniert (mit ihrer Frequenz) und
dann in ein Array die Noten abspeichert und die dann ausgibt. Aber um
das digitale in ein analoges Signal umzuwandeln, damit es auch gehört
werden kann, muss man ja den D/A Wandler benutzen. Ich habe im
Datenblatt danach gesucht und rausgefunden, dass er nur ein Register
hat. Soweit so gut. Aber mein Problem jetzt, ist die Verständnis wie der
D/A Wandler genau funktioniert. Sprich, braucht der von extern einen
Timer, der ihn taktet, usw.
Wäre über eure Hilfe sehr dankbar.
LG
Jimin M. schrieb:> Hallo Leute,>> ich bin durch Zufall über dieses Forum gestolpert und dachte mir,> vielleicht könnt ihr mir helfen.> Ich habe mir vor kurzem einen LPC2368 von der Firma NXP besorgt. Nun> wollte ich wissen, wie man über den schon integrierten Lautsprecher
wie ist der Lautsprecher ins System integriert?
Hängt der bereits am D/A Wandler oder ist der an einem Output Pin
angeschlossen?
Wenn der nur an einem Pin angeschlossen ist:
du hast schon ein 'analoges' Signal. Wenn auch nur mit 2 verschiedenen
Spannungen. WEnn du an den Portpin eine 1 ausgibt, dann schnellt die
Lautsprecher Membran nach vorne, wenn du an den Portpin eine 0 ausgibst,
dann geht die Lautsprechermembran nach hinten. Das reicht dann schon.
Effektiv kannst du damit nur Rechteckschwingungen erzeugen, die einen
etwas eigenartigen Klang haben, aber soviel schöner ist eine reine
Sinusschwingung dann auch wieder nicht.
Also: nicht künsteln, einfach machen. Um den Kammerton 'a' auszugeben,
brauchst du 440Hz, musst also den Pin an dem der Lautsprecher hängt 880
mal in der Sekunde umschalten. Dann hörst du auch was.
> Aber mein Problem jetzt, ist die Verständnis wie der D/A Wandler genau
funktioniert.
Du schreibst einen Zahlenwert ins Register und am Ausgang des D/A
Wandlers kommt die entsprechende Spannung raus. Wenn du eine sich
verändernde Spannung haben willst (wie sie zb bei einer Schwingung
notwendig ist), dann muss eben dein Programm den D/A Wandler im
entsprechenden Takt mit jeweils neuen Werten versorgen.
Jimin M. schrieb:> einen LPC2368 von der Firma NXP besorgt. Nun> wollte ich wissen, wie man über den schon integrierten Lautsprecher
Ein LPC mit integrierten Lautsprecher??
@Karl Heinz
Danke für die Hilfe. Also der Lautsprecher hängt schon am D/A Wandler so
wie ich es anhand der Schematic entnehmen konnte. Man müsste jetzt den
Pin als D/A Wandler aktivieren.
Kann ich fragen, wie du auf den Wert 880 kommst, wenn der "a" Ton 440Hz
beträgt? Verdoppelst du dann einfach den Wert? Und wie kann ich das dann
so oft umschalten? Weil im Register habe ich zwar "settling time"
gelesen, aber ich habe nicht wirklich verstanden, wo ich diese Zeit denn
nun eintragen könnte.
@Markus W.
Ja der Lautsprecher ist auf dem Board schon vorhanden, ist aber eher,
denke ich zumindest, sowas wie ein Summer. Also recht klein und ich
denke auch ziemlich schlechte Qualität. Aber fürs erste zum
rumprobieren, denke ich, dass es langt :)
Jimin M. schrieb:> @Karl Heinz> Danke für die Hilfe. Also der Lautsprecher hängt schon am D/A Wandler so> wie ich es anhand der Schematic entnehmen konnte.
Das musst du wissen.
Hier weiß ja keiner, welches Board du benutzt.
> Kann ich fragen, wie du auf den Wert 880 kommst, wenn der "a" Ton 440Hz> beträgt?
Eine Rechteckschwingung wechselt in einer SChwingungsperiode 2 mal die
Polarität
1
+------+ +------+ +----
2
| | | | |
3
--+ +-----+ +------+
4
5
|<---------->|
6
1 Schwingung
7
8
^ ^
9
| |
10
| +---- Wechsel von 1 auf 0
11
|
12
+----------- Wechsel von 0 auf 1
da in jeder Schwingung 2 Pegelwechsel vorkommen, du aber 440
Schwingungen pro Sekunde brauchst, brauchst du daher 880 Pegelwechsel
pro Sekunde.
@Karl Heinz
Das ist ein MBC2300, aber ich bin mir sicher, dass der an diesem Pin
direkt hängt.
Ah ok jetzt hab ich es verstanden. Danke für die Hilfestellung.
Ich habe ein Programm geschrieben, aber irgendwie ändert er nicht die
Tonlage, obwohl ich in einer for-Schleife die Werte in das Register
reinschreibe. Hier mein Test-Programm:
1
// note periode frequency
2
#define c 3830 //261Hz
3
#define d 3400 //294Hz
4
#define e 3038 //329Hz
5
#define f 2864 //349Hz
6
#define g 2550 //392Hz
7
#define a 2272 //440Hz
8
#define h 2028 //493Hz
9
#define C 1912 //523Hz
10
//Rest
11
#define R 0
12
13
unsignedinti=0;
14
intmelody[8]={c,d,e,f,g,a,h,C};
15
16
intmain(void)
17
{
18
PINSEL1=0x200000;
19
while(1)
20
{
21
for(i=0;i<1024;i++)
22
{
23
DACR=(melody[i]<<6);//6 Bits mach links shiften da im Register VALUE von 6 bis 15
24
25
}
26
27
}
28
}
Die Grenze sollte bei 8 liegen, ich weiß, aber ich hab nichts hören
können, außer ein "Klicken". Deswegen habe ich rumgespielt und
komischerweiße ändert sich die Lautstärke je größer die Grenze wird. Ich
habe mich dann gefragt, wie das sein kann, denn mein Array ist ja mit 8
Werten versehen. Wenn ich nun den Index größer habe wie 8, da steht doch
eigentlich nichts mehr drin oder nicht?
Was mich auch wundert, dass ich keine "Melodie" raushöre. Ich mein jetzt
nicht ein ganzes Lied oder so, aber zumindest eine Änderung der Tonlage
sollte doch mit dieser Logik machbar sein oder? Ich schreibe ja in der
for-Schleife jedes mal einen neuen Wert in das Register rein.
Hat jemand eine Idee?
Btw die Werte für die Defines die ich habe, habe ich im Internet
gefunden.
Jimin M. schrieb:> Ich habe ein Programm geschrieben, aber irgendwie ändert er nicht die> Tonlage, obwohl ich in einer for-Schleife die Werte in das Register> reinschreibe.
Du verwechselst da was.
Die Frequenz einer Schwingung speigelt sich darin wieder, wie schnell du
am DAC unterschiedliche Spannungen erzeugst (zb 0V und 5V).
D.h. deine Notenwerte sind nicht die Werte, die du in den DAC schreibst,
sondern sie steuern, in welchen zeitlichen Abständen du zb 2
unterschiedliche Werte in das DAC Register (für eine Rechteckschwingung)
schreiben musst.
Der Unterschied zwischen dem Ton 'a' und dem Ton 'f' sieht so aus
1
'a'
2
3
Spannung ^ +-----+ +-----+ +-----+
4
| | | | | | |
5
| ----+ +-----+ +-----+ +---
6
|
7
----------> Zeit
1
'f'
2
3
Spannung ^ +---+ +---+ +---+ +---+ +---+
4
| | | | | | | | | | |
5
| ---+ +---+ +---+ +---+ +---+ +---
6
|
7
----------> Zeit
Mit dem DAC steuerst du, wie hoch die Kurve nach oben geht (die Spannung
am Lautsprecher und damit die Auslenkung der Membrane). Je mehr du
auslenkst (also abwechselnd 0 und einen entsprechend höheren WErt
ausgibst) ...
1
'f'
2
3
+---+ +---+ +---+ +---+ +---+
4
| | | | | | | | | |
5
| | | | | | | | | |
6
---+ +---+ +---+ +---+ +---+ +---
7
8
----------> Zeit
... desto lauter wird der Ton. Und natürlich kann man, indem man nicht
einfach nur 2 fixe Werte benutzt auch andere Kurvenformen erzeugen
1
'f'
2
3
+-+ +-+ +-+ +-+ +-+
4
| | | | | | | | | |
5
| | | | | | | | | |
6
--+ +-+ +-+ +-+ +-+ +-
7
8
----------> Zeit
die sich dann anders anhören. Das Grundprinzip ist aber noch wie vor,
dass dir die zeitliche Steuerung der Spannung obliegt.
Um ein 'a' auszugeben, muss also der DAC genau 1/880-tel Sekunde lang 5V
erzeugen und 1/880-tel Sekunde lang 0V. Und das im ständigen Wechsel.
@Karl Heinz
Ok, das habe ich jetzt verstanden, aber die unterschiedlichen Spannungen
spiegeln sich doch in den Werten wieder, die in das DAC Register
reingeschrieben werden, oder lieg ich da falsch?
Aber wenn ich dich jetzt richtig verstanden habe, dann schreibe ich doch
unterschiedliche Abstände rein. Aber ich höre trotzdem nur einen Ton...
Jimin M. schrieb:> @Karl Heinz> Ok, das habe ich jetzt verstanden, aber die unterschiedlichen Spannungen> spiegeln sich doch in den Werten wieder, die in das DAC Register> reingeschrieben werden, oder lieg ich da falsch?
Ja, klar. Aber deswegen hast du ja noch keinen Ton
> Aber wenn ich dich jetzt richtig verstanden habe, dann schreibe ich doch> unterschiedliche Abstände rein.
Wo genau machst du das denn in deinem Programm?
> Aber ich höre trotzdem nur einen Ton...
Aber nur zufällig.
Dein Programm ist Murks. Ds muss so aussehen
1
füralleNotenderMelodie{
2
3
whileDauerderNotenochnichtvorüber{
4
5
DAC=Wert_für_5V
6
7
warte(ZeitdauerabhängigvonderTonhöhe)
8
9
DAC=Wert_für_0V
10
11
warte(ZeitdauerabhängigvonderTonhöhe)
12
}
13
}
Dein Programm hat hauptsächlich mit zeitlicher Steuerung zu tun! Die
Tonhöhe kommt in den zeitlichen Abständen vor, in denen der DAC mit
jeweils einem anderen Wert bestückt wird.
Dir scheint nicht klar zu sein, was eigentlich eine Schwingung bzw. ein
Ton ist bzw. was der DAC eigentlich macht. Der DAC ist kein Synthesizer,
dem du eine Freuqenz vorgibst und der dann eigenständig eine Schwingung
erzeugt. Dem DAC gibst du einen Wert und den setzt er in eine Spannung
um. Gibst du den den Wert (Hausnummer) 1024 dann erzeugt der DAC daraus
4.78V (ebenfalls Hausnummer). Und zwar als Gleichspannung. Wenn es sein
muss auch ein halbes Jahr lang, ohne dass sich an den 4.78V irgendwas
ändert. Eine Schwingung sieht aber anders aus. In einer Schwingung
ändert sich die Spannung laufend. Bei einem 'a' und einer
Rechteckschwingung 880 mal in der Sekunde.
@Karl Heinz
Stand gestern irgendwann voll auf dem Schlauch und habe nichts mehr so
richtig verstanden. Tut mir leid, wenn ich dich genervt habe :)
Ich habe jetzt "Alle meine Entchen" programmiert. Funktioniert ganz gut.
Ich hätte da aber eine Frage. Würde es eigentlich gehen, wenn ich eine
MP3-Datei ausgeben möchte, über diesen Lautsprecher?
Jimin M. schrieb:> Ich hätte da aber eine Frage. Würde es eigentlich gehen, wenn ich eine> MP3-Datei ausgeben möchte, über diesen Lautsprecher?
Im Prinzip ja.
Aber der Schritt von einem simplen Ton über eine Rechteckschwingung zu
einer MP3 Ausgabe ist ungefähr so groß wie der Schritt vom
Schuhband-Knoten-Machen-können zum Schutzgasschweißen-unter-Wasser.
Bis du ein MP3 dekodieren kannst, musst du noch viele Brötchen backen.
Fang lieber erst mal mit kleinen Brötchen an, die deinen Fähigkeiten
angepasst sind. Bis du ein MP3 auf deinen Lautsprecher rauskriegst musst
du erst noch mindestens 2 Dutzend andere Basistechniken vorher
beherrschen. Und wenn ich beherrschen sage, dann meine ich auch
beherrschen. Im Schlaf beherrschen.
@Karl Heinz
Hab dich verstanden und nehme deine Empfehlung zu Herzen. Ich muss
wirklich noch einiges lernen. Würdest du mir vielleicht ein paar Tipps
geben, mit welchen Methoden ich anfangen sollte? Ich respektiere dieses
Gebiet sehr und möchte ein guter Programmierer werden. Dazu muss ich
einiges lernen, aber ich weiß ehrlich gesagt nicht, wo ich anfangen
soll. Du denkst dir bestimmt, was für ein planloser Mensch, aber ich
möchte es wirklich lernen.
Vielen Dank, dass du mir gute Tipps gegeben hast.
Schönen Sonntag
Jimin M. schrieb:> Hab dich verstanden und nehme deine Empfehlung zu Herzen.
Das klingt nach nettem Jungen - eine Seltenheit hier. Jetzt könnte ich
mit einem Zitat kommen: "start at the beginning and go until you come to
the end, then stop", aber das ist sicherlich nicht nützlich - genauso
wenig, wie Ratschläge ohne die notwendige Kenntnis der Vorbedingungen.
Also: Was hast du bislang so gemacht, was hast du bereits gelesen (und
bereits verstanden), auf welche Dinge konzentrieren sich deine
Interessen, kurzum: was für ne Basis besteht bereits und wie kann man
darauf aufbauen?
Nochwas zur Dudelei: Bitte unterscheide gedanklich zwischen
Klangerzeugung und Klangwiedergabe. Für die Klangerzeugung hast du ja
schon etwas in Richtung Rechteckerzeugung mit variabler Periodenlänge
gemacht. Fein. Klangfarben kriegt man hingegen erst dann verändert, wenn
man von der reinen Rechteckform weg kommt und einen Amplitudenverlauf
generiert. Da kommt dann die Trennung zwischen Erzeugung und Wiedergabe,
weil man sich plötzlich mit sowas wie einer Abtastrate und Samples
konfrontiert sieht. Ja, Sprachausgabe ist auch drin, ich hatte AUCH
DIESES (mal wieder) bei der Lernbetty vorgeturnt. Ich hatte dabei auch
die PCM-Version von Sierra mit implementiert, was eine für simple Geräte
geeignete Kompression ist. Von dort zu MP3 ist es jedoch noch eine
ziemliche Strecke - insbesondere was die schiere Rechenleistung
betrifft. Guck mal nach dem MAD-Player, aber sei nicht traurig, wenn die
Rechenleistung des LPC2368 dafür nicht ausreicht - oder nur dann grad so
ausreichen würde, wenn man das Ganze gekonnt in Assembler macht.
"gekonnt" ist hier entscheidend.
W.S.
@W.S.
Ob das selten ist, weiß ich jetzt nicht, aber ich denke, wenn man
wirklich etwas beherrschen möchte, kommt das nicht von allein. Man muss
schon etwas dafür tun und auch von anderen lernen.
Also ich habe Grundkenntnisse mit C und ein bisschen C#(wobei C# schon
ziemlich lange her ist). Was für ein Level das allerdings ist, kann ich
nicht genau sagen. Kleinere Programme geschrieben mit und ohne µC.
Assembler habe ich auch ein bisschen gelernt, aber wirklich beherrschen
tu ich das nicht.
Was ich so im Internet gelesen habe, war schon logisch. Also dass die
Audio-Datei erst einmal umkodiert werden muss (WAV to C-Code) und dann
dieses Sample ausgelesen werden muss, was dann wiederum am Lautsprecher
wiedergegeben wird. Alles schön und gut, aber ich habe nichts gefunden,
womit ich eine wav-Datei in einen C-Code umwandeln kann. Vielleicht habe
ich auch falsch gesucht, kann ich jetzt nicht genau sagen und einen
Decoder zu basteln, wäre glaub ich eine ganze Nummer zu groß, zumal ich
nicht mal genau sagen kann, wie das ganze umgewandelt wird. Also das
ganze Hintergrundwissen hab ich einfach noch nicht. Ich hab auch
gelesen, dass manche z.B. einen SD-Kartenleser auf ihr Board bauen und
damit die Dateien rausholen. Aber das würde doch auch ohne gehen oder?
Ich mein die entsprechend umgewandelte Datei in einem Ordner
abspeichern, worauf dann mein Programm zugreifen kann, aber ich weiß
halt auch nicht, ob mein Speicher dafür ausreichen würde.
Ich habe mal im Internet nach dem MAD-Player gesucht. Da stand, dass es
ein Programm ist, womit man MPEG Audio Dateien dekodieren kann. Ich
konnte leider nicht das Programm in C-Code finden, um nachzuvollziehen,
wie das ganze Dekodieren funktioniert. Aber wie schon vorhin erwähnt,
ich glaub, da bin ich noch ganz klein, um sowas selber zu programmieren.
Ich wäre aber über eine Hilfestellung zum Thema Dekodieren sehr erfreut.
Vielleicht hat ja irgendjemand ein Sample, das schon dekodiert worden
ist, womit ich dann ein bisschen "spielen" kann. Da kann ich bestimmt
noch eine Menge lernen.
Vielen Dank für die netten Tipps.
Gruß
Hallo Leute,
ich habe ein Programm geschrieben, dass mit einer festen Frequenz von
44,1kHz die Melodie, die ich selber eingebe, abtastet. Mein erstes
Programm, das mir "Alle meine Entchen" am Lautsprecher ausgegeben hat,
lief mit verschiedenen For-Schleifen. Nun wollte ich das ganze mit den
Timern programmieren, damit ich eine feste Frequenz habe. Das habe ich
auch geschafft, aber mein Problem ist nun, dass die Noten die ausgegeben
werden, sich ziemlich schief anhören. Für mein erstes Programm habe ich
Werte aus dem Internet genommen (Programm in C mit einem Arduino
http://www.arduino.cc/en/Tutorial/PlayMelody). Die Werte haben in meinem
Programm mit den Timern nicht funktioniert, deswegen habe ich die Werte
für die einzelnen Noten selber berechnet.
Da ich eine Abtastrate von 44,1kHz eingestellt habe, berechnete ich die
Werte wie folgt:
44100/ 440 = 100
wobei das jetzt ein Beispiel ist mit der Frequenz von dem Ton a. Also
die Frequenz für den Ton a lautet 440Hz.
Das habe ich dann für die anderen Noten auch gemacht. Aber die Töne
klingen ziemlich schief.
Kann mir jemand verraten, ob ich die Berechnung richtig gemacht habe?
Wäre wirklich sehr nett.
Schönes Wochenende
Jimin M. schrieb:> Was ich so im Internet gelesen habe, war schon logisch. Also dass die> Audio-Datei erst einmal umkodiert werden muss (WAV to C-Code) und dann> dieses Sample ausgelesen werden muss, was dann wiederum am Lautsprecher> wiedergegeben wird.
Nein, das ist nicht logisch.
Also: Du hast einen Mikrocontroller. Der hat RAM und ROM (zumeist
Flash-ROM). Im ROM sollte verständlicherweise deine Firmware stehen, mit
der du Leben in deinen Mikrocontroller bringen willst. Wenn du nun
irgendwelche Klänge abspielen willst, dann brauchst du dafür dreierlei:
1. ne Hardware, also etwas wo es digital reingeht (z.B. DAC) und dan
analog am Lautsprecher rauskommt.
2. irgendeine Dudel-Routine in deiner Firmware, die eine Folge von
Samples an die o.g. Hardware ausgeben kann
3. die eigentlichen Samples deines Klanges, den du ausgeben willst.
Deine Firmware mußt du natürlich in irgend einer Programmiersprache
schreiben, übersetzen und in den ROM deines µC's hineinlöffeln. Aber wie
diese nun zu den Samples deines Klanges kommt, kann unterschiedlich
sein. Zum Beispiel ganz vornehm per Wav-Datei auf einer SD-Karte, oder
eben als Folge von Bytes oder Words irgendwo, wo deine Dudelroutine
drauf zugreifen kann. Das kann zusammen mit deinem Programm im ROM
stehen oder auch von einem externen Speicher (serieller Flash u.a.)
geladen werden (sofern du sowas hast).
Es hängt von deinem Programmiergerät ab, ob du die Samples einer
Wav-Datei separat in den ROM kriegst, oder ob du erstmal das Ganze in
eine Quelle deiner Programmiersprache umverpackst und dann zusammen mit
deiner Firmware in den ROM brennst.
Guck dier hier im Forum ruhig mal die Lernbetty an. Die hat keinen
echten DAC, aber dafür kann man ja auch einen Timer im PWM-Modus
benutzen. Ich hatte damals (glaub ich) auch ein Programm mit
hochgeladen, womit man aus einer Wav-Datei ein Stück C-Quelle machen
kann, so mit const byte Dudeldei[sowieso] = { ....... };
Obendrein hatte ich wohl noch einen Sierra-Kompressor engebaut, das
spart ca. 50% Platz im ROM.
W.S.
@W.S.
Danke für die Erklärung. Ich würde mir gerne das anschauen, was du mir
empfohlen hast, aber ehrlich gesagt, finde ich es nicht. Hast du da
vielleicht einen Link? Wäre sehr nett.
Gruß
Jimin M. schrieb:> Ja der Lautsprecher ist auf dem Board schon vorhanden, ist aber eher,> denke ich zumindest, sowas wie ein Summer.
Wenn das wirklich ein Summer ist, wird das schwer mit dem Produzieren
der Töne meine ich.
Eventuell kannst Du den aber abklemmen und einen echten Lautsprecher
dranhängen. Das wäre wohl das erste bevor Du beginnst, die richtigen
Töne zu finden,
@Datenblattleser
Ja du hast Recht.
Aber kann mir evtl. jemand sagen, ob meine Berechnung für die einzelnen
Töne richtig ist?
Wenn ich eine Abtastrate von 44,1kHz haben möchte, dann müsste doch die
Berechnung bei dem Ton 'a' (440Hz) so lauten:
44100/440 = 100
Ich bekomme auch schon Töne raus. Also ich lass jedes mal einen Sinus
berechnen, der dann via Timer abgetastet wird.
Die Töne klingen den Umständen zufolge ok, aber bei dem Ton 'g' und ich
glaube 'f', klingen die total schief. Ich weiß aber nicht wirklich
warum, da die anderen ja richtig klingen.
Wollte nur sagen, dass ich jetzt weiß, an was es lag. Also die Töne
wurden aufgrund des Integers so krass abgerundet, dass die Töne total
schief klangen. Hab einfach "double" benutzt und später dann in
"integer" umgewandelt, um es in mein DAC Register reinschreiben zu
können.
Jetzt klingt alles besser :)
Jimin M. schrieb:> Aber die Töne klingen ziemlich schief.> Kann mir jemand verraten, ob ich die Berechnung richtig gemacht habe?> Wäre wirklich sehr nett.
Ein Tontabelle findest Du hier, bzw kannst sie Dir innerhalb der
Software aus dieser Vorschrift dynamisch generieren:
Freq = 440 x (196/185) hoch N (N = Halbtonschritt)
http://www.96khz.org/oldpages/musicfrequencygeneration.htm
Jetzt kommt noch Dein Timer ins Spiel:
Damit die Tonhöhen in Akkorden über die Oktaven gut genug zueinander
passen, müssen sie jeweils auf etwa 5-10 Tausendstel genau sein.
Damit, wie in Deinem Fall, das auch bei Rechtecksignalen mit ihren
Oberwellen noch gut passt und nicht zu "fett" wird, müssen sie auf 2-3
Zehntausendstel genau sein. Daraus folgt, dass die Timerauflösung mal
wenigstens 5-stellig sein sollte.
@Jürgen S.
Danke für deine wertvollen Tipps.
Könnte ich vielleicht etwas fragen, was vielleicht nicht ganz zum Thema
passt?
Geht es eigentlich einen Pointer mit dem Datentypen "double" zu
deklarieren und diesen dann auf ein Array mit dem Datentypen "double"
zeigen zu lassen? Ich "spiele" ein bisschen an meinem Programm rum und
wollte den Array mit meiner Melodie über einen Zeiger abspielen. Also
ich habe 2 Melodien und diese wollte ich dann abspielen lassen, wenn
z.B. der eine Timer auslöst oder keine Ahnung, wenn eine Variable
gesetzt wird. Ich wollte ein Array-Buffer haben in das dann meine
gewünschte Melodie geladen wird (Je nach Situation). Hab das ganze mal
mit der Funktion memmove() gemacht, hat gut geklappt, aber ich musste
meinem Buffer ganz am Anfang eine feste Größe übergeben(hoffe das ist
richtig ausgedrückt). Da ich aber Melodien mit verschiedenen Längen
habe, habe ich meinem Buffer dem größeren Array angepasst. Jedoch wurden
die restlichen Felder mit "0" ausgefüllt. Um das zu vermeiden (und ich
wollte es ohne eine for-Schleife machen) habe ich gedacht vielleicht
würde es mit einem Zeiger gehen.
Also ungefähr so:
Weiter habe ich noch nicht geschrieben :)
Hab aber direkt eine Fehlermeldung bekommen, in der steht, dass die
Deklaration inkompatibel wäre, was ich nicht verstehe, da ja beide
Datentypen "double" sind.
Also hier nochmal die Fehlermeldung:
main.c(62): error: #147: declaration is incompatible with "double
*ptr_melody" (declared at line 59)
ptr_melody = melody_a[0];
Wäre nett, wenn mir jemand einen Tipp geben könnte.
Danke
natürlich geht das.
Aber du hast das Problem schon erkannt. Nur mit dem Pointer alleine
weißt du nicht, wie gross das Array ist.
D.h. du musst an der Stelle, an der das Array verwendet wird noch eine
zusätzliche Variable haben, in der du vermerkst wie groß eigentlich das
Array ist, auf das der Pointer zeigt.
(*)
> Ich wollte ein Array-Buffer haben in das dann meine gewünschte> Melodie geladen wird
Und umkopieren brauchst du das Array auch nicht. Alles was du brauchst
sind (wahrscheinlich) 2 Pointer.
Der eine zeigt immer auf den Anfang der Melodie, der andere auf die
aktuell zu spielende 'Note'.
> Also hier nochmal die Fehlermeldung:>> main.c(62): error: #147: declaration is incompatible with "double> *ptr_melody" (declared at line 59)> ptr_melody = melody_a[0];
logisch:
wenn melody_a das komplette Array ist, dann ist melody_a[0] ein Wert aus
diesem Array. Ein Wert dieses Arrays, das ist aber ein double. Also 4.0
oder 7.0 oder 3.141592654
Das ist aber nicht das was du nach ptr_melody kopiert haben willst.
ptr_melody soll auf den Anfang des Arrays zeigen, soll also die
Startadresse des Arrays im Speicher beinhalten. Die Startadresse kriegst
du aber indem du sie dir zb so beschaffen lässt ...
1
ptr_melody=&melody_a[0];
... also den 'Address_of_Operator' (das &) benutzt. Oder aber indem du
ausnutzt, dass der Name eines Arrays alleine (also ohne Indexangabe)
bereits als seine eigene Startadresse fungiert.
1
ptr_melody=melody_a;
> Hab aber direkt eine Fehlermeldung bekommen, in der steht, dass> die Deklaration inkompatibel wäre, was ich nicht verstehe, da ja> beide Datentypen "double" sind.
Die beiden Datentypen sind eben nicht 'beide double'.
In
1
ptr_melody=melody_a[0];
ist der Datentyp links vom = ein 'double *', während der Datentyp rechts
vom = ein 'double' ist. Das links vom = ist ein 'Pointer auf double'.
Das ist ein eigener Datentyp: zuallererst mal ist das ein Pointer (das
ist die wichtigere Information!). Und so ein Pointer kann auf einen
double zeigen.
In ....
1
int*pI;
2
char*pC;
3
double*pD;
4
structtest*pPtr;
... sind alle zuallererst mal Pointer! Eine Pointer Variable beinhaltet
die Adresse von etwas (wo ist dieses andere im Speicher zu finden). Es
ist zuallererst mal ein Verweis auf irgendetwas anderes. Die zusätzliche
Angabe (int, char, double, struct test) gibt auskunft darüber, was
dieses 'andere' ist, was man erhält, wenn man genau unter dieser Adresse
im Speicher nachsieht. Das ändert aber nichts daran, dass all diese
Variablen zuallererst mal einfach nur Pointer sind. Und ein Pointer ist
nun mal kein double.
Der Unterschied ist:
1
inti;
es wird eine Variable i angelegt. Diese Variable enthält einen Wert
enthalten. Zum Beispiel 5
1
i
2
+-------+
3
| 5 |
4
+-------+
wohingegen
1
int*pI;
eine Pointer Variable angelegt wird. Diese Pointer Variable enthält die
Speicheradresse von etwas anderem, wo dann der Wert zu finden ist. pI
könnte zum Beispiel die Adresse von i enthalten
1
pI=&i;
wodurch das hier entsteht
1
pI
2
+---------+
3
| o-------------+
4
+---------+ | i
5
| +-------+
6
+->| 5 |
7
+-------+
In pI ist die Adresse von i eingetragen (in der Zeichnung ausgedrückt
durch den Pfeil, da der numerische Wert dieser Adresse recht
uninteressant ist). Will man den Wert (also die 5) ausgehend von pI
erhalten, dann muss man einmalig den Pfeil verfolgen um an diesen Wert
zu kommen. Genau das ist die Bedeutung des '*' in
1
intj;
2
j=*pI;
bzw. auch in
1
*pI=8;
Diese 'Dereferenzierung' ist nichts anderes als ein 'verfolge von pI
ausgehend den Pfeil und mach etwas mit dem, was du am Ende des Pfeils
findest'.
>> Wäre nett, wenn mir jemand einen Tipp geben könnte.
Wie meistens, ist der heisseste Tip: C-Buch durcharbeiten!
Nur glaubt einem das niemand. Und so müssen dann immer wieder
diejenigen, die ihre C-Bücher vor langer langer Zeit riguros
durchgearbeitet haben und geübt haben ehe sie ihr erstes Projekt
angegangen sind, immer wieder mit Basiskentnissen aushelfen.
(*) Es gäbe noch eine 2-te Möglichkeit: man kann natürlich dem
verwendenden Code das Ende des Arrays auch dadurch anzeigen, dass man
einen speziellen Wert als letzten Array Eintrag benutzt, an dem der
verwendende Code erkennt, dass jetzt das Array zu Ende ist, das also
keine weiteren sinnvollen Werte mehr kommen. String-Verarbeitung
funktioniert in C genau nach diesem Prinzip.
@Karl Heinz
Wow, deine Erklärungen sind so gut...Ich bin sehr froh, dass du (und
auch die anderen) sich so viel Mühe geben und mir meine Fragen
beantworten.
Ich habe mir aufmerksam alles durchgelesen und wollte die von dir
vorgeschlagene zweite Möglichkeit ausprobieren. Ich kann dir echt nur
danken. Es funktioniert :)
Danke Danke Danke
Karl Heinz schrieb:> String-Verarbeitung> funktioniert in C genau nach diesem Prinzip.
Ich hätte das so und so in einen Musik-String verpackt, wie "C4,B3,A2"
etc...
Markus W. schrieb:> Ich hätte das so und so in einen Musik-String verpackt, wie "C4,B3,A2"> etc...
Ich würde mich diesbezüglich eher an MIDI orientieren.
http://www.berkhan.com/basic/manual_7/manual_d/data_d/chap7-3.htm
Und nicht vergessen, dass die Längen der Töne noch berücksichtigt werden
sollten (also Note/Länge). Wäre schon recht wichtig, sonst kann man
genau genommen gar kein Liedchen dudeln lassen ... Später vielleicht
noch die Lautstärke der Töne; das ist dann ein "Extra" (aber zum Lernen
- ebenso wie Mehrstimmigkeit - wahrscheinlich nicht schlecht).
Guten Abend zusammen,
vor ein paar Wochen habe ich auch angenfangen mich mit Mikrocontroller
(MSP430) auseinander zu setzen. Hab soweit kleine einfache Programme auf
die Beine gestellt (LED blinken, PWM generieren)
Seid kurzem wollte ich mittels DAC ebenfalls etwas ausgeben.
Hab es ganz einfach hinbekommen, ein Dreieckssignal bzw. ein Sinussignal
auszugeben.
Mein nächster Versuch bestand darin, eine Melodie abzuspielen.
Und dann bin ich auf diesen Thread gestoßen. Vielen Dank an alle die
hier so ausführlich geschrieben haben.
Dennoch habe ich noch Grundlegende verständnis Probleme, was
wiederzugeben.
Jimin M. schrieb:
> Ich habe jetzt "Alle meine Entchen" programmiert. Funktioniert ganz gut.
Und zwar wollte ich ebenfalls wie der Threadersteller "Alle meine
Entchen" wiedergeben. Hab auch soweit verstanden, dass nicht nur
verschiedene Spannungspegel den Ton formen, sondern man ebenfalls die
Schwingung benötigt. Deshalb habe ich im Array nach jeder Spannung eine
Variable hinzugefügt, die die Amplitude wieder auf 0V bringt.
Mir ist bewusst, dass die Clock noch nicht richtig eingestellt ist, aber
ich wollte für den Anfang überhaupt erstmal höhen unterschiede höre.
Hoffe ihr könnt mir an der Stelle auch weiter helfen.
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
//Rest
15
#define R 0 // 8.
16
17
unsignedinti=0,y=0;
18
19
// 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
Du schreibst, du hast erkannt, dass es um Schwingungen geht, schwingst
aber nicht. Ein Ton besteht nicht aus einmal "an, dann aus" sondern das
muss er ganz oft machen.
Im Idealfall ist das sinusförmig mit der Frequenz des Tones. Hierfür
brauch man einen DAC und eine Wertetabelle für einen Sinus. Je genauer
dein DAC ist, desto mehr Werte brauchst du.
Jedem Wert in deiner Tabelle kann man nun einem Winkel zuordnen. Der
trick bei der Tonhöhe besteht nun einfach darin, nicht jeden Punkt in
deinem array auszugeben.
Hat deine komplette (wir haben also einfach eine komplette
Sinusschwingung in 1000 Teile geteilt) Tabelle nun 1000 Werte
(ausreichend für einen 8 Bit DAC, da jeder Wert vierfach vorkommt (zwei
mal positiv und zwei mal negativ)) und du gibst dein signal mit 40 kHz
aus (diese Frequenz sollte fest sein) kannst du einfach anhand der Menge
an übersprungenen Werten die Tonhöhe bestimmen.
Bei 40kHz vergehen zwischen der Ausgabe am DAC etwa 25us.
Möchtest du also einen 1kHz Ton ausgeben, musst du in einer Millisekunde
durch deine Periode durch sein. Du kannst 40 Werte ausgeben, weshalb du
einfach jeden 25. Wert ausgibst.
Bei einem 440Hz Ton hast du 2.27 ms Zeit für deine Periode. Du kannst
also 91 Werte ausgeben. Das heißt du nimmst jeden 11. Wert.
Das ganze nennt sich dann phasenakkumulator. Möchtest du also eine
Sekunde lang einen 1kHz Ton ausgeben, machst du nichts anderes wie 40000
mal jeden 25. Wert auszugeben.
Du hast das Problem, wenn du es nur digital machen möchtest, dass du
keine Zwischenstufen ausgeben kannst. Um den ton zu variieren muss also
die Ausgangsfrequenz (wie oben die 40kHz) variiert werden.
Das macht es relativ einfach den passenden Ton auszugeben (einfach mit
der doppelten Frequenz den Pin toggeln) aber schwerer die korrekte
tonlänge auszugeben. Möchtest du eine Sekunde lang 1kHz ausheben, musst
du 2000 mal den pin mit 2khz toggeln, möchtest du einen 500Hz Ton musst
du 1000 mal den pin mit 1kHz toggeln.
Noch eine Anmerkung: Ja ich weiß, man brauch keine komplette
Sinusschwingung in einem array. Und man brauch auch nicht so viele
Werte, man kann auch interpolieren etc.
@Gerald M.
Wow vielen Dank für die ausführliche Nachricht!
Ich probier das nun mal aus. Hab auch schon eine Seite gefunden, die mir
1000 Sinus Werte generiert.
Hab jetzt statt deinen vorgeschlagenen 8 Bit DAC, den 12 Bit DAC
ausgewählt mit den entsprechenden Werten.
An dieser Stelle würde ich gern noch was hinzufügen, bitte nicht falsch
verstehen.
Den Nachteil den ich an der Konstruktion sehe ist der, dass ich für
jedes Lied was ich abspielen möchte, die entsprechenden Noten dafür
nutzen muss.
Ich mein ich hab das in dem vorherigen Post nicht mitgeteilt, aber was
wäre wenn ich nun eine beliebe wav Datei abspielen möchte, mit dem
entsprechenden HEX Code?
Denn das wäre mein erstes großes Ziel.
Gerald M. schrieb:
> du gibst dein signal mit 40 kHz> aus (diese Frequenz sollte fest sein)
Ja danke für den Tipp, leider bin ich noch nciht so sehr eingeübt dass
ich nicht genau weiß, wie ich das auf 40 kHz runterschrauben soll.
Ich habs mit Timern und Interrupts verscuht, funktioniert aber nicht.
Oder ich hab da was großes Übersehen.
Da das gar nicht ging, hab ich das wieder raus genommen und die Freq vom
ACLK die ich vorher mit 8 geteilt habe benutzt. Da bekomme ich 1 MHz.
Steht alles im Code kommentiert.
Mit dem DCO hab ich es auch versucht, den hab ich ebenfalls auf das
Minimum runtergeschraubt und auch mit den Teiler 4 geteilt, aber kommt
auch nichts sinnvolles bei rum.
Hier wäre ich für Anregungen sehr dankbar!
Gerald M. schrieb:
> Du hast das Problem, wenn du es nur digital machen möchtest, dass du> keine Zwischenstufen ausgeben kannst. Um den ton zu variieren muss also> die Ausgangsfrequenz (wie oben die 40kHz) variiert werden.> Das macht es relativ einfach den passenden Ton auszugeben (einfach mit> der doppelten Frequenz den Pin toggeln)
Den Schritt verstehe ich noch nicht ganz. Könntest du mir den bitte
genauer erklären.
Soweit habe ich deinen Lösungsvorschlag programmiert. Ich höre schon
eine leichte Melodie, aber die CLK ist noch sehr schnell.
Jürgen S. schrieb:
> wer hat eigentlich festgelegt, dass man Musik aus Sinustönen> zusammenbauen muss?
Genau das wollte ich in den vorherigen Post, bevor ich den Code gepostet
habe, anmerken.
Ich mein so lerne ich natürlich auch was, aber wenn mir für die Lieder
die ich später per SD Karte abspielen möchte, die Frequenzen fehlen, ist
es nicht mehr möglich.
Und deshalb habe ich erstmal versucht, mittels einem Array wo die Werte
in HEX abgelegt sind abzuspielen, um eine Melodien auszugeben.
Bekam aber leider nicht das gewünschte Ergebnis. Den Code habe ich ja
weiter oben shcon gepostet.