Hallo,
ich habe hier ein Arduino-Board mit einem ATmega328P, das ich jedoch in
C programmiere.
Nun habe ich einen Lautsprecher, den ich gerne ansteuern möchte.
Einfache Rechtecksignale sind kein Problem, da habe ich mir bereits
einige Funktionen geschrieben, mit denen ich (wenn auch nur sehr
geringfügig) die Lautstärke bei gleichbleibender Frequenz ändern kann
sowie +- 3Hz eine Frequenz ausgeben kann.
Bei den nächsten Schritten habe ich aber Probleme:
Wie kann ich zwei Töne gleichzeitig ausgeben (über einen Lautsprecher)?
Wenn ich zwei Frequenzen gleichzeitig über einen Pin ausgebe, dann
bekomme ich üblicherweise nur den oberen Ton und ein "Rattern" (eher so
ein Knacksen) auf Höhe des unteren Tons zu hören.
Wie macht man so etwas üblicherweise?
Und:
mein Ziel ist es, auch Audio-Dateien wiederzugeben.
Allerdings ohne externe SD Card.
Dafür muss ich natürlich die Qualität der Datei extrem vermindern, meine
Schritte waren folgende:
mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen und als
headerless raw-file in unsigned 8-bit gespeichert.
Um die dann direkt in den Code einbetten zu können, habe ich mithilfe
von xdd (Linux commandline hex editor) den Inhalt in Hex-Werte
umgewandelt und in ein gültiges C-Array gepackt.
Mein Problem ist jetzt, wie ich diese Werte ausgeben kann. Wie ermittle
ich die benötigten Frequenzen?
Danke für jede Hilfe!
Arduino und Atmega328 sind hier meiner Meinung nach völlig ungeeignet.
Ein ARM mit I²S wäre hier z.B. angebrachter. Du begibst dich hier auf
einn Irrweg.
A. Audio schrieb:> mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen
Da das Abtasttheorem nicht so einfach ausser Kraft zu setzen ist, wird
auf die Art die höchste in der Datei wiederzugebende Frequenz bei etwa
500Hz sein, abgesehen von dem Problem, die 1kHz Samplefrequenz vom
Ausgang fernzuhalten.
Deswegen ist die niedrigste Samplefrequenz, die man so benutzt, bei ca.
8kHz. Dann geht wenigstens Sprache oder der schlechteste
Mittelwellensender der Welt.
A. Audio schrieb:> Wie ermittle ich die benötigten Frequenzen?
Du brauchst genau eine Frequenz, und die hast Du bereits festgelegt -
das ist die Samplerate.
Deine Audiosamples musst Du mit genau dieser Datenrate an einen DAC
übergeben, und aus dem DAC kommt dann Dein gewünschtes Audiosignal
heraus.
Problem: Dein Atmega328 hat keinen eingebauten DAC.
Mit einer entsprechend höhergetakteten PWM lässt sich ein DAC
nachbilden; Du brauchst, da Du 8-Bit-Samples hast, eine 8-Bit-PWM, was
bedeutet, daß deren Frequenz das 256fache Deiner Samplerate betragen
muss.
Bei 1 kHz Samplerate sind das also 256 kHz.
Du kannst auch einen ganzen Port opfern und dort ein sog. R 2xR Netzwerk
dran machen. Das ist sozusagen ein passiver D/A-Wandler. MIT gleichen
SMD-Widerständen kriegt man das auch einigermaßen klein hin. Ich habe
das mal für ein Lokomoteufelchen (Modelleisenbahn) gebraucht, damit der
Lokführer Sprüche zum Besten geben konnte.
Ich muß gucken, wo ich das habe -auf dem Rechner hier ist es nicht.
MfG Paul
Curby23523 N. schrieb:> Arduino und Atmega328 sind hier meiner Meinung nach völlig> ungeeignet.> Ein ARM mit I²S wäre hier z.B. angebrachter. Du begibst dich hier auf> einn Irrweg.ARM sind schon bestellt, dauert aber noch. Die sind dann mein nächster
Schritt.
Allerdings gibt es genug Videos, die unter Beweis stellen, dass das
eigentlich auch mit einem ATmega gehen müsste. Der verwendete Code ist
da eigentlich immer die Audio.h Lib aus der Arduino IDE.
Matthias S. schrieb:> A. Audio schrieb:>> mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen>> Da das Abtasttheorem nicht so einfach ausser Kraft zu setzen ist, wird> auf die Art die höchste in der Datei wiederzugebende Frequenz bei etwa> 500Hz sein, abgesehen von dem Problem, die 1kHz Samplefrequenz vom> Ausgang fernzuhalten.> Deswegen ist die niedrigste Samplefrequenz, die man so benutzt, bei ca.> 8kHz. Dann geht wenigstens Sprache oder der schlechteste> Mittelwellensender der Welt.
Das es grausig klingt, weiß ich auch. Die SD Card Module sind auch schon
bestellt, ich wollte nur schon einmal vorab den Code fertigen. Und dafür
müsste ja eigentlich erst einmal auch eine Sampling Rate von 1000Hz
reichen, oder nicht? Man erkennt zumindest am PC einigermaßen, was
gemeint ist. Es geht hier auch nur um kurze Töne von 1-2s.
Rufus Τ. F. schrieb:> A. Audio schrieb:>> Wie ermittle ich die benötigten Frequenzen?>> Du brauchst genau eine Frequenz, und die hast Du bereits festgelegt -> das ist die Samplerate.>> Deine Audiosamples musst Du mit genau dieser Datenrate an einen DAC> übergeben, und aus dem DAC kommt dann Dein gewünschtes Audiosignal> heraus.>> Problem: Dein Atmega328 hat keinen eingebauten DAC.>> Mit einer entsprechend höhergetakteten PWM lässt sich ein DAC> nachbilden; Du brauchst, da Du 8-Bit-Samples hast, eine 8-Bit-PWM, was> bedeutet, daß deren Frequenz das 256fache Deiner Samplerate betragen> muss.>> Bei 1 kHz Samplerate sind das also 256 kHz.
Wieso muss diese das 256-fache der Samplingrate betragen? Es müsste doch
auch reichen, wenn PWM mit z.B. 32kHz läuft. Da lassen sich doch auch
bequem 8-bit drauflegen, oder nicht? Und 32kHz wären eigentlich noch im
Machbaren.
Paul B. schrieb:> Du kannst auch einen ganzen Port opfern und dort ein sog. R 2xR> Netzwerk> dran machen. Das ist sozusagen ein passiver D/A-Wandler. MIT gleichen> SMD-Widerständen kriegt man das auch einigermaßen klein hin. Ich habe> das mal für ein Lokomoteufelchen (Modelleisenbahn) gebraucht, damit der> Lokführer Sprüche zum Besten geben konnte.>> Ich muß gucken, wo ich das habe -auf dem Rechner hier ist es nicht.>> MfG Paul
Ich kann leider max. 2 Pins dafür opfern. Alle anderen sind bereits
anderweitig verplant. Wobei das mit Sicherheit auch mal interessant
wäre.
Rufus Τ. F. schrieb:> Das ist tatsächlich eine gute und pragmatische Idee.>> Hier die Grundlagen dazu:>> https://de.wikipedia.org/wiki/R2R-Netzwerk
Aber wohl leider nicht möglich, da ich nicht so viele Pins frei habe.
A. Audio schrieb:> Ich kann leider max. 2 Pins dafür opfern. Alle anderen sind bereits> anderweitig verplant.
Daraus schließe ich, daß der Kontroller auch noch eine Menge anderer
Sachen machen muß bzw. soll. Denke aber daran, daß so eine Sprach- bzw.
Musikausgabe den ganzen Mann fordert. Jede Unterbrechung oder
Verzögerung ist dann sehr störend hörbar.
MfG Paul
Die anderen Sachen sind weder zeitkritisch noch allzu rechenaufwendig.
Das wird auch die Interrupts nicht verzögern, da ansonsten keinerlei
Interrupts verwendet werden (nur in dem gleichen Interrupt noch andere
Sachen; ein bisschen wie in IRMP und IRSND). Es gibt einfach einen
Interrupt, in denen verschiedene Interrupt-Funktionen aufgerufen werden.
Es wäre mir also lieb, wenn es möglich wäre, das schon über Software zu
implementieren. Wie gesagt, die Arduino Lib schafft das ja auch
irgendwie.
Was sonst vllt. noch möglich wäre, wäre ein zweiter µC, der nur für die
Soundausgabe zuständig ist und den ich über SPI (das lässt sich ja, da
schon benutzt, mit nur einem weiteren SS-Pin machen).
Oder was meint ihr sonst noch?
Ist denn ein Schieberegister schnell genug? Ich habe zwar etliche hier
herumliegen, aber ehrlich gesagt noch nie intensiver damit gearbeitet.
Ich habe jetzt allerdings folgendes:
___. . . . . ._____
|. . | . . . . . . |. . . .|
|. . |______|. . . .|____
|--------------||-------------|
32kHz
Wenn ich jetzt in 256 verschiedenen Stufen die Breite des high-pegels
bei einer Frequenz von 32kHz verändere, stimmt das dann?
Jetzt wird nämlich ein Ton ausgegeben, der aber aufgrund seiner Kürze
und Ungenauigkeit (600Hz) nicht einfach zu identifizieren ist.
Durch die sehr kleinen (und damit eher schlechten) Lautsprecher wird das
wohl vermutlich auch noch einmal verfälscht. Ansonsten bleibt mir wohl
nichts anderes übrig, als auf das SD Module zu warten (nicht wundern,
diese Pins habe ich bereits einberechnet; die kann ich deshalb nicht für
die Soundausgabe nutzen).
Kann das aber theoretisch stimmen?
PS: Es ist ganz schön schwer, hier drinnen mit Zeichen zu zeichnen, wenn
das Ergebnis ganz anders aussieht als im Editor.
A. Audio schrieb:> _. . . . . ._____> |. . | . . . . . . |. . . .|> |. . |______|. . . .|____>> |--------------||-------------|> 32kHz> PS: Es ist ganz schön schwer, hier drinnen mit Zeichen zu zeichnen, wenn> das Ergebnis ganz anders aussieht als im Editor.
Jetzt kam sogar noch etwas anderes heraus als in der Vorschau gezeigt
wurde. -.-
Noch ein Versuch, ansonsten hoffe ich, dass ihr wisst, was ich meine:
256 verschiedene Breiten
|--| . . .|----|
_......._____
|..|......|....|
|..|______|....|____
|---------||--------|
32kHz
A. Audio schrieb:> 256 verschiedene Breiten> |--| . . .|----|> _......._____> |..|......|....|> |..|______|....|____>> |---------||--------|> 32kHz
Ich gebe es auf...
Und entschuldigt bitte die mehrfachen Beiträge, die letzten beiden
können gerne gelöscht werden.
A. Audio schrieb:> PS: Es ist ganz schön schwer, hier drinnen mit Zeichen zu zeichnen, wenn> das Ergebnis ganz anders aussieht als im Editor.
Da gibts einen Tipp, der über jedem Eingabefeld für einen neuen Beitrag
steht:
Formatierung
Wenn man da drauf klickt:
https://www.mikrocontroller.net/articles/Formatierung_im_Forum
die 'pre' tags wären brauchbar, dann kommts so raus, wie mans eintippt.
Aber in eckige Klammern...
A. Audio schrieb:> Wie kann ich zwei Töne gleichzeitig ausgeben (über einen Lautsprecher)?> Wenn ich zwei Frequenzen gleichzeitig über einen Pin ausgebe, dann> bekomme ich üblicherweise nur den oberen Ton und ein "Rattern" (eher so> ein Knacksen) auf Höhe des unteren Tons zu hören.
Hier hilft DDS.
Aber zuerst was wichtiges:
Arduino kannst du natürlich benutzen, aber nur als Board. Programmieren
in Arduino-Umgebung bringt hier nichts, Programm wird zu langsam und es
fehlt vieles in Arduino, was du brauchst.
Deshalb nimm so etwas wie AVR Studio 4.19, noch ISP-Programmer, und noch
ein bißchen "C" studieren.
Wie kannst du einen Ton mit sehr, sehr genauer Frequenz ausgeben:
1. richte ein Timer so, daß du Interrupts mit ca. 20 bis 50 kHz hast.
2. nimm zwei Variablen. Eine wird Frequenzwert haben, weitere zählen,
beide als unsigned long. Wenn wir Interrupt-Frequenz als Fd und
Soll-Frequenz als Fv notieren, kannst du Frequenzwert so berechnen: K =
(Fv/Fd)*2^32
In Interrupt wird immer gemacht:
1
volatileunsignedlongwert,freq;
2
wert=Fv*24294967296/Fd;
3
ISR:
4
freq+=wert;
weiter kannst du obere z.B. 8 bit von freq nehmen und als
Frequenzausgang benutzen. Z.B. in PORTB schreiben, wo R-2R-Matrix
angeschlossen wird.
So einfach bekommst du Sägezahn. Willst du Sinus, so mach eine
Sinustabelle, z.B. so:
und Sinus ist da!
Genauigkeit von Frequenz (abgesehen von Quarz-Toleranz) ist Fd/2^32, bei
Fd = 50 kHz wird das 0,00001164... Hz.
Nun deine Aufgabe, zwei Frequenzen auszugeben: nimm zweimal wert und
freq, und addiere, was du aus der Sinus-Tabelle nimmst.
Willst du statt Sinus etwas anderes, kein Problem: mache eine andere
Tabelle.
Servus,
man braucht keine R2R-Matrix und viele Portausgänge!
Mit einem PWM-Ausgang und Pulsbreitenmodulation, wie oben in den
ASCII-Skizzen schon gezeigt, geht das wunderbar und kann sich auch hören
lassen.
Wenigstens ein simples RC-Filter sollte man aber schon dafür spendieren,
sonst klingt es wirklich grausig.
Hier habe ich das mal simuliert - ein 1kHz Sinuston wird mit 31.25kHz in
Impulslängen zerlegt. Die Spannung an V3 wäre das Signal, das per
Timer-PWM (z.B. ein 8-Bit Timer mit 8 MHz Clock) ausgegeben werden kann.
Die WAV-Datei ist das Signal vom out.
Maxim B. schrieb:> A. Audio schrieb:>> Wie kann ich zwei Töne gleichzeitig ausgeben (über einen Lautsprecher)?>> Wenn ich zwei Frequenzen gleichzeitig über einen Pin ausgebe, dann>> bekomme ich üblicherweise nur den oberen Ton und ein "Rattern" (eher so>> ein Knacksen) auf Höhe des unteren Tons zu hören.>> Hier hilft DDS.> Aber zuerst was wichtiges:> Arduino kannst du natürlich benutzen, aber nur als Board. Programmieren> in Arduino-Umgebung bringt hier nichts, Programm wird zu langsam und es> fehlt vieles in Arduino, was du brauchst.>> Deshalb nimm so etwas wie AVR Studio 4.19, noch ISP-Programmer, und noch> ein bißchen "C" studieren.
Wie anfangs gesagt, ich nutze bereits C.
DDS scheitert, wenn ich das richtig nachgelesen habe, an einem fehlenden
DA-Wandler.
> Wie kannst du einen Ton mit sehr, sehr genauer Frequenz ausgeben:> 1. richte ein Timer so, daß du Interrupts mit ca. 20 bis 50 kHz hast.> 2. nimm zwei Variablen. Eine wird Frequenzwert haben, weitere zählen,> beide als unsigned long. Wenn wir Interrupt-Frequenz als Fd und> Soll-Frequenz als Fv notieren, kannst du Frequenzwert so berechnen: K => (Fv/Fd)*2^32>> In Interrupt wird immer gemacht:volatile unsigned long wert, freq;> wert = Fv*24294967296/Fd;> ISR:> freq += wert;> weiter kannst du obere z.B. 8 bit von freq nehmen und als> Frequenzausgang benutzen. Z.B. in PORTB schreiben, wo R-2R-Matrix> angeschlossen wird.> So einfach bekommst du Sägezahn.
Mit Sägezahn meinst du vermutlich ein Rechteck-Signal, oder?
Weiterhin verstehe ich irgendwie deine Rechnung nicht ganz.
Weshalb *2^32?
Ich habe es bisher immer so gemacht:
counter = INTERRUPTS_PER_S frequency 2;
Dann in der ISR counter heruntergezählt und bei 0 den Pin getoggled.
Um einen Wert auszugeben habe ich dazu folgendes ergänzt:
counter = INTERRUPTS_PER_S / frequency;
value_counter = INTERRUPTS_PER_S value 0xFF counter 255/256.;
Beides in der ISR heruntergezählt und bei 0 von value_counter den Pin
auf low gesetzt und bei counter == 0 den value_counter wieder
eingestellt.
Mein Problem ist, dass INTERRUPTS_PER_S bei großen Frequenzen natürlich
zu klein ist. Wenn du mir deinen Ansatz noch einmal erklärst, kann ich
das vllt. einbauen. Wobei ich dabei ehrlich gesagt auch die Gefahr sehe,
dass die Werte zu groß werden. Was genau ist denn dann eigentlich freq
für ein Wert, warum verwende ich nur die obersten 8 bits?
> Willst du Sinus, so mach eine> Sinustabelle, z.B. so:const unsigned char sinus_table[256] PROGMEM = {> 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167,> 170, 173,> 176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, 208, 211,> 213, 215,> 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 238, 240, 241,> 243, 244,> 245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254, 254, 255,> 255, 255,> 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251, 250, 250, 249,> 248, 246,> 245, 244, 243, 241, 240, 238, 237, 235, 234, 232, 230, 228, 226, 224,> 222, 220,> 218, 215, 213, 211, 208, 206, 203, 201, 198, 196, 193, 190, 188, 185,> 182, 179,> 176, 173, 170, 167, 165, 162, 158, 155, 152, 149, 146, 143, 140, 137,> 134, 131,> 128, 124, 121, 118, 115, 112, 109, 106, 103, 100, 097, 093, 090, 088,> 085, 082,> 079, 076, 073, 070, 067, 065, 062, 059, 057, 054, 052, 049, 047, 044,> 042, 040,> 037, 035, 033, 031, 029, 027, 025, 023, 021, 020, 018, 017, 015, 014,> 012, 011,> 010, 009, 007, 006, 005, 005, 004, 003, 002, 002, 001, 001, 001, 000,> 000, 000,> 000, 000, 000, 000, 001, 001, 001, 002, 002, 003, 004, 005, 005, 006,> 007, 009,> 010, 011, 012, 014, 015, 017, 018, 020, 021, 023, 025, 027, 029, 031,> 033, 035,> 037, 040, 042, 044, 047, 049, 052, 054, 057, 059, 062, 065, 067, 070,> 073, 076,> 079, 082, 085, 088, 090, 093, 097, 100, 103, 106, 109, 112, 115, 118,> 121, 124> };> weiter wird gemacht:PORTB = pgm_read_byte (&sinus_table[(unsigned> char)(freq>>24)]);und Sinus ist da!
Hier ist das Prolbem, dass ich nicht den ganzen PORTB frei habe. Und ich
will auch nicht einfach nur einen konstanten Ton erzeugen. Es geht
darum, zwei Töne auf einem Lautsprecher ausgeben zu können, also quasi
einen Akkord und letztendlich auch darum, ein (kleines) Audiofile
abspielen zu können.
A. Audio schrieb:> counter = INTERRUPTS_PER_S frequency 2;> Dann in der ISR counter heruntergezählt und bei 0 den Pin getoggled.> Um einen Wert auszugeben habe ich dazu folgendes ergänzt:> counter = INTERRUPTS_PER_S / frequency;> value_counter = INTERRUPTS_PER_S value 0xFF counter 255/256.;
Das heißt natürlich:
Und noch ein Problem:
Wenn man eine MP3-Datei im raw-format abspeichert, dann ist die 0 ja in
der Mitte, also unsigned bei 127.
Entsprechend müsste ich ja eigentlich bei 127 0 ausgeben und bei 126 -1.
Aber ich kann über PWM ja nicht -1 ausgeben. Gibt es dafür noch eine
Lösung? So hat man natürlich immer, wenn eigentlich 0 ausgegeben werden
soll 127 und somit ein leichtes Rauschen.
A. Audio schrieb:> DDS scheitert, wenn ich das richtig nachgelesen habe, an einem fehlenden> DA-Wandler.
Du solltest die "Klangsynthese" von der Ausgabe getrennt betrachten. Ob
Du nun die Werte an einen integrierten DAC, Port mit R2R-Netzwerk oder
PWM-Generator übergibst, ändert doch nichts an der Berechnung der
Wellenform.
Dementsprechend scheitert auch das DDS-Verfahren nicht, weil kein
integrierter DAC vorhanden ist.
A. Audio schrieb:> Mein Problem ist, dass INTERRUPTS_PER_S bei großen Frequenzen natürlich> zu klein ist.
Die Interrupts werden bei DDS nicht häufiger, wenn die Frequenz des
Audio-Signals erhöht wird. Die Interrupts laufen fest mit der
Sample-Frequenz (z.B. 32kHz), egal, ob Du einen 1kHz oder 5kHz Ton (oder
auch beide gleichzeitig) erzeugen willst.
A. Audio schrieb:> value_counter = INTERRUPTS_PER_S / (value / 0xFF counter 255/256.);
Mir scheint, Du willst die 8-Bit PWM per Software in Interrupts erzeugen
- dazu bräuchtest Du ja dann tatsächlich eine Interrupt-Frequenz von
256*PWM-Frequenz - dieser Ansatz ist natürlich gleich zum Scheitern
verurteilt!
Die PWM muss natürlich mit Hardware-Unterstützung gemacht werden (Timer
mit Output Compare).
Bin jetzt nicht so der Spezialist, was die Möglichkeiten der
AVR-Peripherie angeht. Beim PIC würde ich das PWM Modul direkt benutzen
- da muss dann jeweils nur der aktuelle Ausgabewert in ein Register
geschrieben werden.
Wenn das so beim AVR nicht geht(*), wäre die zweitbeste Methode eben ein
Interrupt beim Match des Timers mit dem OCR-Register. Das sind dann aber
auch nur jeweils ein Interrupt pro PWM-Zyklus und nicht 256.
A. Audio schrieb:> So hat man natürlich immer, wenn eigentlich 0 ausgegeben werden> soll 127 und somit ein leichtes Rauschen.
Kein Rauschen, sondern die PWM-Frequenz mit mehr oder weniger großer
Amplitude, je nach Charakteristik des nachgeschalteteten Tiefpasses.
Wenn die PWM-Frequenz aber über der Hörgrenze liegt (> 20kHz), dürften
die Reste der PWM-Frequenz auf dem Signal nicht stören.
(*) Edit: habe gerade mal ins kurz ins Datenblatt geguckt! Natürlich hat
der Controller auch brauchbare Hardware-PWM Peripherie. Geht also auch
voll Hardwareseitig!
Thomas E. schrieb:> A. Audio schrieb:>> DDS scheitert, wenn ich das richtig nachgelesen habe, an einem fehlenden>> DA-Wandler.>> Du solltest die "Klangsynthese" von der Ausgabe getrennt betrachten. Ob> Du nun die Werte an einen integrierten DAC, Port mit R2R-Netzwerk oder> PWM-Generator übergibst, ändert doch nichts an der Berechnung der> Wellenform.> Dementsprechend scheitert auch das DDS-Verfahren nicht, weil kein> integrierter DAC vorhanden ist.>> A. Audio schrieb:>> Mein Problem ist, dass INTERRUPTS_PER_S bei großen Frequenzen natürlich>> zu klein ist.>> Die Interrupts werden bei DDS nicht häufiger, wenn die Frequenz des> Audio-Signals erhöht wird. Die Interrupts laufen fest mit der> Sample-Frequenz (z.B. 32kHz), egal, ob Du einen 1kHz oder 5kHz Ton (oder> auch beide gleichzeitig) erzeugen willst.
Ich probiere es einmal aus.
Allerdings folgendes Problem:
Maxim B. schrieb:> volatile unsigned long wert, freq;> wert = Fv*24294967296/Fd;> ISR:> freq += wert;
Dafür reichen uint32_t nicht aus. Das bräuchte min. 64 Bits. Und dann
ist das freq>>24 natürlich sinnlos. Weshalb überhaupt * 24294967296?
24294967296 != 2^32, und ich dachte 2^32 soll man verwenden? Wobei man
damit natürlich erst recht nicht mit einem uint32_t hinkommt.
Thomas E. schrieb:> A. Audio schrieb:>> So hat man natürlich immer, wenn eigentlich 0 ausgegeben werden>> soll 127 und somit ein leichtes Rauschen.>> Kein Rauschen, sondern die PWM-Frequenz mit mehr oder weniger großer> Amplitude, je nach Charakteristik des nachgeschalteteten Tiefpasses.> Wenn die PWM-Frequenz aber über der Hörgrenze liegt (> 20kHz), dürften> die Reste der PWM-Frequenz auf dem Signal nicht stören.
Ich verstehe nur irgendwie das Prinzip dahinter nicht.
Wenn ich den Wert 127 analog ausgebe mit 255 Stufen, dann bin ich ja bei
50% * U. Dabei steht 127 doch eigentlich für keinerlei Ton. Und bei 0
bin ich dafür bei 0% * U. Also kein Ton, obwohl ja eigentlich sehr wohl
ein Ton da sein müsste mithilfe einer negativen Spannung, oder nicht?
> (*) Edit: habe gerade mal ins kurz ins Datenblatt geguckt! Natürlich hat> der Controller auch brauchbare Hardware-PWM Peripherie. Geht also auch> voll Hardwareseitig!
Ich habe auch noch einmal ins Datenblatt geschaut und ein wenig
gegooglet. Tatsächlich ist es möglich, auch Duty-Cycles einzustellen mit
OCRnA und OCRnB. Daran habe ich gar nicht gedacht, dass ich ja auch
einfach zwei Register kombinieren kann. Danke für den Hinweis.
Ich ging ehrlich gesagt davon aus, dass es nur möglich ist,
Rechtecksignale mit 50% Duty zu erstellen. Auf die Kombination von
zweien bin ich nicht gekommen.
A. Audio schrieb:> Weshalb überhaupt * 24294967296?
keine Ahnung, wie er auf diese Zahl kommt. Gibt ja auch als Hex-Zahl
(5A817C800) nicht viel Sinn. Ich würde sagen: klammere Dich nicht an
diese Zahl sondern versuche, das Prinzip zu verstehen. Wenn Du nicht
unbedingt eine extrem fein granulierbare Frequenzeinstellung benötigst,
reicht evtl. auch eine 16-Bit Rechnung.
Das Prinzip ist, daß man in der ISR mit fester Ausgabe-Samplerate (z.B.
alle 32µs) den Lesezeiger für den Samplespeicher (z.B. Sinus-Daten) um
einen gewissen Betrag weiterstellen muss, abhängig von der gewünschten
Tonhöhe. Wenn man mit ganzen Zahlen rechnet, geht das normalerweise nur
in ganzzahligen Schritten, d.h. die Sinuswelle könnte man nur mit
einfacher, doppelter, dreifacher... Frequenz ausgeben.
Für andere Verhältnissse (z.B. *1,5 oder *0,75) braucht man
Nachkommastellen. Man könnte mit float rechnen, aber das will man aus
Performance-Gründen hier eher nicht. Also benutzt man
Festkomma-Arithmetik und nimmt eine lange Integer-Variable, von der die
oberen Bits als Vorkommastellen (->Sinus-Sampleadresse) und die
niedrigeren Bits als Nachkommastellen behandelt werden.
A. Audio schrieb:> Also kein Ton, obwohl ja eigentlich sehr wohl> ein Ton da sein müsste mithilfe einer negativen Spannung, oder nicht?
Durch eine simple Gleichspannung entsteht nie ein Ton. Der Ton entsteht
durch eine zyklische Änderung der Spannung, und dabei ist dann aber
egal, ob sich die Spannung im Bereich -1 und +1 Volt ändert, oder
zwischen 0V und 2V. Auch ein DAC, wie er in vielen µCs eingebaut ist,
oder ein R2R-Netzwerk am Port-Ausgang kann i.d.R. keine negative
Spannung ausgeben. Da aber ein Tonsignal positive und negative
Halbwellen hat, setzt man hier den "Ruhepegel" eben auf die Hälfte der
maximal möglichen Ausgangsspannung. So kann sich die Spannung relativ
dazu in beide Richtungen ändern. Der Verstärker gibt nur den verstärkten
Wechelspannungs-Anteil an den Lautsprecher, dafür ist also egal, wo der
absolute Ruhepegel liegt.
Autor: A. Audio (Gast)
Datum: 24.03.2018 15:13
>Hier ist das Prolbem, dass ich nicht den ganzen PORTB frei habe. Und ich>will auch nicht einfach nur einen konstanten Ton erzeugen. Es geht>darum, zwei Töne auf einem Lautsprecher ausgeben zu können, also quasi>einen Akkord und letztendlich auch darum, ein (kleines) Audiofile>abspielen zu können.
PWM und DDS eignet sich gut dafür:
Beitrag "17 Kanal Avr Synthesizer in Asm"
A. Audio schrieb:> mein Ziel ist es, auch Audio-Dateien wiederzugeben.> Allerdings ohne externe SD Card.> Dafür muss ich natürlich die Qualität der Datei extrem vermindern, meine> Schritte waren folgende:
Schau mal, wie so etwas in der klassischen digitalen Telefonie gemacht
wird. Die Signale werden mit einer Auflösung von etwa 14 Bit mit 8kHz
gesampelt. Dann werden sie mit einer PCM-Codierung (A-law oder µ-Law)
auf 8 Bit komprimiert. Das gibt auf eine serielle umgerechnet eine
Datenrate von 64 kBit pro Sekunde oder einen Speicherbedarf von 8 kByte.
Audacity kann solche Daten aus eigentlich jedem anderen Format
herstellen.
Wie kann man das möglichst simple wiedergeben? Als DAC benutzt man PWM.
Um mit der Qualität in die Nähe der Aufnahme zu kommen, sollte die PWM
bei einer Frequenz von 8 kHz eine Auflösung von 11-12 Bit haben, mehr
als 14 bringt aber auch nichts. Jetzt muß man nur im PWM Interrupt alle
125µs (die 8kHz) ein Sample von PCM auf linear decodieren und auf die
PWM geben.
Das decodieren geht leichter, als es die Formeln vermuten lasse. Da die
PCM-Samples nur 8 Bit haben, kann man für das Decodieren eine Tabelle
verwenden. Das sind 256 16Bit Integer, also ein halbes k. Diese kann man
sich leicht vorher, sowohl für A-Law als auch für µ-Law auf dem PC
ausrechnen. Das Decodieren ist dann nur noch ein Tabellenzugriff, das
schafft wirklich jeder µC.
Das Ausgangssignal hat die klassische Telefonbandbreite von 300Hz bis
3,2kHz. Das Signal aus der PWM hat aber eine Problem, es enthält hohe
Anteile an der PWM-Frequenz von 8kHz, die hörbar ist. Für einen DAC mit
einer PWM braucht man sowieso ein Filter, hier sollte es eine höhere
Ordnung haben.
Die Belastung des µC ist marginal: nächstes Sample lesen,
Tabellenzugriff und Schreiben des PWM Registers. Und das alle 125µs. Und
die Qualität ist eher besser als ein Walkman. Ich hab sowas mal gebaut
und das PWM_Signal gegenphasig auf ein paar parallelgeschaltete
Busbuffer gegeben. Dann ein paar LC-Filter und einen Lautsprecher, so
ein Class-D für Arme. Ich hielt das Ergebniss für brauchbar.
Ist länger geworden, als ich gedacht hatte
MfG Klaus
Klaus schrieb:> sollte die PWM> bei einer Frequenz von 8 kHz eine Auflösung von 11-12 Bit haben,
Wozu denn eine so hohe Auflösung? Bei 8kHz ist das Sampleraster schon
derart grob, daß einen da eine hohe Auflösung (> 60dB SNR) bei der
Qualität auch nicht mehr groß 'rausreisst. Ich würde da eher auf eine
höhere Abtastfrequenz gehen und die PWM-Frequenz möglichst erhöhen,
damit man keinen so steilflankigen Tiefpass nachschalten muss. Für
Telefonqualität reicht doch SNR = 48 dB (8 Bit Aufösung) locker. Evtl.
wäre es sogar in der Praxis besser, noch ein Bit zugunsten einer höheren
PWM-Frequenz zu opfern. Ein 7-Bit Timer mit 16 MHz gibt 125kHz, davon
bleibt selbst mit einem simplen, 1-stufigen RC-Filter nicht mehr viel
übrig.
Also, mein "Rezept" für brauchbare Qualität mit geringem Aufwand wäre:
8-Bit samplen, aber dafür >= 16kHz Abtastrate (relativ weit weg vom
Nutzsignal) und noch höhere PWM Frequenz (sehr weit weg vom Nutzsignal).
Beim Telefon wird wahrscheinlich mit einer höheren Auflösung gesampled,
um den Dynamikbereich zu erhöhen, d.h. es soll ja auch noch etwas zu
verstehen sein, wenn der Sprecher mal etwas leisere Töne anschlägt. Zur
Ausgabe eines Signaltons braucht es das aber nicht, da man den immer mit
optimaler (Voll-)Aussteuerung generieren kann.
Thomas E. schrieb:> A. Audio schrieb:>> Weshalb überhaupt * 24294967296?>> keine Ahnung, wie er auf diese Zahl kommt. Gibt ja auch als Hex-Zahl> (5A817C800) nicht viel Sinn. Ich würde sagen: klammere Dich nicht an> diese Zahl sondern versuche, das Prinzip zu verstehen. Wenn Du nicht> unbedingt eine extrem fein granulierbare Frequenzeinstellung benötigst,> reicht evtl. auch eine 16-Bit Rechnung.> Das Prinzip ist, daß man in der ISR mit fester Ausgabe-Samplerate (z.B.> alle 32µs) den Lesezeiger für den Samplespeicher (z.B. Sinus-Daten) um> einen gewissen Betrag weiterstellen muss, abhängig von der gewünschten> Tonhöhe. Wenn man mit ganzen Zahlen rechnet, geht das normalerweise nur> in ganzzahligen Schritten, d.h. die Sinuswelle könnte man nur mit> einfacher, doppelter, dreifacher... Frequenz ausgeben.> Für andere Verhältnissse (z.B. *1,5 oder *0,75) braucht man> Nachkommastellen. Man könnte mit float rechnen, aber das will man aus> Performance-Gründen hier eher nicht. Also benutzt man> Festkomma-Arithmetik und nimmt eine lange Integer-Variable, von der die> oberen Bits als Vorkommastellen (->Sinus-Sampleadresse) und die> niedrigeren Bits als Nachkommastellen behandelt werden.
Okay, jetzt habe ich es, denke ich, verstanden.
Einfach:
1
uint32_t counter = 0;
2
uint32_t value = sampling_rate * 65536 / 20000;
3
counter += value;
4
if(counter < size)
5
analog_output(counter>>16);
6
else
7
stop();
Müsste soweit eigentlich auch stimmen.
> A. Audio schrieb:>> Also kein Ton, obwohl ja eigentlich sehr wohl>> ein Ton da sein müsste mithilfe einer negativen Spannung, oder nicht?>> Durch eine simple Gleichspannung entsteht nie ein Ton. Der Ton entsteht> durch eine zyklische Änderung der Spannung, und dabei ist dann aber> egal, ob sich die Spannung im Bereich -1 und +1 Volt ändert, oder> zwischen 0V und 2V. Auch ein DAC, wie er in vielen µCs eingebaut ist,> oder ein R2R-Netzwerk am Port-Ausgang kann i.d.R. keine negative> Spannung ausgeben. Da aber ein Tonsignal positive und negative> Halbwellen hat, setzt man hier den "Ruhepegel" eben auf die Hälfte der> maximal möglichen Ausgangsspannung. So kann sich die Spannung relativ> dazu in beide Richtungen ändern. Der Verstärker gibt nur den verstärkten> Wechelspannungs-Anteil an den Lautsprecher, dafür ist also egal, wo der> absolute Ruhepegel liegt.
Okay, das ist soweit klar.
Mein Problem ist aber, dass, wenn ich 0x80 (=128) länger ausgebe, einen
konstanten Ton erhalte. Und bei dem, was ich ausgebe, kommt nur
ziemlicher Schwachsinn heraus. Nur bei 0x00 wird nichts ausgegeben.
Die Werte gebe ich so aus:
1
void analog_init()
2
{
3
TCCR0B = (1 << CS02);
4
TCCR0A = (1 << WGM01);
5
OCR0A = 0xFF;
6
OCR0B = 0x80;
7
TIMSK0 |= (1 << OCIE0A) | (1 << OCIE0B);
8
}
9
10
void analog_output(uint8_t value)
11
{
12
OCR0B = audio_[(uint8_t)(rate_counter >> 16)];
13
}
Dabei ist audio_ das Array mit den Werten aus der mp3, die ich ausgeben
will.
chris schrieb:> Beitrag "17 Kanal Avr Synthesizer in Asm"
Mein Problem ist das ASM. Ich kann zwar die Grundlagen, aber es ist für
mich sehr anstrengend.
Ich kann aber ja einmal durchschauen, ob ich nicht doch etwas finde, das
ich verstehe und wiederverwenden kann.
Klaus schrieb:> A. Audio schrieb:>> mein Ziel ist es, auch Audio-Dateien wiederzugeben.>> Allerdings ohne externe SD Card.>> Dafür muss ich natürlich die Qualität der Datei extrem vermindern, meine>> Schritte waren folgende:>> Schau mal, wie so etwas in der klassischen digitalen Telefonie gemacht> wird. Die Signale werden mit einer Auflösung von etwa 14 Bit mit 8kHz> gesampelt. Dann werden sie mit einer PCM-Codierung (A-law oder µ-Law)> auf 8 Bit komprimiert. Das gibt auf eine serielle umgerechnet eine> Datenrate von 64 kBit pro Sekunde oder einen Speicherbedarf von 8 kByte.> Audacity kann solche Daten aus eigentlich jedem anderen Format> herstellen.>> Wie kann man das möglichst simple wiedergeben? Als DAC benutzt man PWM.> Um mit der Qualität in die Nähe der Aufnahme zu kommen, sollte die PWM> bei einer Frequenz von 8 kHz eine Auflösung von 11-12 Bit haben, mehr> als 14 bringt aber auch nichts. Jetzt muß man nur im PWM Interrupt alle> 125µs (die 8kHz) ein Sample von PCM auf linear decodieren und auf die> PWM geben.>> Das decodieren geht leichter, als es die Formeln vermuten lasse. Da die> PCM-Samples nur 8 Bit haben, kann man für das Decodieren eine Tabelle> verwenden. Das sind 256 16Bit Integer, also ein halbes k. Diese kann man> sich leicht vorher, sowohl für A-Law als auch für µ-Law auf dem PC> ausrechnen. Das Decodieren ist dann nur noch ein Tabellenzugriff, das> schafft wirklich jeder µC.>> Das Ausgangssignal hat die klassische Telefonbandbreite von 300Hz bis> 3,2kHz. Das Signal aus der PWM hat aber eine Problem, es enthält hohe> Anteile an der PWM-Frequenz von 8kHz, die hörbar ist. Für einen DAC mit> einer PWM braucht man sowieso ein Filter, hier sollte es eine höhere> Ordnung haben.>> Die Belastung des µC ist marginal: nächstes Sample lesen,> Tabellenzugriff und Schreiben des PWM Registers. Und das alle 125µs. Und> die Qualität ist eher besser als ein Walkman. Ich hab sowas mal gebaut> und das PWM_Signal gegenphasig auf ein paar parallelgeschaltete> Busbuffer gegeben. Dann ein paar LC-Filter und einen Lautsprecher, so> ein Class-D für Arme. Ich hielt das Ergebniss für brauchbar.>> Ist länger geworden, als ich gedacht hatte>> MfG Klaus
Ich werde es mir einmal ansehen, danke für den Tipp.
Allerdings habe ich ja derzeit noch Probleme mit der Ausgabe.
A. Audio schrieb:> Mein Problem ist aber, dass, wenn ich 0x80 (=128) länger ausgebe, einen> konstanten Ton erhalte.
Du hast nicht verstanden, wie die DAC-Nachbildung mit PWM funktioniert,
d.h. Du hast das zur Glättung nötige RC-Glied (Tiefpass) am Ausgang
weggelassen.
Das, was Du als Wert der PWM übergibst, entspricht einem Spannungspegel
am Ausgang - 0 ist der geringste, 255 der größte und 128 der mittlere
Pegel.
A. Audio schrieb:> Maxim B. schrieb:> Mit Sägezahn meinst du vermutlich ein Rechteck-Signal, oder?
Oder. Sägezahn ist kein Rechteck.
> Weiterhin verstehe ich irgendwie deine Rechnung nicht ganz.> Weshalb *2^32?
Weil max. Zahl in unsigned long 2^32-1 ist.
Bei neueren Toolchains geht auch mit __uint24, für so eine Verwendung
ist Genauigkeit von 2^24 ausreichend.
> Ich habe es bisher immer so gemacht:> counter = INTERRUPTS_PER_S frequency 2;> Dann in der ISR counter heruntergezählt und bei 0 den Pin getoggled.
Das ist kein DDS, das ist etwas anderes. Viel weniger genau, was
Frequenz betrifft. Z.B. 0,01 cent Genauigkeit kann man so nicht
erreichen - gut wenn es unterhalb 2-3 cent bleibt.
>> warum verwende ich nur die obersten 8 bits?
Weil das reicht. Du kannst statt char auch int verwenden, nur mehr
Speicherplatz und etwas langsamer. Wenn mehr als 2 Töne gleichzeitig,
dann auch bei F_CPU = 20 MHz muß du Fd unter 32 kHz herabsetzen.
> Hier ist das Prolbem, dass ich nicht den ganzen PORTB frei habe.
Dann nimm ein Register, so wie 574, damit alle Ausgänge synchron
funktionieren - und nimm die Pins, die du frei hast. Es wird nur ein
bißchen langsamer. Oder mit SPI und 595-Register.
Z.B. so ist das möglich (zum Frage, warum obere byte nur auf 240
beschränkt: so ist bequemer, gängige Obertöne für Wave-Tabelle zu
berechnen: 16' = 480, 8' = 240, 5 1/3' = 160, 2/3' = 20):
A. Audio schrieb:> Dabei ist audio_ das Array mit den Werten aus der mp3, die ich ausgeben> will.
Nur mal zur Klarstellung: Eine MP3-Datei kannst Du so nicht direkt
ausgeben! Die musst Du vorher schon dekodieren und die Samples als
Wellenform abspeichern.
Ich vermute/hoffe, daß das hier impliziert, daß in ein Wave-Format
gewandelt wurde:
A. Audio schrieb:> Dafür muss ich natürlich die Qualität der Datei extrem vermindern, meine> Schritte waren folgende:> mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen und als> headerless raw-file in unsigned 8-bit gespeichert.
>> mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen und als>> headerless raw-file in unsigned 8-bit gespeichert.
Das kann AVR nicht schaffen. Dafür zu schwache Leistung
Wenn Datei im voraus auf dem Computer so vorbereitet, dass AVR wirklich
nur WAV 8-bit bekommt - dann ist das möglich. Aber auch an Grenze.
Es gibt zwar eine Variante mit ATtiny85 oder 861A und PWM, aber die
haben PWM-Taktfrequenz bis 64 MHz! Das hat ATmega328P nicht.
Dazu noch: was soll bedeuten "auf 1000Hz heruntersamplen"? Theorie sagt,
dann ist Klang max. 500 Hz möglich. Praxis sagt aber, dass 500 Hz zu
viele Verzerrungen haben wird, praktisch gelingt es mehr oder weniger
sauber mit höchstens 200 Hz. Braucht jemand wirklich so einen Klang???
A. Audio schrieb:> Ich werde es mir einmal ansehen, danke für den Tipp.> Allerdings habe ich ja derzeit noch Probleme mit der Ausgabe.
Ich hab meinen Ansatz mal skiziert. Statt 7404 hab einen HC240 achtfach
Buffer genommen. Die Kondensatoren sind im Bereich 1µF, die Spulen hab
ich aus der Grabbelkiste. Ich bin nicht so der Filterexperte, ich hab
probiert statt zu rechnen. Das funktioniert natürlich mit jedem PWM
Signal, solange die Filterfrequenz und die PWM Frequenz passen.
MfG Klaus
Rufus Τ. F. schrieb:> A. Audio schrieb:>> Mein Problem ist aber, dass, wenn ich 0x80 (=128) länger ausgebe, einen>> konstanten Ton erhalte.>> Du hast nicht verstanden, wie die DAC-Nachbildung mit PWM funktioniert,> d.h. Du hast das zur Glättung nötige RC-Glied (Tiefpass) am Ausgang> weggelassen.>> Das, was Du als Wert der PWM übergibst, entspricht einem Spannungspegel> am Ausgang - 0 ist der geringste, 255 der größte und 128 der mittlere> Pegel.Maxim B. schrieb:>> Weiterhin verstehe ich irgendwie deine Rechnung nicht ganz.>> Weshalb *2^32?> Weil max. Zahl in unsigned long 2^32-1 ist.> Bei neueren Toolchains geht auch mit __uint24, für so eine Verwendung> ist Genauigkeit von 2^24 ausreichend.>>> Ich habe es bisher immer so gemacht:>> counter = INTERRUPTS_PER_S frequency 2;>> Dann in der ISR counter heruntergezählt und bei 0 den Pin getoggled.> Das ist kein DDS, das ist etwas anderes. Viel weniger genau, was> Frequenz betrifft. Z.B. 0,01 cent Genauigkeit kann man so nicht> erreichen - gut wenn es unterhalb 2-3 cent bleibt.>>>> warum verwende ich nur die obersten 8 bits?> Weil das reicht. Du kannst statt char auch int verwenden, nur mehr> Speicherplatz und etwas langsamer. Wenn mehr als 2 Töne gleichzeitig,> dann auch bei F_CPU = 20 MHz muß du Fd unter 32 kHz herabsetzen.Thomas E. schrieb:> A. Audio schrieb:>> Dabei ist audio_ das Array mit den Werten aus der mp3, die ich ausgeben>> will.>> Nur mal zur Klarstellung: Eine MP3-Datei kannst Du so nicht direkt> ausgeben! Die musst Du vorher schon dekodieren und die Samples als> Wellenform abspeichern.Rufus Τ. F. schrieb:> Ich vermute/hoffe, daß das hier impliziert, daß in ein Wave-Format> gewandelt wurde:>> A. Audio schrieb:>> Dafür muss ich natürlich die Qualität der Datei extrem vermindern, meine>> Schritte waren folgende:>> mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen und als>> headerless raw-file in unsigned 8-bit gespeichert.
Ja. Die Samples wurden raw ohne Header in unsigned 8-bit values
abgespeichert.
Maxim B. schrieb:>>> mp3-Datei auf mono umstellen, auf 1000Hz heruntersamplen und> als>>> headerless raw-file in unsigned 8-bit gespeichert.> Das kann AVR nicht schaffen. Dafür zu schwache Leistung> Wenn Datei im voraus auf dem Computer so vorbereitet, dass AVR wirklich> nur WAV 8-bit bekommt - dann ist das möglich. Aber auch an Grenze.>> Es gibt zwar eine Variante mit ATtiny85 oder 861A und PWM, aber die> haben PWM-Taktfrequenz bis 64 MHz! Das hat ATmega328P nicht.>> Dazu noch: was soll bedeuten "auf 1000Hz heruntersamplen"? Theorie sagt,> dann ist Klang max. 500 Hz möglich. Praxis sagt aber, dass 500 Hz zu> viele Verzerrungen haben wird, praktisch gelingt es mehr oder weniger> sauber mit höchstens 200 Hz. Braucht jemand wirklich so einen Klang???
Sampling Rate auf 1000Hz stellen.
Natürlich klingt es grottig.
Allerdings wollte ich zumindest die Software schon einmal fertigstellen,
während das SD Card module noch auf dem Weg zu mir ist.
Gibt da ja offensichtlich genug zu tun.
Klaus schrieb:> A. Audio schrieb:>> Ich werde es mir einmal ansehen, danke für den Tipp.>> Allerdings habe ich ja derzeit noch Probleme mit der Ausgabe.>> Ich hab meinen Ansatz mal skiziert. Statt 7404 hab einen HC240 achtfach> Buffer genommen. Die Kondensatoren sind im Bereich 1µF, die Spulen hab> ich aus der Grabbelkiste. Ich bin nicht so der Filterexperte, ich hab> probiert statt zu rechnen. Das funktioniert natürlich mit jedem PWM> Signal, solange die Filterfrequenz und die PWM Frequenz passen.>> MfG Klaus
Danke.
Allerdings habe ich gerade keinerlei freie Inverter da und diskret
nachbauen ist vermutlich bei 7 Invertern ein wenig zu aufwendig. Wofür
sind die denn eigentlich da in der Schaltung?
Allerdings habe ich jetzt auch einmal einen Tiefpass-Filter mit
einfachem RC-Glied eingebaut (den habe ich tatsächlich vergessen). Mit
Filter ist allerdings eigentlich einfach nur alles leiser. Egal ob
"nichts" (=0x80) oder anderes. Bei 0x80 kommt somit auch weiterhin ein
ziemlich hohes Piepen (wobei laut Berechnungen und auch Multimeter die
Frequenz bei 62kHz liegt und somit eigentlich unhörbar sein müsste) und
der Rest ist einfach nur unglaublich leise. Und ein Operationsverstärker
wird die 0.2-0.3A nicht überleben.
Ich habe Kondensatoren von 10nF bis 2.2mF probiert. Je größer, desto
leiser natürlich. Aber wahlweise man hört gar nichts mehr - weder von
der eigentlichen Ausgabe noch von dem "Nullpunkt" bei 0x80 - oder eben
immer dieses hohe Piepsen.
Gibt es irgendeine Möglichkeit, wie man nur das Piepsen (ca. 62.7kHz,
2.5V) herausfiltert?
Oder soll ich einfach, wenn ich gerade nichts ausgebe, die Spannung dann
einfach doch auf konstant 0V setzen?
Thomas E. schrieb:> Klaus schrieb:>> sollte die PWM>> bei einer Frequenz von 8 kHz eine Auflösung von 11-12 Bit haben,>> Wozu denn eine so hohe Auflösung? Bei 8kHz ist das Sampleraster schon> derart grob, daß einen da eine hohe Auflösung (> 60dB SNR) bei der> Qualität auch nicht mehr groß 'rausreisst. Ich würde da eher auf eine> höhere Abtastfrequenz gehen und die PWM-Frequenz möglichst erhöhen,> damit man keinen so steilflankigen Tiefpass nachschalten muss. Für> Telefonqualität reicht doch SNR = 48 dB (8 Bit Aufösung) locker. Evtl.> wäre es sogar in der Praxis besser, noch ein Bit zugunsten einer höheren> PWM-Frequenz zu opfern. Ein 7-Bit Timer mit 16 MHz gibt 125kHz, davon> bleibt selbst mit einem simplen, 1-stufigen RC-Filter nicht mehr viel> übrig.> Also, mein "Rezept" für brauchbare Qualität mit geringem Aufwand wäre:> 8-Bit samplen, aber dafür >= 16kHz Abtastrate (relativ weit weg vom> Nutzsignal) und noch höhere PWM Frequenz (sehr weit weg vom Nutzsignal).>> Beim Telefon wird wahrscheinlich mit einer höheren Auflösung gesampled,> um den Dynamikbereich zu erhöhen, d.h. es soll ja auch noch etwas zu> verstehen sein, wenn der Sprecher mal etwas leisere Töne anschlägt. Zur> Ausgabe eines Signaltons braucht es das aber nicht, da man den immer mit> optimaler (Voll-)Aussteuerung generieren kann.
Den Beitrag hier habe ich letztes Mal offensichtlich übersehen.
Das Problem ist, dass die Abtastrate eben genau so speicherraubend ist.
Aber ich versuche sonst einfach einmal, ein kürzeres Beispiel zu nehmen,
das ich aber einfach ganz oft wiederhole. Dann kann ich zumindest
schauen, ob die Tonhöhe getroffen wird.
Danke euch allen auch noch einmal für eure Geduld.
Thomas E. schrieb:> Klaus schrieb:>> sollte die PWM>> bei einer Frequenz von 8 kHz eine Auflösung von 11-12 Bit haben,>> Wozu denn eine so hohe Auflösung? Bei 8kHz ist das Sampleraster schon> derart grob, daß einen da eine hohe Auflösung (> 60dB SNR) bei der> Qualität auch nicht mehr groß 'rausreisst. Ich würde da eher auf eine> höhere Abtastfrequenz gehen und die PWM-Frequenz möglichst erhöhen,> damit man keinen so steilflankigen Tiefpass nachschalten muss.
Es geht nicht darum was du würdest, es geht danach was im weltweiten
Telefonnetz gemacht wird. Ich hab beschrieben, wie man leicht diese
Signale erzeugen (audacity) und ausgeben kann. Die Dynamik kannst du
auch gut brauchen, wenn du digital die Lautstärke ändern willst.
A. Audio schrieb:> Wofür> sind die denn eigentlich da in der Schaltung?
Die liefern den Strom für den Lautsprecher, ein Class-D Verstärker für
Arme, wie ich schrieb. Das für den Class-D nötige Filter ist auch
gleichzeitig das Filter für die PWM Frequenz.
MfG Klaus
Application Note AVR314 bei Microchip beschreibt die Ausgabe von DTMF
(Touch-) Tönen mit jedem beliebigen AVR. Das sind also immer 2 Töne. Das
ist sehr viel einfacher als die meisten Vorschläge, die bis jetzt
gemacht wurden.
Einfach mal anschauen.
Klaus:
>Die Kondensatoren sind im Bereich 1µF, die Spulen hab>ich aus der Grabbelkiste.
Hallo Klaus,
die genauen Werte für LC wären interessant. Könntest Du eine Aufnahme
mit-/ohne LC Filter machen? Mich würde interessieren, ob man den
Unterschied gut hört.
chris schrieb:> die genauen Werte für LC wären interessant. Könntest Du eine Aufnahme> mit-/ohne LC Filter machen? Mich würde interessieren, ob man den> Unterschied gut hört.
Ich hab den Aufbau nicht lauffähig. Aber ich kann dir sagen, ohne Filter
hälst die 8kHz nicht aus, mit einer Stufe stört es, bei zwei Stufen ist
es brauchbar. Die Lautstärke hat sich insgesamt kaum verändert.
Die Drosseln sind aus einem Projekt übrig geblieben und haben so 1 bis 2
mHµ. Wenn man es richtig macht, könnte man wohl auch statt der zwei
Drosseln pro Filterstufe eine Doppeldrossel nehmen. Ich bin nicht so der
Filterspezialist, aber ich weiß, daß bei passiven Filtern die
Ausgangsimpedanz des Treibers auf der einen und die Impedanz der Last,
des Lautsprechers auf der anderen Seite eine wichtige Rolle spielt.
MfG Klaus
Klaus schrieb:> Es geht nicht darum was du würdest, es geht danach was im weltweiten> Telefonnetz gemacht wird.
So? Und wer bestimmt das, wonach es geht? Ich kann mich nicht erinnern,
gelesen zu haben, daß der TO aus seinem AVR ein Telefon bauen will. Ob
das, was im weltweiten Telefonnetz gemacht wird, auch wirklich das Ideal
für seine Anwendung ist, kann man wohl kaum so einfach bestimmen, wie Du
es tust. Geht es ihm eher um Sprachverständlichkeit bei großem
Dynamikumfang oder um einen klirrarmen Sound eines akustischen Signals?
Mit bloß 15 diskreten Werten im Bereich über der halben Amplitude wird
jedenfalls ein Sinus z.B. schon ganz schön "verbogen", dh. es wird
effektiv systembedingt ein Störsignal von min. 1/32 der Amplitude
aufmoduliert. Und ist er gewillt, den Aufwand eines steilflankigen
Tiefpasses höherer Ordnung zu treiben?
Thomas E. schrieb:> So? Und wer bestimmt das, wonach es geht? Ich kann mich nicht erinnern,> gelesen zu haben, daß der TO aus seinem AVR ein Telefon bauen will
Er hat gefragt, wie man einfach audio mit seinem µC ausgeben kann. Und
ich hab gesagt, ich hab das mal so gemacht. Das ist alles. Er hat dann
noch Einzelheiten abgefragt. Das du alles besser kannst, ist klar.
Trotzdem habe ich das nicht berücksichtig, als ich das mal gemacht und
werde es auch nicht tun. Was der TO nun macht, ist sein Ding.
MfG Klaus
Klaus schrieb:> Und> ich hab gesagt, ich hab das mal so gemacht. Das ist alles.
Ja und? Habe ich irgendwo geschrieben, daß das falsch wäre?
Ich habe auch nur geschrieben, wie ich es machen würde, und zwar aus
diesem oder jenem Grund. Ich kann leider im Gegensatz zu Dir nicht
schreiben, daß ich das schon so gemacht habe, weil das gelogen wäre. Ich
habe aber nicht etwas in der Art geschrieben: "ist egal, was der Klaus
macht oder vorschlägt, das macht man anders!" Das wäre in meinen Augen
besserwisserisch.
So, und jetzt schreibst Du "Es geht nicht darum was du würdest, es geht
danach was im weltweiten Telefonnetz gemacht wird." und stellst mich als
Besserwisser dar?
Oder habe ich da vielleicht etwas falsch interpretiert?
Falk B. schrieb:> Beitrag "Re: Arduino Nano, SD Card, PCM"
Sehr, sehr interessant! Vielen Dank!
Ich experimentiere auch in so einer Richtung, wenn auch ein bißchen
anderes (ein Sampler. Ich brauche etwas für Beerdigungen, was bessere
Orgelklang liefert als ein Yamaha-Keyboard, aber von AA-Batterien auch
läuft). Aber hier sehe ich gute Material auch für mich.
Bernd K. schrieb:> Du könntest statt R2R auch versuchen einen Delta Sigma DAC zu bauen.
Aber nicht mit einem AVR und schon gar nicht in C. Für einigermaßen gute
Audioqualität habe ich 30 MHz bei einem cortex M4 in Assembler benötigt
und gut das doppelte in C.
A. Audio schrieb:> Bei 0x80 kommt somit auch weiterhin ein> ziemlich hohes Piepen (wobei laut Berechnungen und auch Multimeter die> Frequenz bei 62kHz liegt und somit eigentlich unhörbar sein müsste)
Da ist sicher etwas anderes faul! Wenn Du keine Fledermaus bist, kannst
Du 62 kHz nicht hören!
A. Audio schrieb:> und> der Rest ist einfach nur unglaublich leise. Und ein Operationsverstärker> wird die 0.2-0.3A nicht überleben.
Was denn für 0.2-0.3A? Woher kommen die und wie sieht Deine Schaltung
hinter dem 62kHz Rechtecksignal überhaupt aus?
Wie gesagt, egal, wie schlecht Dein Filter ist, von 62kHz dürfte vom
menschlichen Ohr nichts wahrgenommen werden - da muss ein anderer Fehler
vorliegen!
Läuft Dein Programm vielleicht in einer Schleife und initialisiert die
PWM ständig neu? Möglicherweise mit einer Rate, die im
Tonfrequenzbereich liegt?
A. Audio schrieb:> Das Problem ist, dass die Abtastrate eben genau so speicherraubend ist.
Du kannst auch mit nur 8kHz samplen - meine 16kHz waren ja nur der
Vorschlag, um weiter von der Nutzfrequenz wegzukommen, damit der
Tiefpass einfacher wird. Wenn ich's richtig verstanden habe, sollen die
Daten später sowieso von einer SD-Karte kommen, da ist der
Speicherverbrauch dann ja auch nicht mehr so kritisch. Wichtiger ist
wohl, bei der PWM-Frequenz im unhörbaren Bereich zu bleiben.
Thomas E. schrieb:> A. Audio schrieb:>> Bei 0x80 kommt somit auch weiterhin ein>> ziemlich hohes Piepen (wobei laut Berechnungen und auch Multimeter die>> Frequenz bei 62kHz liegt und somit eigentlich unhörbar sein müsste)>> Da ist sicher etwas anderes faul! Wenn Du keine Fledermaus bist, kannst> Du 62 kHz nicht hören!
Ein Rechteck ist aber kein reiner Sinus. Zwischen allen mitschwingenden
Harmonischen ist bestimmt was hörbares dabei.
Eric B. schrieb:> Ein Rechteck ist aber kein reiner Sinus. Zwischen allen mitschwingenden> Harmonischen ist bestimmt was hörbares dabei.
Nein, da gibt es nichts unterhalb der Grundfrequenz, d.h. hier also
nichts unter 62 kHz.
Hallo,
Es gab hier mal das Projekt von Ulrich Radig
(Beitrag "MegaLOL").
Wenn mich nicht alles täuscht wurde damit genau das vom TO gewünschte
bereits gemacht.
BG, Tom