Guten Tag.
Ich möchte einen Ton per PWM erzeugen, aber weiß nicht so recht wie ich
das anstellen soll.
PWM Frequenz ist immer konstant, das ist klar.
Die Tonhöhe kann man ändern indem man das Puls-Pausen-Verhältnis ändert
und quasi eine Sinus Frequenz ändert.
Aber WIE kann man die Lautstärke regeln? Das verstehe ich gerade nicht
:(
Logischerweise auch über Puls-Pau-Verhältnis, aber darüber wird doch
schon die Tonhöhe geregelt.
Bitte, klärt mich auf.
Danke
Gruß Alex
Alex schrieb:> Aber WIE kann man die Lautstärke regeln? Das verstehe ich gerade nicht> :(
Über den Modulationsgrad (falls man das bei PWM aus so nennt). Wenn dein
aufmodulierter Sinus das Tastverhältnis von 0% bis 99% ändert ist er
natürlich lauster als einer der es nur von 45% bis 55% ändert.
@ Alex (Gast)
>PWM Frequenz ist immer konstant, das ist klar.
Nein, das ist nicht allgemein klar. Denn es gibt 2 Möglichkeiten.
a) Der einfache Ansatz. Die PWM erzeugt DIREKT die gewünschte Frequenz.
- PWM-Frequenz = Tonhöhe (variabel)
- PWM-Tastverhältnis = "Tonfarbe" (Oberwellen)
- Lautstärke = konstant
- Kurvenform = konstant (Rechteck)
b) Der komplexere Ansatz. Die PWM + nachgeschalteter Filter arbeitet als
Audio-DAC
- PWM-Frequenz = Ausgabetakt (konstant, relativ hoch > 8kHz)
- PWM-Tastverhältnis = Amplitude des Audiosamples (Lautstärke)
- Kurvenform = beliebig (Audiosample)
Dir muss klar sein, dass die PWM nur MIttel zum Zweck ist, um damit so
etwas ähnliches wie eine Spannung variabler Höhe zu erzielen. Eine
externe Beschaltung (das kann auch ein gewöhlicher Lautsprecher sein)
mittelt dir das Puls/Pausenverhältnis dahingehend aus, dass du durch
Variation desselben genau dasselbe erreichen kannst, wie wenn du
unterschiedlich hohe Spannungen an den Lautsprecher angelegt hättest.
Wie entsteht nun ein Ton mit einer bestimmten Frequenz?
Der entsteht dadurch, dass du die angelegte Spannung in der Zeit
variierst. Zuerst legst du 0V an, dann 0.1V, dann 0.2V etc. etc. Die
Membran des Lautsprechers folgt dieser Spannung, d.h. sie wird (na ja)
genau so weit ausgelenkt, wie es die Spannung vorgibt. D.h. legst du
eine Wechselspannung an, die pro Sekunde sagen wir mal 440 mal einen
Spannungszyklus durchläuft der wie ein Sinus aussieht, dann folgt
natürlich die Membran dieser Spannung und du hörst einen Ton. Hier ist
es dann der berühmte Kammerton 'A'.
Wie laut ist der Ton. Das hängt davon ab, wie weit die Membran
ausgelenkt wird. Durchläuft die auf ihrem 'Weg' durch den Sinus nur
kleine Auslenkungen, dann ist der Ton leise. Durchläuft sie große
Auslenkungen, dann ist der Ton laut. Warum ist das so? Weil bei einer
großen Auslenkung von der Membran dementsprechend ein größeres
Luftvolumen hin und her geschoben wird. Wir hören das dann eben als
lauter als wenn nur winzige Luftmengen von der Membran geschoben werden.
Um einen leisen Ton zu erzeugen, legst du an die Membran zb abwechselnd
die Spannungen 0.5V und 0.6V an (und das 440 mal pro Sekunde).
Dementsprechend schnappt die Membran auch nur zwischen diesen beiden
nahe beeinander liegenden Pegeln hin und her. Legst du 440 mal in der
Sekunde abwechselnd die Spannungen 0.4V und 0.7V an, dann wird die
Membran zwar genau so oft umgeschnappt wie vorher, aber eben auch dem
Spannungspegel entsprechend weiter ausgelenkt. Der Ton wird lauter. (Und
die Kurvenform ist durch die lediglich 2 möglichen Spannungen natürlich
kein Sinus mehr, sondern eine Rechteckschwingung. Aber es geht ja auch
ums Prinzip, und so brauch ich nicht mit haufenweisen Zahlen hantieren).
Die PWM, die du erzeugst, ist nur Hilfsmittel um aus einem Digitalpin
ein Analogon zu einer variablen Spannung erzeugen zu können. Mit der
eigentlichen Tonerzeugung hat sie eher weniger zu tun.
Vielen Dank!
Ich denke, ich verstehe das irgendwo unterbewusst :)
Also ich habe eine Vorstellung wie das funktioniert, muss aber den
Gedanken im Kopf reifen lassen.
Noch habe ich keine Ahnung wie ich das programmieren könnte (wenn ich
das wollte) :)
Gruß Alex
Hallo noch mal,
das Prinzip habe ich durch das Ausprobieren verstanden.
Nun möchte ich einen Ton aufzeichnen und wiedergeben.
Welcher Ton das sein soll, ist erst mal egal. Ein Ton, wo der
Taschenrechner vom Tisch fällt zum Beispiel.
Wie kann ich das anstellen? Also nicht den Taschenrechner runter
schmeißen, sondern den Ton richtig aufzeichnen und ein Sample davon
erstellen.
Um den Ton nachher wiedergeben zu können, muss ich zu einem bestimmten
Zeitpunkt die passende Frequenz haben.
Das bedeutet irgendwie den ADC Wert in PWM Wert umrechnen, der dem Ton
entspricht.
Habe extra keine bestimmte Frequenz ausgesucht, weil das Piepen oder
Brummen langweilig ist.
Kann mir da jemand auf die Sprünge helfen?
Danke & Gruß Alex
@ Alex (Gast)
>Nun möchte ich einen Ton aufzeichnen und wiedergeben.
Das macht der Soundrecorder im Windows. Mit einem Mikrophon/Headset am
PC kann man Töne aufzeichnen.
>Wie kann ich das anstellen? Also nicht den Taschenrechner runter>schmeißen, sondern den Ton richtig aufzeichnen und ein Sample davon>erstellen.
Eben dazu MUSSt du den Taschenrechner runterschmeißen! Wie sonst?
Man kann auch Töne synthetisch erzeugen, dazu gibt es diverse
PC-Programme. Damit aber natürliche Töne nachzumachen, ist gar nicht so
leicht.
>Um den Ton nachher wiedergeben zu können, muss ich zu einem bestimmten>Zeitpunkt die passende Frequenz haben.
Falsche Denkweise. Bei der Arbeit mit Samples gibt man einfach den
Kurvenverlauf des Audiosignals 1:1 wieder, welchen man vorher
aufgenommen hat. Welche Frequenzen da drin stecken, spielt in dem Moment
keine Rolle.
>Kann mir da jemand auf die Sprünge helfen?http://elm-chan.org/works/sd20p/report.html
Sample auf die SD-Karte kopieren, los gehts. Kann man bei ELV auch
fertig kaufen.
http://www.elv.de/mp3-sound-modul-msm-2-komplettbausatz.html
Das Ding arbeitet mit einfachen PCM Samples als auch MP3, aber das kann
man am PC einfach umwandeln.
Wenn man es aber weniger BlackBox artig haben will und WIRKLICH sehen
will, wie es funktioniert, kann man auch einfach einen größeren uC mit
ausreichend Flash nehmen, 32kB sollten erstmal reichen. Dort kann man
ein kleines Sample mit vielleicht 8 kHz Abtastfrequenz direkt in den
Flash packen und direkt per PWM abspielen.
>Wenn man es aber weniger BlackBox artig haben will und WIRKLICH sehen>will, wie es funktioniert, kann man auch einfach einen größeren uC mit>ausreichend Flash nehmen, 32kB sollten erstmal reichen. Dort kann man>ein kleines Sample mit vielleicht 8 kHz Abtastfrequenz direkt in den>Flash packen und direkt per PWM abspielen.
Hallo Frank, danke für deine Antwort.
Das fertige Gerät interessiert mich natürlich nicht. Ich möchte den
Sound schon selbst erzeugen (können).
Meine PWM habe ich bei den Versuchen auf 50kHz eingestellt, also sollte
ich den herunterfallenden Taschenrechner auch mit 50kHz abtasten, oder?
Ich kann natürlich meine PWM Frequenz ändern, wenn es sich rausstellt,
dann die andere Frequenz besser zum Rechnen/abspielen ist.
Für ca. 0,5Sek, wo das Ding Krach macht, soll der Flash von 200kb
reichen :)
Mir ist halt noch unklar, wie ich die aufgenommene Audio Datei im Zahlen
zerlege und vor allem, wie ich diese "Variable" abspiele :)
Eigentlich war das die Frage.
Danke & LG Alex
@Alex (Gast)
>Hallo Frank,
Wer ist das?
>Meine PWM habe ich bei den Versuchen auf 50kHz eingestellt, also sollte>ich den herunterfallenden Taschenrechner auch mit 50kHz abtasten, oder?
Du solltest ihn auffangen, damit er nicht kaputt geht ;-)
>Ich kann natürlich meine PWM Frequenz ändern, wenn es sich rausstellt,>dann die andere Frequenz besser zum Rechnen/abspielen ist.>Für ca. 0,5Sek, wo das Ding Krach macht, soll der Flash von 200kb>reichen :)
Ja. Auf einer CD sind es "nur" 44,1 kHz und 16 Bit/Sample. Für den
Hausgebraucht reichen 22kHz und 8 Bit, mehr macht deine PWM meist nicht
(Jaja, man kann 10 Bit und mehr machen, dann geht aber die Frequenz ganz
schnell runter).
>Mir ist halt noch unklar, wie ich die aufgenommene Audio Datei im Zahlen>zerlege und vor allem, wie ich diese "Variable" abspiele :)>Eigentlich war das die Frage.
Sehr gut erkannt! Dazu gibt es mehrere Möglichkeiten.
1.) Wav ist aber ein einfaches Format mit einem praktisch Konstanten
Header. Diesen kann man im Programm einfach überspringen und danach
direkt auf die Tondaten zugreifen. Man muss nur halt im 8 Bit/22kHz/Mono
Format speichern. Die Daten haben nur 22 kHz Abtastrate, die PWM sollte
man aber so hoch wie möglich laufen lassen. Damit vereinfacht sich der
Filter am Ausgang.
2.) Das Einbinden in das C/ASM Programm.
a) Es gibt diverse Tools im Internet ala Bin to C source, muss man mal
googlen. Die Wandlen beliebige Binärdaten in Textdateien um, welche eine
Konstante initialisieren. Etwas so
char meine_Daten[5000] = {0x08, 0x15, 0x00, .......};
http://stackoverflow.com/questions/8707183/script-tool-to-convert-file-to-c-c-source-code-arrayhttp://stahlworks.com/dev/?tool=bintosrc
Kann man machen, aber erzeugt natürlich riesige Dateien, aber bei den
heuten PCs ist das kein Problem.
b) der clevere Weg ist das direkte Einbinden von Binärdaten in das
Programm. Das geht über den Linker. Beim avr gcc geht das so.
http://www.atmel.com/webdoc/avrlibcreferencemanual/FAQ_1faq_binarydata.html
Wenn du einen anderen Compiler/uC hast, musst du dort in der Doku
suchen.
Vielen Dank Falk, hast mir sehr geholfen!
Ich werde jetzt im Internet irgendeine WAV Datei suchen.
>Diesen kann man im Programm einfach überspringen und danach direkt auf >die
Tondaten zugreifen.
Aber von welchem Programm ist hier die Rede? :) In meinem C Programm,
oder im Programm, dass aus der WAV Datei eine Variable(&meine_daten)
macht?
Oder ist die Variable "meine_daten" die WAV Datei selbst?
Sonst habe ich alles (glaube ich) verstanden :)
Danke dir noch mal
@Alex (Gast)
>Ich werde jetzt im Internet irgendeine WAV Datei suchen.
Ob du dort eine findest?
>>Diesen kann man im Programm einfach überspringen und danach direkt auf >>die
Tondaten zugreifen.
>Aber von welchem Programm ist hier die Rede? :) In meinem C Programm,
Ja.
>oder im Programm, dass aus der WAV Datei eine Variable(&meine_daten)>macht?
Nein.
>Oder ist die Variable "meine_daten" die WAV Datei selbst?
Ja!
>Sonst habe ich alles (glaube ich) verstanden :)
Na dann mal los!
Viel Erfolg!
Ich hab mal fix das Einbinden getestet, es geht einfach.
Die Datei foo.bin mit den Binärdaten sinnvollerweise in den
Projektordner oder Ordner default im Projetverzeichnis kopieren.
In der Kommandozeile mittels CD dort reingehen und diesen Befehl
ausführen
avr-objcopy --rename-section
.data=.progmem.data,contents,alloc,load,readonly,data -I binary -O
elf32-avr foo.bin foo.o
Damit wird die Datei foo.o erzeugt.
1
#include<avr/io.h>
2
#include<avr/pgmspace.h>
3
4
externconstchar_binary_foo_bin_start[]PROGMEM;
5
externconstchar_binary_foo_bin_end[]PROGMEM;
6
7
intmain(void){
8
intsize,i;
9
10
size=_binary_foo_bin_end-_binary_foo_bin_start;
11
12
DDRC=0xFF;
13
14
for(i=0;i<size;i++){
15
PORTC=pgm_read_byte(&_binary_foo_bin_start[i]);
16
}
17
}
Man muss nur noch das Objektfile dem Linker mitteilen, das geht in den
Projektoptionen unter AVR Studio 4.18 so.
Project -> Configuration Options -> Librabies -> Add Object
Siehe Anhang. Im Atmelstudio 6.2 ist das im Fenster Solution Explorer
unter
Libraries -> rechte Maustaste -> Add Library -> Browse Libraries ->
Browse -> foo.o auswählen
Hmmm, aber irgendwie mag Atmelstudio meine foo.o nicht, obwohl sie
vorhanden ist.
Ich habe nun eine WAV Datei runtergeladen. Ist im Anhang.
Dann wollte ich die "nach Zahlen" konvertieren.
Als Programm habe ich GoldWave benutzt.
Ich kann das leider nur als txt und als Dezimalzahl abspeichern.
Wie soll ich denn die WAV Datei in mein Code rein bekommen? :))
Wollte sowas wie Falk geschrieben hat
>char meine_Daten[5000] = {0x08, 0x15, 0x00, .......};
machen.
Die geht das? :)
Danke schön
Danke Falk, ich schätze deine Mühe sehr. Das ist hier im Forum nicht
üblich.
Leider benutze ich keine AVRs und logischerweise kein Atmelstudio. Somit
helfen mir deine mit Liebe gemachten Screenshots und Beschreibung nicht
:(
Falk Brunner schrieb:> Error 1 cannot find -lfoo.o 1 1 test_link_atmelstudio> Error 2 ld returned 1 exit status collect2.exe 0 0> test_link_atmelstudio>> Hat jemand eine Idee?
Nicht als Library einbinden.
@Alex (Gast)
>Ich habe nun eine WAV Datei runtergeladen. Ist im Anhang.>Dann wollte ich die "nach Zahlen" konvertieren.>Als Programm habe ich GoldWave benutzt.
Falsches Format.
>Die geht das? :)
Schrub ich das nicht? Siehe Anhang. Damit kannst du in Zukunft auch
andere Dateien umwandeln.
Guten Abend,
ich probiere immer sehr lange aus, bevor ich nach Hilfe schreie.
Leider funktioniert der Ton nicht.
hier ist der "code" einfach als Ablauf
1
charTon[4208]={//22,0kHz 8bit
2
0x52,0x49,0x46,0x46,0x68,0x10,0x00,0x00,0x57,0x41,0x56,0x45,0x66,0x6D,0x74,0x20,// ... usw 4208 Werte sind das insgesamt geworden
so im Groben.
Es kommt Ton raus, aber das ist eher Müll als Ton :(
PWM Frequenz habe ich mit dem Oszi nachgeguckt, die läuft stabil mit
60kHz
Der Pin im Timerinterrupt wechselt mit 22kHz (jede 45-igste uS) den
Pegel.
Was da genau passiert, warum das nicht funktioniert kann ich nicht mal
sagen.
Es geht halt alles viel zu schnell.
Ich schätze in der Timerinterrupt routine ist etwas falsch, da der Duty
Wert nach (beim) jeden " if (pwm_data == (&Ton + sizeof (Ton)) ){"
auf 255 ist, was eigentlich nicht sein darf.
Kann jemand die Routine noch mal angucken, bitte?
Danke schön. Viele Grüße
Falk Brunner schrieb im Beitrag #4056951:
>>Nicht als Library einbinden.>> Wie dann? Im AVR Studio geht es.
Ich arbeite nicht mit dem AtmelStudio.
Letztlich muss die foo.o beim Linker-Aufruf zusammen mit den anderen
Object-Files genannt werden.
Falk Brunner schrieb im Beitrag #4056910:
> Error 1 cannot find -lfoo.o 1 1 test_link_atmelstudio> Error 2 ld returned 1 exit status collect2.exe 0 0 test_link_atmelstudio
Das "-lfoo.o" bedeutet, dass nach einer Datei "libfoo.o.a" gesucht wird,
also nach der Library "foo.o". Die hast du nicht gebaut, nur das
Object-File "foo.o". Entweder "foo.o" als Object-File linken oder mit
avr-ar aus "foo.o" das Library-File "libfoo.o.a" erzeugen.
@ Alex (Gast)
>so im Groben.
Das kanst du dir in die Haare schmieren. Poste vollständigen, ORIGINALEN
Quelltext als Anhang.
>Es kommt Ton raus, aber das ist eher Müll als Ton :(
Wie sieht deine Aussenbeschaltung aus? Hast du einen
Entkoppelkondensator in Reihe zum PWM-Ausgang? Denn dein uC macht keine
negativen Spannungen, dein Kopfhörer hätte aber gern welche.
Ausserdem muss man aufpassen, dass die PWM im gepufferten Modus
arbeitet. Denn wenn man duch einen dummen Zufall duch das einschreiben
eines neuen PWM-Wertes die PWM kurzzeitig abwürgt, kommen komische
Signale zustande.
>Was da genau passiert, warum das nicht funktioniert kann ich nicht mal>sagen.>Es geht halt alles viel zu schnell.>Ich schätze in der Timerinterrupt routine ist etwas falsch, da der Duty
Darum sollte man diese im ORIGINAL sehen.
>Wert nach (beim) jeden " if (pwm_data == (&Ton + sizeof (Ton)) ){">auf 255 ist, was eigentlich nicht sein darf.>Kann jemand die Routine noch mal angucken, bitte?
Deine Fragmente nützen niemandem etwas, siehe Netiquette.
Falk B. schrieb:> Ich hab mal fix das Einbinden getestet, es geht einfach.>> Die Datei foo.bin mit den Binärdaten sinnvollerweise in den> Projektordner oder Ordner default im Projetverzeichnis kopieren.> In der Kommandozeile mittels CD dort reingehen und diesen Befehl> ausführen>> avr-objcopy --rename-section> .data=.progmem.data,contents,alloc,load,readonly,data -I binary -O> elf32-avr foo.bin foo.o>> Damit wird die Datei foo.o erzeugt.>
1
>#include<avr/io.h>
2
>#include<avr/pgmspace.h>
3
>
4
>externconstchar_binary_foo_bin_start[]PROGMEM;
5
>externconstchar_binary_foo_bin_end[]PROGMEM;
6
>
7
>intmain(void){
8
>intsize,i;
9
>
10
>size=_binary_foo_bin_end-_binary_foo_bin_start;
11
>
12
>DDRC=0xFF;
13
>
14
>for(i=0;i<size;i++){
15
>PORTC=pgm_read_byte(&_binary_foo_bin_start[i]);
16
>}
17
>}
... 10 Jahre später: C23 bringt #embed, womit man eine (Binär)Datei
direkt im C-Code verwenden kann:
1
#include<stddef.h>
2
#include<avr/io.h>
3
4
staticconst__flashuint8_tfoo_bin[]=
5
{
6
#embed "foo.bin"
7
};
8
9
intmain()
10
{
11
for(size_ti=0;i<sizeof(foo_bin);++i)
12
{
13
PORTC=foo_bin[i];
14
}
15
}
Praktischerweise kann man auch andere Sachen mit ins Array packen, zum
Beispiel eine abschließende \0 um einen C-String zu bekommen: