Forum: Mikrocontroller und Digitale Elektronik PWM Tonhöhe und Lautstärke


von Alex (Gast)


Lesenswert?

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

von Max H. (hartl192)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
von Alex (Gast)


Lesenswert?

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

von Alex (Gast)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

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

von Alex (Gast)


Lesenswert?

>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

von Alex (Gast)


Lesenswert?

Entschuldigung, Falk. Habe mich verguckt :)

von Falk B. (falk)


Lesenswert?

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

http://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.

von Falk B. (falk)


Lesenswert?

Ach so, das Abspielen ist einfach. Man nutzt einen Timer, um mit der 
bekannten Abtastrate die Daten in das PWM-Modul zu schreiben. etwa so.
1
char *pwm_data= &meine_daten;
2
3
ISR(TIMER0_OVF_vect) {
4
   OCR0A = *pwm_data++;
5
   if (pwm_data == (&meine_daten + sizeof (meine_daten)) ){
6
     pwm_data = &meine_daten;  // Ende erreicht, neu anfangen
7
   }
8
}

von Alex (Gast)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

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

von Falk B. (falk)



Lesenswert?

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
extern const char _binary_foo_bin_start[] PROGMEM;
5
extern const char _binary_foo_bin_end[] PROGMEM;
6
7
int main(void) {
8
    int size, 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.
1
Error  1  cannot find -lfoo.o    1  1  test_link_atmelstudio
2
Error  2  ld returned 1 exit status  collect2.exe  0  0  test_link_atmelstudio

Hat jemand eine Idee?

: Bearbeitet durch User
von Alex (Gast)


Angehängte Dateien:

Lesenswert?

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

von Alex (Gast)


Lesenswert?

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

von Konrad S. (maybee)


Lesenswert?

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.

von Markus M. (adrock)


Lesenswert?

Es gibt Hexeditoren die als C-Code speichern können, z.B.

http://mh-nexus.de/en/hxd/

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@ Konrad S. (maybee)

>Nicht als Library einbinden.

Wie dann? Im AVR Studio geht es.

von Falk B. (falk)


Lesenswert?

http://soundfile.sapp.org/doc/WaveFormat/

Also einfach die ersten 44 Bytes überspringen, dort beginnen die 
eigentlichen Tondaten.

von Alex (Gast)


Lesenswert?

Vielen Dank an alle :)
Kann jetzt endlich was mit anfangen.

von Alex (Gast)


Lesenswert?

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
char Ton[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
3
};
4
5
char *pwm_data= &Ton;
6
7
/*
8
Timer auf 22kHz initialisiert
9
PWM auf 60kHz initialisiert
10
Timer gestertet
11
*/
12
13
// Timerinterrupt
14
{
15
Pin toggeln um die Frequenz von Timer mit dem Oszilloscope zu kontrollieren
16
 PWM_Duty = *pwm_data++;
17
 if (pwm_data == (&Ton + sizeof (Ton)) ){
18
  pwm_data = &Ton;  // Ende erreicht, neu anfangen
19
 }
20
}

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

von Konrad S. (maybee)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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

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.